This article is part of the series on the rust-http redesign, Teepee.
Of the first article, most details are superseded here; the most important part that is still definitely in place is the status code class part.
The criticism and responses to it
The main point of criticism levelled at the designs I posted is that it was still treating the Reason-Phrase
too importantly.
Some argue in favour of dropping the reason phrase altogether. That I am not willing to do, citing the 451 example for justification. No, the reason phrase must remain around, somewhere.
A common suggestion is splitting the status code and reason phrase apart. This is looking like a healthy option. It is one that had not occurred to me; I had become too tied up in their correlation, that being what I had been working with in the past in rust-http.
Library designers, bewareââyour own perspective will become warped over time so that you often see only slight variations from what you are doing. Getting fresh eyes on a solution is marvellous; I am very glad that I wrote about this matter. Thank you, everyone, for the feedback: Teepee will be the stronger for it.
The new design
I now present a new design, influenced strongly by the feedback received.
At the lowest level, rather than giving a single Status
object, the code will work with the pair (StatusCode, ReasonPhrase)
.
Responses received by the client will have both of these:
Responses a server is writing will have both fields, but with the reason phrase optional:
Normally people will just set the status code. If the reason phrase is None
, the appropriate value will be inferred, or for unknown statuses, something like â<no reason phrase given>â.
I am satisfied with this design. Now the only question remaining is how StatusCode
itself is represented.
The StatusCode
part: a few designs
There are a few possibilities for the Status-Code part; I present here a few, each with its benefits and drawbacks. Their ordering is not significant.
#1: an enum with an extension code variant
This is similar to what is done in rust-http. It takes four bytes, while the others take two bytes.
This maps extremely well onto the RFC 2616 definition of Status-Code
:
However, this has the backwardsâcompatibility problem (one I identified earlier but forgot to write down in my previous article) that when a new status 103 Newly Registered Value
is registered, things will change from using ExtensionCode(103)
to using NewlyRegisteredValue
. Itâs a very rare case, but very significant.
#2: a 500âvariant Câstyle enum
This scheme has the slight weakness that when a status becomes registered, its variant will change; this is not, however, a severe backwardsâcompatibility problem, for we would leave static aliases behind (e.g. pub static Code103: StatusCode = NewlyRegisteredValue
). That could also be used to take care of cases like 451.
#3: a simple wrapping struct with associated statics
I handle this as a separate struct rather than just as u16
, because there are only 500 valid values (100â599). Just as ~str
applies checks to maintain the invariant that it is valid UTF-8, I will ensure that an illegal StatusCode
can never exist. (That applies to the ExtensionCode
variant of the enum solution too, by the way.)
The biggest thing this has going against it is that pattern matching wonât work.
#4: just a number
A variant of #3, one can cause pattern matching to work by using a number type directly:
I am not in favour of this solution because of semantic mismatch. A status is not just a numberââit has 500 valid values, as mentioned above, and I wish to maintain the invariant. Also things like +
simply donât make sense for a status. Sure, itâs shown as a number, but it is opaque data.
Conclusion
I am now satisfied with the overall design of the Status-Line
handling. As to the representation of StatusCode
, my current order of preferences, from favourite to least favourite, is #2, #3, #1, #4.
I now invite you to join in the discussion at /r/rust.
Update: the HTTP/2.0 situation
Something I neglected to do all along was refer to the HTTP/2.0 specification. (I looked at that part a few months ago, but had forgotten about it. Iâve been focusing more on the multiplexing aspects of HTTP/2.0, as thatâs the main change and the main area of implementation difficulty for Teepee.) It has a couple of notable changes:
The reason phrase is gone altogether (Section 8.1.3.2, Response Header Fields). This confirms that separating the code and the reason is the correct thing to do.
1xx Informational class statuses are removed (Section 8.1.1, Informational Responses). This suggests that restricting the values structurally in the type system might not be quite so valuable, as only a subset of those values are actually valid in certain situations.