
Announcing the `http` crate - JoshTriplett
https://users.rust-lang.org/t/announcing-the-http-crate/12123
======
int_19h
It's great to see this approach to core API design, and I wish other platforms
adopted it. There are many advantages to having a rich ecosystem of third-
party libraries, but composability becomes a problem when they define
different types for the same concepts. This is the best of both worlds - you
get multiple competing implementations of the interesting bits, but everything
"just works" with any of them.

~~~
nly
I couldn't agree more. Although, as someone mostly in to C++, I think data
types like this should be standardised as concepts rather than added as
concrete types. The HeaderMap described in this crate sounds like it is quite
complex. I'd rather have a concept with some kind of trait mechanism for
determining if e.g. the type preserved insertion order (which defaulted to
false)

The Beast HTTP library that just got accepted in to Boost follows this
approach. E.g. the following Fields concept specifies the requirements the
library has on its any HeaderMap-like type you feed it. Writing an adapter for
your own types then becomes straightforward

[http://vinniefalco.github.io/beast/beast/concepts/Fields.htm...](http://vinniefalco.github.io/beast/beast/concepts/Fields.html)

~~~
derefr
Defining the type as a trait would prevent link-time optimization of library-
consumer-side manipulations of data of that type, no?

Really, you want a concept that's like a trait, but is explicit about the fact
that there's exactly one implementation of the trait, and that that
implementation is discoverable at compile time. Less like an interface, more
like a C typedef in a third-party-library header file—just without the "header
file" part.

~~~
mtanski
Most Rust compilation is non-incremental but rather one shot with all type
information available. Thus, because of LTO optimization either in Rust or
LLVM the compiler should discover what the concrete type of the trait is and
be able to optimize / inline accordingly.

------
tyingq
One watch out here is patterns that encourage developers to do the wrong
thing.

With golang, for example, it's common to see applications that don't set
reasonable cache control headers, content type and length headers, handle head
requests properly, compression, and so on.

It's not that golang can't do those things, but the libraries, documentation,
and examples don't encourage it. So you see a lot of minimal http
implementations that "work", but not well. It's like every (less experienced)
end user of the library has to learn all the basics by trial, error, bug
reports, etc.

~~~
tadfisher
I'd argue that all but the most extremely basic of HTTP options are far from
universal, and defining sane defaults is the responsibility of frameworks and
not a core library.

~~~
JoshTriplett
Agreed. And in particular, these kinds of types would make it much easier to
write a framework-agnostic library that helps you handle caching correctly,
built on top of these types, like Request and Response.

~~~
taeric
I'd argue that at the API level, these things should be required to think
about. Any level of "help" so that I don't have to worry about cache headers
should be from a framework that tells me what they think about them.

~~~
JoshTriplett
> I'd argue that at the API level, these things should be required to think
> about. Any level of "help" so that I don't have to worry about cache headers
> should be from a framework that tells me what they think about them.

Agreed completely. The lowest-level API should expose them and every other bit
of the standard, and higher-level APIs should handle them automatically in
sensible ways.

------
the_common_man
Would it not be better to call it http-types/http-base/http-common as this
just provides common types and not the transport or security? Thanks and keep
up the awesome work.

~~~
JoshTriplett
I think "http" actually makes sense here, for two reasons.

First, this crate provides a common layer for the HTTP protocol; if you're
interacting with HTTP, you'd use this crate and its types, often directly.
Note, in particular, that this crate provides builders to construct HTTP
requests and responses, which is often a large part of client and server
libraries, respectively.

And second, I don't think any _specific_ HTTP client or server software should
claim the crate name "http". A common layer like this, built around the
protocol itself, seems to have a much more reasonable claim to it.

~~~
tadfisher
In addition, the "transport" and "security" portions are the least-HTTP-
related parts of an HTTP stack. Far more than HTTP runs on TCP and TLS.

------
arianvanp
Seems like they took the hint from haskell :) good job. We have WAI
([https://www.stackage.org/lts-9.0/package/wai-3.2.1.1](https://www.stackage.org/lts-9.0/package/wai-3.2.1.1))
a common interface for multiple HTTP Web Servers. It's very useful, and a rich
ecosystem of middleware has flourished.

------
deathanatos
I really wish I could start a rebellious movement in HTTP libraries to call
the constant UNAUTHENTICATED and for it to return

    
    
        401 Unauthenticated
    

…and then once rough consensus switches, get an update in the RFC.

(I'd likely be horrified to learn that something out there critically depends
on the Reason Phrase…)

~~~
JoshTriplett
You're not _supposed_ to depend on the specific reason phrase given with the
code, but I wouldn't find it surprising if something does.

See [https://hackernoon.com/three-bytes-and-a-
space-8f9fbd1c669b](https://hackernoon.com/three-bytes-and-a-
space-8f9fbd1c669b) for a related debugging adventure.

Also, technically, you can return 401 for either "unauthenticated" (you need
to pass authentication information) or "unauthorized" (you passed
authentication information but it wasn't acceptable), depending on the nature
of what you need.

~~~
BillinghamJ
401 Unauthorized means you aren’t authenticated, or your authentication is
broken/expired/invalid.

403 Forbidden means that your authentication is valid, but that you don’t have
access to the resource.

401 should not be used to indicate the latter.

~~~
throwaway91111
Why not? 401 seems like a fine fit if your client doesn't need to
differentiate between authentication and authorization; most don't need to at
all.

Also, you can fail authorization without passing authentication. For instance,
you could be authorized by ip range or something unrelated to any of the data
in the http request.

~~~
erikpukinskis
Wut. Most clients don't need to differentiate between "you're not allowed to
do that" and "you're not logged in"? Those things require totally different
reactions, no?

------
mixedCase
I can't seem to find a parser for HTTP requests in the repo. I assume this is
out of scope for the crate?

~~~
ivanbakel
To quote the announcement:

>It does not cover transport, but is rather intended for use in libraries like
Hyper, and to support an ecosystem of crates that can share HTTP-related
types.

So I don't think they added any implementation details to the crate itself, to
avoid people taking issue with something being too bloat-ey or not to their
need, and rejecting the common types, which seem to be the real goal. It does
seem like something you'd always need, though - I can only imagine that a
proper parser would be pretty large, and they didn't want people to complain
about it.

~~~
JoshTriplett
I wouldn't be surprised if an "http-parser" crate pops up on top of this. But
unlike the http crate, an http-parser crate would have to make at least one
potentially controversial choice, namely "which parsing library".

~~~
steveklabnik
I've been working with this crate for a while, and use
[https://crates.io/crates/httparse](https://crates.io/crates/httparse) with
it, it works pretty well.

------
gPH45
Interesting micro-optimizations... For example the use of lookup tables and
nested switches in uri.rs and method.rs.

Is this common practice in Rust? Shouldn't the compiler be smart enough to do
that for you? Such code seems quite sensitive to typos.

~~~
DiThi
I don't think the lookup tables is a micro-optimization. They're both clear
and fast in this case (I can't think of a more clear alternative, just of a
less verbose one). The "switches" are actually pattern matching, a very
powerful feature of Rust. I'm not sure about nesting them being a micro-
optimization either. I think it's also a choice that is both readable and
fast. Can a more experienced Rust code shed light?

------
pimeys
This is good news. Waiting it to be merged with hyper including the http2
support. With both of them it will make Rust the perfect choice for all my
current use-cases.

