231 lines
9.5 KiB
Markdown
231 lines
9.5 KiB
Markdown
# hyper Vision
|
|
|
|
## Purpose
|
|
|
|
This is an overview of what the shape of hyper looks like, but also somewhat
|
|
zoomed out, so that the _vision_ can survive while the exact minute details
|
|
might shift and change over time.
|
|
|
|
### Charter
|
|
|
|
> hyper is a protective and efficient HTTP library for all.
|
|
|
|
### Tenets
|
|
|
|
Tenets are guiding principles. They guide how decisions are made for the whole
|
|
project. Ideally, we do all of them all the time. In some cases, though, we may
|
|
be forced to decide between slightly penalizing one goal or another. In that
|
|
case, we tend to support those goals that come earlier in the list over those
|
|
that come later (but every case is different).
|
|
|
|
0. Open
|
|
1. Correct
|
|
2. Fast
|
|
3. HTTP/\*
|
|
4. Flexible
|
|
5. Understandable
|
|
|
|
There's a lot more detail about each in [TENETS](./TENETS.md).
|
|
|
|
## Use Cases
|
|
|
|
Who are the *users* of hyper? How would they use hyper?
|
|
|
|
### Low-Level Client Library (curl, reqwest, aws-sdk)
|
|
|
|
These client libraries care that hyper is **Flexible**, since they are
|
|
expressing their own opinion on how a more-featured HTTP client should act.
|
|
This includes opinions on connection establishment, management, pooling, HTTP
|
|
version options, and even runtimes.
|
|
|
|
curl's main reason for using hyper is that it is **Safe**.
|
|
|
|
### Web Server Frameworks (deno, axum)
|
|
|
|
These are using hyper's server feature to expose a different, higher-level API
|
|
to users. Besides the obvious requirements, these require that hyper is
|
|
**Fast**. Servers are costly, handling more requests faster is important to
|
|
them.
|
|
|
|
That hyper is **Flexible** is also important, in that it needs to be flexible
|
|
enough for them to build a server framework, and allow them to express their
|
|
own opinions about API to their users.
|
|
|
|
### Services and Proxies (linkerd, cloudflare, fastly)
|
|
|
|
These are using hyper directly, likely both the client and server, in order to
|
|
build efficient and powerful services, applications, and tools for their end
|
|
users. They care greatly that hyper is **Correct**, since web traffic can
|
|
stretch the limits of what is valid HTTP, and exercise less-common parts of the
|
|
specifications.
|
|
|
|
They also require hyper to be **Fast**, for similar reasons that the web server
|
|
frameworks do.
|
|
|
|
### New Rust Web Developers
|
|
|
|
These are developers who are either new to Rust, or new to web servers, and
|
|
have reached for hyper to start with.
|
|
|
|
It's likely that these users don't have strong opinions about how an HTTP
|
|
server or client should work, just that it _should_ handle all the things they
|
|
normally assume it would. For these users, it would be best to quickly help
|
|
them compare their own expectations with hyper's capabilities, and may
|
|
suggest reaching for higher-level, _easier_ libraries instead.
|
|
|
|
Those that stick around after that recommendation are users that wish both to
|
|
learn at a lower level, and to pick and choose what batteries they plug in to
|
|
hyper as they move along. While they do care about the other tenets, that hyper
|
|
is **Understandable** is of extra importance to them.
|
|
|
|
## The Library
|
|
|
|
So with all that context in mind, what does hyper, the library, actually look
|
|
like? This doesn't highlight what _is_ and _isn't_ present. What currently
|
|
needs to change to reach this vision is left to individual version roadmaps.
|
|
|
|
### Layers
|
|
|
|
In all cases, a user brings their own runtime and IO to work with hyper. The IO
|
|
is provided to hyper, and hyper acts on top of it. hyper returns `Future`s that
|
|
the user then decides how to poll, likely involving their runtime options.
|
|
|
|

|
|
|
|
|
|
#### Protocol Codecs
|
|
|
|
hyper has dedicated codecs for the major HTTP versions. Each is internally
|
|
designed to be **Correct** and **Fast** when it comes to encoding and decoding.
|
|
|
|
The individual codecs may be implemented as sub-crates, with a less-stable
|
|
promise, to support the **Flexible** needs of some users who wish to build
|
|
their own connection management, or customize encoding and decoding beyond what
|
|
is officially supported.
|
|
|
|
#### Connection State Management
|
|
|
|
A **Correct** implementation includes more than just enforcing certain
|
|
characters when encoding and decoding. Order of frames, and flags in certain
|
|
frames can affect the state of the connection. Some examples of things enforced
|
|
at this layer:
|
|
|
|
- If a message has a `content-length`, enforce only that many bytes are read or
|
|
written.
|
|
- Reading a `Response` before a `Request` is even written implies a mismatched
|
|
reply that should be interpreted as an error.
|
|
- The presence of some headers, such as `Connection: close`, or the absence of
|
|
others, such as `content-length` and `transfer-encoding`, can mean that the
|
|
connection should terminate after the current message.
|
|
- HTTP/2 and HTTP/3 may send connection-level frames that don't pertain to any
|
|
specific transaction, and must be read and handled regardless of if a user is
|
|
currently checking for a message.
|
|
|
|
#### HTTP Role and Version Abstraction
|
|
|
|
This is the public API layer. Methods exposed are around sending and receiving
|
|
`http::Request`s and `http::Response`s, not around framing specifics of the
|
|
different versions. These are built around a client or server `Connection`
|
|
interface.
|
|
|
|
By exposing this layer publicly, we take care of the **Correct** tenet, by not
|
|
forcing the user to send the specific frames themselves. The API should be
|
|
designed in a way that a user cannot easily (if at all) create an _incorrect_
|
|
HTTP connection.
|
|
|
|
Motivated by the **Flexible** tenet, there _are_ version-specific options that
|
|
can be configured at this level, and version-specific functionality can usually
|
|
be handled via `http::Extensions`.
|
|
|
|
### Not quite stable, but utile (useful)
|
|
|
|
Beyond what is directly in the hyper crate, there are useful (utile) parts that
|
|
may not meet hyper's stability promise. Developing, experimenting, and exposing
|
|
those parts is the purpose of the `hyper-util` crate. That crate does not have
|
|
the same stability level as hyper. However, the goal is that things that other
|
|
libraries might want to expose as a public dependency do not live in
|
|
`hyper-util` forever, but rather stabilize and get promoted into `hyper`.
|
|
|
|
Exactly what gets put into `hyper-util` presently is kept in the roadmap
|
|
documents.
|
|
|
|
### Stability Promise
|
|
|
|
What even is hyper's stability promise? Does it mean we are "done"? No. Will we
|
|
ever make breaking changes again? Probably. We'll still follow the [semantic
|
|
versioning](https://semver.org).
|
|
|
|
Prior to 1.0, hyper has already only done breaking changes once a year. So 1
|
|
year isn't much of a promise. We'll have significant more use and understanding
|
|
after a few years, and that could prompt some redesign.
|
|
|
|
As of this writing, we'll promise that _major_ versions of hyper are stable for
|
|
3 years. New features will come out in _minor_ versions frequently. If it is
|
|
determined necessary to make breaking changes to the API, we'll save them for
|
|
after the 3 years.
|
|
|
|
hyper also establishes a Minimum Supported Rust Version (MSRV). hyper will
|
|
support Rust versions at least 6 months old. If a new Rust version is released
|
|
with a feature hyper wishes to use, we won't do so until at least 6 months
|
|
afterwards. hyper will only ever require a new Rust version as a _minor_
|
|
release (1.x), not as a patch (1.x.y).
|
|
|
|
## Security
|
|
|
|
The security of hyper is a large part of what makes hyper _protective_. We make
|
|
hyper secure via the combined efforts of being **Correct**, focusing on
|
|
**HTTP/\***, and making it all **Understandable**.
|
|
|
|
### Memory Safety
|
|
|
|
Being **Correct** requires that hyper be memory-safe. Using the Rust language
|
|
gets us most of the way there. But there is the ability to write `unsafe`
|
|
Rust. Does being **Correct** mean that we can _never_ write `unsafe` code
|
|
anywhere? Even if it helps make hyper **Fast**? We can, carefully.
|
|
|
|
How do we balance the two, so that hyper is secure?
|
|
|
|
hyper prefers not to have large modules of intertwined `unsafe` code. hyper
|
|
does allow small `unsafe` blocks, no more than a few lines, where it's easier
|
|
to verify that the `unsafe` code was written **Correctly**.
|
|
|
|
### Meticulous Testing
|
|
|
|
hyper's test suite grows and grows. There's a lot that needs to be right.
|
|
Parsers, encoders, state machines. When easily isolated, those pieces have
|
|
internal unit tests. But hyper also keeps a large list of growing integration
|
|
tests that make sure all the parts are **Correct**.
|
|
|
|
Making writing new tests easy is a high priority. Investing in the testing
|
|
infrastructure is a proven way to make sure hyper stays **Correct** and secure.
|
|
|
|
### Constant Fuzzing
|
|
|
|
One thing is to know specific cases to test for. But we can't know all the
|
|
inputs or states that *might* cause a bug. That's why hyper has rounds of
|
|
fuzzing built into its CI. It's also why hyper signs up for and uses resources
|
|
to provide *constant*, around-the-clock fuzzing, always looking for something
|
|
that hyper should be hardened against.
|
|
|
|
### Security Process
|
|
|
|
hyper has an outlined
|
|
[SECURITY](https://github.com/hyperium/hyper/blob/master/SECURITY.md) process,
|
|
so we can safely report and fix issues.
|
|
|
|
## Non-goals
|
|
|
|
After writing this up, it is easier to articulate what sorts of things many
|
|
might associate with an HTTP library, but which are explicitly *not* for hyper.
|
|
These are all things that definitely **out of scope**.
|
|
|
|
- TLS: We learned early that bundling TLS directly in hyper [has
|
|
problems](https://github.com/hyperium/hyper/issues/985). People also have
|
|
very strong opinions about which TLS implementation to use. The design of
|
|
hyper allows users to bring their own TLS.
|
|
- Routing
|
|
- Cookies
|
|
- Not-HTTP: WebSockets, or other protocols that are built next to HTTP. It
|
|
should be possible to _use_ hyper to upgrade, but the actual next-protocol
|
|
should be handled by a different library.
|