When I was experimenting with Orbited early on, before it was an Open Source project, I became very, very annoyed by browser security. Specifically, for some god-forsaken reason it’s just this side of impossible to do cross domain scripting even when you are running both servers, and on the same parent domain. Sure, at this point it seems straightforward to me, but that’s only because I spent a year tackling the problem.
If you are interested in cross-domain scripting, read what some of the experts have done. Such as Abe Fettig. For the other 99.995% of you who don’t give a rat’s ass, I included a proxy in Orbited.
The proxy, as you may well already know, overcomes the problem of cross-domain scripting by putting Orbited in front of your web application such that the browser thinks orbited is the Comet server and the web app.
The proxy is a testing and development tool though. In a production environment it is a pretty bad idea to use the proxy. Not only will it make it much harder for you to scale your application and achieve true redundancy at all tiers, it will use at least twice the cpu as you should be using.
Even so, it turns out that 90% of developers only want to use the proxy. From what I’ve gleaned, most people want to create prototypes or in-house apps. I think that the idea that anyone could use Comet is so new an idea that developers of large web applications are staying away. It’s going to take a new startup (maybe meebo) getting huge before all the other sites out there start integrating Comet.
In the mean time, as the prototypes roll, I’m left holding the bag. I had absolutely no idea what I was getting into when I included the proxy.
Proxy v1
When I first started, I was using CherryPy as a backend for all of my test and demo apps. I shut off CherryPy’s multi-threading because I wasn’t interested in generating all sorts of thread synchronization bugs. As a result, I had to also disable keepalive. With a single thread and keepalive, one user would tie up the server.
Given that keepalive was off, it was very clear how to proxy incoming requests. Examine the url. If it looks like an Orbited url, then hold on to the connection. Otherwise, check the proxy rules and send it on its way. After I designated a connection as proxy, I never looked at it again.
Proxy v2
I wrote an app that used more than one thread, and I enabled keepalive. Whoops. Suddenly my orbited requests were sometimes going straight through to the webapp. Whats going on? Well, my proxy would look at the first request coming down the pipe and then never look again. So the second request, which was for Orbited, got proxied as well.
Some long hours later, and I had a new proxy. It would look at all the data as it flowed from the client to the server. At the end of each request, it turned the connection back over to Orbited. When the next request came down the pipe, Orbited ran its usual check to see if it was for Orbited or for the proxy.
Proxy v3
So along comes a django developer. He writes a simple version of the cherrychat app in django, sets up the proxy, and nothing happens. No requests ever make it back from django to the proxy. And get this — the error reported is: “<type ‘exceptions.TypeError’&rt;: exceptions must be classes, instances, or strings (deprecated), not type” with no useful line number.
Turns out pyevent 0.3 and python 2.5 on ubuntu 7.04 causes exceptions generated by Orbited to be reported incorrectly. So I patched pyevent 0.3 and tried again. After much grief, the problem became clear. Django uses a rarely seen feature of HTTP/1.1 known as Transfer-Encoding: chunked;. It allows Django (or any other web framework) to render templates incrementally and send the results as they are available. The reason this wouldn’t be possible without chunked transfer is that in HTTP/1.1 you need to specify the Content-Length header before any content. But Django can’t know how long the content will be until it’s rendered.
So I rewrote the proxy yet again, because the previous code base wasn’t very conducive to this sort of interaction. This time though, the rewrite took about two hours because I had the old version to reference. After I finished, my Django tester disappeared never to return, apparently discouraged by the previous lack of Django support. I tried to do my own Django thing but I got lost. And I couldn’t make it use HTTP/1.1, much less chunked transfer encoding. So someone please test this when you get a chance.
Proxy v3.1
After coming all this way, I stopped supporting a subset of HTTP/1.0. That is, If not Content-Length header is specified, the connection just ends when it ends. But I was assuming, as per HTTP/1.1 that it meant the length was 0. This wasn’t a very involved fix, but I’d like to thank Matthew (desmaj) for finding this bug.
So the whole Ordeal was definitely worth it — I know all about HTTP Protocol and how it effects comet, proxies, and comet proxies. The proxy is more stable, which is great. I think that it will continue to be the main method of deploying Orbited applications because it’s just so much easier. It makes the difference between a 10 minute tutorial and a 30 minute tutorial. Just because of the proxy which isn’t a viable real world tool, we probably have a 1000% higher retention rate of prospective Orbited users. It just goes to show you that ease of use is what makes something popular. No one cares about scalability until after they’ve chosen a framework.