Chris Morgan › Blog Introducing Teepee: the next step for rust-http rust-http was but an experiment, an essay in the craft. Here, at last, is the real thing: the Teepee project, a properly engineered HTTP toolkit. Tagged: Web, Rust, Teepee

Published: April 23, 2014

Last updated: January 1, 2017

This post has been sitting 90% complete for two months, and I’ve been promisng Teepee for around three months; I apologise to all those whose hopes and plans I have been delaying. Well, at least it’s here now, and it’ll be progressing faster again now. This is an ongoing series on the design of Teepee. Here are the articles on the topic in order: Introducing Teepee: the next step for rust-http ( April 23 ; this article) A careful look at the HTTP/1.1 Status-Line ( April 25 ) Status-Line , take two ( April 25 ) Header representation ( May 10 ; this one took quite some nutting out before I finally had something that satisfied me) the HTTP method ( July 8 ) More articles are coming. [2017-01-01: Teepee stalled for various technical and social reasons, mostly to do with decision paralysis; this work was subsequently taken up in the Hyper project, which has gone on to prosper. These articles are therefore useful only as a historical record.]

Background

What is currently rust-http was from the beginning an experimental project. I wrote it for a combination of reasons:

I wanted to use an HTTP library with a strong typing discipline, where things like status codes would actually be status codes, not merely numbers and/or strings.

Having primarily used Django in the past, I had formed a vision of the web framework that I wanted. Shortly after writing down a first draft of that vision, I came across Rust again and assessed it more closely; I quickly decided that it was the first really suitable language for my vision.

… but Rust had no proper HTTP library—​only a couple of toy libraries already just about to become obsolete, for these were the days when the new runtime was being finished up and the old runtime was still the default.

As a proof of concept (especially in the extensive usage of Rust’s type system), rust-http has been successful. It’s even—​despite its limitations—​a useful library, as is evidenced by (a) people using it, and (b) no one writing any direct competitor since.

Various things have changed since the initial experimentation. Most notably:

I understand the requirements for high-performance HTTP/1.1 and HTTP/2.0 better (I only understood HTTP/1.1 well before, and I only had general notions of what the significant differences were in HTTP/2.0).

I actually know Rust well now (rust-http was the first non-trivial Rust code I wrote—​it shows).

The old runtime is now completely supplanted by the new runtime. (This happened some time ago and is, truth to tell, scarcely of note as concerns rust-http.)

I/O errors are now explicitly handled with things returning IoResult .

A TcpStream can now be cloned, allowing for storing the TcpStream in both the request and the response for a server (important for squeezing optimal performance out of an HTTP/1.1 server) and also the ability to work with the same stream across multiple tasks (which is crucial for HTTP/2.0).

What comes next for rust-http?

Having assessed the situation and the code extant at length, I have come to the following conclusion: rust-http must be completely rewritten.

It is expedient for this to happen immediately rather than later, to minimise technical debt.

The alternative was to keep a fair amount of the code base intact and alter it gradually into the new, deliberately designed form. This was my preferred approach until recently when I took a more careful look at how the existing structures would map onto what I was designing. When I did that I decided that at the very least the transfer model—​currently one layer due to what TcpStream used to be and because I was at the time writing the buffered stream support myself and made the (quite natural) error of putting too much HTTP logic into it—​this transfer model needs to be two distinct layers (the stream buffer, applicable to the entire connection, and the transfer encoding, applicable to only one request) to ensure it is maintainable, plus a third for the data structures (again, that is presently more or less blended in with the rest). I am convinced that replacing this part at least wholesale is the only sensible plan.

Beyond that, there are various other things which I would like to take this opportunity to redesign properly, such as the headers system. In the end, there is very little that I don’t want to do at least something to. (I believe I’m content with the Status struct, but even it will be redone with a macro rather than source code generation, for added coolness.)

So, then, I believe a complete rewrite is in order. Parts will be used as reference material, but no code will simply be copied over. It is safer thus. I will also be imposing the rule that all code that is written must include meaningful doc comments and must be tested. (Some of the key parts of rust-http are not tested; and bugs in an HTTP implementation can be a nightmare to pinpoint and fix.)

I recognise that in this I am vulnerable to second system syndrome. This is part of the reason why I want my plans reviewed by others before building it all.

It’s becoming a broader project

Now that I’ve become thoroughly acquainted with Rust, I’m more sure of my footing: I want to work more with Rust in the future and I believe it will make a very good platform for web-related work; and, what’s more, I intend to be in the forefront of this brave new world where writing fast, safe and correct websites is actually popular.

I have been mulling over what to do with rust-http. It’s got to the stage where I think separating the client and server into separate crates will be a good plan—​they have some shared things (certain traits and utility methods and all the header types), but beyond that they are largely different. I think that splitting it into httpc (client) and httpd (server) crates, with a common crate containing their shared dependencies and data types (perhaps httpcommon ), is probably the way forward (this is one of the points I’m least confident about).

In the end, this project will end up quite a bit like Spray is for Scala, and I think that having an overarching project which manages it all is probably a good idea.

My first desire was http.rs with its eponymous domain name, but alas! RNIDS (the operator of the .rs registry) has reserved http.rs, presumably to avoid any form of confusion.

The name I ended up settling upon was the only one which I came up with that I really liked: Teepee. Teepees are those American Indian tent thingies (also spelled tipi or tepee) but is absolutely nothing to do with Apache HTTP server (that connection was suggested by a couple of people independently afterwards—​it was not my intent in any way). The real derivation of the name was the latter two letters of HTTP. The project will be based at teepee.rs. Aside: registering .rs domains A .rs domain is a nice-looking thing for a Rust project, but it’s not without its caveats. I went for the cheapest registrar I could find. Here are some of the problems I found: Although registration is not limited to citizens of the Republic of Serbia ( RNIDS General T&C, article 3, clause 2: “registrant can be domestic or foreign, a physical person or a legal entity” [2017-01-01: link broken; the latest version doesn’t seem to make it as clear, at the very least]), in practice a national personal identification number is required of the registrant ( RNIDS General T&C, article 8, clause 2 ) and for this registrar at least their form required such a thing. 0000000 satisfied it and citing article 3 I’m confident that I am in fact permitted to register a .rs domain myself.

Back to this particular registrar: their registration process did not use HTTPS. (Sure, the payment part did as they outsource that to 2checkout, but the part on their site did not.)

And then they emailed me my password (one hundred random characters, as is my practise) in plain text. I’m not sure that I trust them much.

What are the important new features?

Proper multiple HTTP version support. The library will have good support for all HTTP versions: 0.9 (yes! really! ), 1.0, 1.1 and 2.0.

Various “bad things” will be able to be dealt with, rather than being dropped or otherwise inaccessible—​e.g. bad headers,

System boundaries will be more accurately segregated, abstracting away HTTP’s transfer details more completely than it is presently done and leaving a more sound API.

The tools for working with HTTP at a lower level will be more solid, and the higher level interface will sit cleanly on top of that lower level interface.

In consequence, extending it will be easier; WebSocket, for example, with its CONNECT upgrading, could only be implemented as a kludge in rust-http; such things will have proper support under Teepee.

Unified, pure‐Rust compilation model (using custom syntax extensions in place of source code generation).

Partially in consequence of all these things, Teepee’s HTTP libraries will be much easier to maintain. (I have decreed it so, and so it shall be!)

Under the umbrella of the Teepee project will also exist implementations of other related specifications like WebSocket and Server-Sent Events.

The new designs

I am still making some of the designs for Teepee. I will post them here as I complete them (or a little staggered); I will also be posting discussions of some of the matters that I think could do with particular discussion.

At this point, everything can be questioned and is subject to change. Comments and criticisms are welcome as I publish the designs.

If you wish to discuss the design, please join #teepee on irc.mozilla.org.

Are you interested?

In order to succeed, Teepee is going to need collaboration. There are a few classes of people that will be particularly valuable at this stage:

Servo developers: Teepee’s HTTP client needs to meet Servo’s requirements.

HTTP implementers: for both the client and the server, to ensure everything (client and server) is implemented in a reasonable manner.

Web app developers: HTTP server design—​is it appropriate for the forms of servers that you want to write? (I’ve also got to be careful about the web framework story, that things are built in a way that doesn’t end up with frameworks reimplementing most things too much, or that it forces too much on you. That’s part of the reason for having a more layered approach this time round.)

If you have any feedback on rust-http as it is at present and things you like about it, don’t like about it, can’t stand about it, couldn’t bear to see changed about it—​please speak up.

If you’re interested in getting involved with Teepee or have opinions to express, please join #teepee on irc.mozilla.org or drop me a line.

A little bit of personal plugging

In the long term, I hope the Teepee project as a whole to be both directly and indirectly a source of income for me and others in many and various ways (e.g. consulting, support, sponsorship of features). Whether or not this will pan out remains to be seen. At present I’m operating as a freelancer, spending most of my time working with a certain web agency (working mostly with Django), but I would love to spend more time working in/on Rust, rust-http and Teepee. If you should happen to want any development done in Rust or with rust-http, or should out of some extraordinary and inexplicable generosity desire to sponsor work on Teepee, I’m ready!

Actively soliciting donations in this way is not something that I have observed in the Rust community yet, so I’ll make myself a test case of what the response is and whether anything happens. (Even if it’s not quite a representative case, for by my observations good HTTP support is the biggest thing people want in Rust, beyond the language itself.)

If you want to hire or contract me for anything, please email me@chrismorgan.info.

If you want to donate to me directly to work on these things: