2011-03-04
Why I call FastCGI complex and SCGI much simpler
In a comment on this entry, Daniel Martin took issue with with my description of SCGI as much simpler than FastCGI. As it happens, I have a straightforward reason for describing FastCGI this way: it's a protocol that uses encoded binary structures.
Any protocol that uses encoded binary structures requires you to write decoders and encoders, or at least a protocol description for your encoder/decoder generator. This is annoying even with simple fixed-format binary structures; it is an outright pain in the rear if the protocol has multiple structures, structures with variable fields, or complex switching logic (where you don't always have a common prefix that you can do simple switch dispatching on). FastCGI has multiple levels of decoding (where you have structures inside structures) and at least one case of an excessively clever structure encoding.
(The excessively clever structure encoding is worth special note, because in the name of saving six bytes FastCGI has four variations on the same basic structure that are differentiated not by an explicit type field, but by which of the first two bytes have their high bits set. In the process, it re-orders structure fields. I could go on about this particular encoding mistake, but this is not the entry for it.)
Regardless of the inherent simplicity or complexity of the protocol in an abstract sense (ie in terms of what the flow of messages is), using encoded binary structures makes you (much) more complicated than an equivalent protocol that uses a simpler, easier to parse and generate encoding. Since FastCGI uses encoded binary structures and SCGI doesn't, I say that SCGI is much simpler than FastCGI.
(FastCGI is also a more involved protocol than SCGI. I could easily call it over-engineered, in part because it reimplements OS-level concepts on its own and generally does this worse than the OS does.)
Sidebar: one OS-level concept that FastCGI reimplements
FastCGI needs to pass multiple communication channels between the web server and the FastCGI server process. As it happens, Unix OSes have a simple and well supported way of doing this; you open up multiple file descriptors between you and the other end and use each file descriptor for a separate channel. FastCGI would still need to do a little bit of multiplexing to handle standard output and standard error over the same channel, but that is much easier than the multiplexing job that it has taken on for itself.
(Doing this does not require multiple processes; you can perfectly well
handle all connections with select()
et al in one process. It does
give you an easy way of using multiple processes, which can be handy.)