This commit is contained in:
nora 2023-03-07 14:00:23 +01:00
parent 25adea4103
commit 7af1274587
160 changed files with 38999 additions and 4 deletions

View file

@ -0,0 +1,21 @@
# Code of Conduct
## Be Kind
- Don't be mean.
- Insulting anyone is prohibited.
- Harassment of any kind is prohibited.
- If another person feels uncomfortable with your remarks, stop it.
- If a moderator deems your comment or conduct as inappropriate, stop it.
- Disagreeing is fine, but keep it to technical arguments. Never attack the person.
- Give the benefit of the doubt. Assume good intentions.
- Show empathy. There are 3 interpretations to any message: what we thought, what we said, and what they understand.
- This does mean we exclude people who are not kind. We are happy to make that sacrifice.
## Or Else
- Violations of the Code of Conduct will result in 1 warning.
- If the violation is major, a moderator may just ban immediately.
- If a warning has already been given, a moderator will ban the offender.
- There is no process for appealing a ban.
- Any violations can be reported to sean@seanmonstar.com.

65
hyper/docs/COMMITS.md Normal file
View file

@ -0,0 +1,65 @@
# Git Commit Guidelines
We have very precise rules over how our git commit messages can be formatted. This leads to **more
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the change log**.
## Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on github as well as in various git tools.
## Type
Must be one of the following:
* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug or adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
## Scope
The scope should refer to a module in hyper that is being touched. Examples:
* client
* server
* http1
* http2
* ffi
* upgrade
* examples
## Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
## Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes"
The body should include the motivation for the change and contrast this with previous behavior.
## Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
The last line of commits introducing breaking changes should be in the form `BREAKING CHANGE: <desc>`

113
hyper/docs/ISSUES.md Normal file
View file

@ -0,0 +1,113 @@
# Issues
The [issue tracker][issues] for hyper is where we track all features, bugs, and discuss proposals.
## Triaging
Once an issue has been opened, it is normal for there to be discussion
around it. Some contributors may have differing opinions about the issue,
including whether the behavior being seen is a bug or a feature. This
discussion is part of the process and should be kept focused, helpful, and
professional.
The objective of helping with triaging issues is to help reduce the issue
backlog and keep the issue tracker healthy, while enabling newcomers another
meaningful way to get engaged and contribute.
### Acknowledge
Acknowledge the human. This is meant actively, such as giving a welcome, or
thanks for a detailed report, or any other greeting that makes the person feel
that their contribution (issues are contributions!) is valued. It also is meant
to be internalized, and be sure to always [treat the person kindly][COC]
throughout the rest of the steps of triaging.
### Ask for more info
Frequently, we need more information than was originally provided to fully
evaluate an issue.
If it is a bug report, ask follow up questions that help us get a [minimum
reproducible example][MRE]. This may take several round-trip questions. Once
all the details are gathered, it may be helpful to edit the original issue text
to include them all.
### Categorize
Once enough information has been gathered, the issue should be categorized
with [labels][#labels]. Ideally, most issues should be labelled with an area,
effort, and severity. An issue _can_ have multiple areas, pick what fits. There
should be only one severity, and the descriptions of each should help to pick
the right one. The hardest label to select is "effort". If after reading the
descriptions of each effort level, you're still unsure, you can ping a
maintainer to pick one.
### Adjust the title
An optional step when triaging is to adjust the title once more information is
known. Sometimes an issue starts as a question, and through discussion, it
turns out to be a feature request, or a bug report. In those cases, the title
should be changed from a question, and the title should be a succinct action to
be taken. For example, a question about an non-existent configuration option
may be reworded to "Add option to Client to do Zed".
### Mentoring
The last part of triaging is to try to make the issue a learning experience.
After a discussion with the reporter, it would be good to ask if they are now
interested in submitting the change described in the issue.
Otherwise, it would be best to leave the issue with a series of steps for
anyone else to try to write the change. That could be pointing out that a
design proposal is needed, addressing certain points. Or, if the required
changes are mostly know, a list of links to modules and functions where code
needs to be changed, and to what. That way we mentor newcomers to become
successful contributors of new [pull requests][PRs].
## Labels
Issues are organized with a set of labels. Most labels follow a system of being prefixed by a "type".
### Area
The area labels describe what part of hyper is relevant.
- **A-body**: streaming request and response bodies.
- **A-client**: the HTTP client.
- **A-dependencies**: library dependencies.
- **A-docs**: documentation.
- **A-error**: error reporting and types.
- **A-ffi**: the C API.
- **A-http1**: the HTTP/1 specifics.
- **A-http2**: the HTTP/2 specifics.
- **A-server**: the HTTP server.
- **A-tests**: the unit and integration tests.
### Blocked
These labels indicate an issue is "blocked" for some reason.
- **B-breaking-change**: a breaking change that is waiting for the next semver-compatible release.
- **B-rfc**: request for comments. More discussion is needed to explore the design.
- **B-upstream**: waiting on something in a dependency or the compiler.
### Effort
The effort labels are a best-guess at roughly how much effort and knowledge of hyper is needed to accomplish the task.
- **E-easy**: a great starting point for a new contributor.
- **E-medium**: some knowledge of how hyper internals work would be useful.
- **E-hard**: likely requires a deeper understanding of how hyper internals work.
### Severity
The severity marks how _severe_ the issue is. Note this isn't "importance" or "priority".
- **S-bug**: something is wrong, this is bad!
- **S-feature**: this is a new feature request, adding something new.
- **S-performance**: make existing working code go faster.
- **S-refactor**: improve internal code to help readability and maintenance.
[issues]: https://github.com/hyperium/hyper/issues
[COC]: ./CODE_OF_CONDUCT.md
[PRs]: ./PULL_REQUESTS.md

9
hyper/docs/MSRV.md Normal file
View file

@ -0,0 +1,9 @@
# Minimum Support Rust Version (MSRV)
hyper's current policy is to always support a Rust version at least 6 months
old. That is, a compiler version released within the last 6 months can compile
hyper. It is possible that an older compiler can work, but that is not
guaranteed. We try to increase the MSRV responsibly, only when a significant
new feature is needed.
The current MSRV is: **1.56**.

View file

@ -0,0 +1,49 @@
# Pull Requests
Pull requests are the way to submit changes to the hyper repository.
## Submitting a Pull Request
In most cases, it a good idea to discuss a potential change in an
[issue](ISSUES.md). This will allow other contributors to provide guidance and
feedback _before_ significant code work is done, and can increase the
likelihood of getting the pull request merged.
### Tests
If the change being proposed alters code (as opposed to only documentation for
example), it is either adding new functionality to hyper or it is fixing
existing, broken functionality. In both of these cases, the pull request should
include one or more tests to ensure that hyper does not regress in the future.
### Commits
Once code, tests, and documentation have been written, a commit needs to be
made. Following the [commit guidelines](COMMITS.md) will help with the review
process by making your change easier to understand, and makes it easier for
hyper to produce a valuable changelog with each release.
However, if your message doesn't perfectly match the guidelines, **do not
worry!** The person that eventually merges can easily fixup the message at that
time.
### Opening the Pull Request
From within GitHub, open a new pull request from your personal branch.
Once opened, pull requests are usually reviewed within a few days.
### Discuss and Update
You will probably get feedback or requests for changes to your Pull Request.
This is a big part of the submission process so don't be discouraged! Some
contributors may sign off on the Pull Request right away, others may have more
detailed comments or feedback. This is a necessary part of the process in order
to evaluate whether the changes are correct and necessary.
Any community member can review a PR and you might get conflicting feedback.
Keep an eye out for comments from code owners to provide guidance on
conflicting feedback.
You don't need to close the PR and create a new one to address feedback. You
may simply push new commits to the existing branch.

3
hyper/docs/README.md Normal file
View file

@ -0,0 +1,3 @@
# Developing hyper
This is a set of documents outline how hyper is developed, how to contribute or get involved, various processes we use, and internal design explanations.

404
hyper/docs/ROADMAP.md Normal file
View file

@ -0,0 +1,404 @@
# hyper 1.0 Roadmap
## Goal
Align current hyper to the [hyper VISION][VISION].
The VISION outlines a decision-making framework, use-cases, and general shape
of hyper. This roadmap describes the currently known problems with hyper, and
then shows what changes are needed to make hyper 1.0 look more like what is in
the VISION.
## Known Issues
> **Note**: These known issues are as of hyper v0.14.x. After v1.0 is released,
ideally these issues will have been solved. Keeping this history may be helpful
to Future Us, though.
### Higher-level Client and Server problems
Both the higher-level `Client` and `Server` types have stability concerns.
For the `hyper::Server`:
- The `Accept` trait is complex, and too easy to get wrong. If used with TLS, a slow TLS handshake
can affect all other new connections waiting for it to finish.
- The `MakeService<&IO>` is confusing. The bounds are an assault on the eyes.
- The `MakeService` API doesn't allow to easily annotate the HTTP connection with `tracing`.
- Graceful shutdown doesn't give enough control.
It's more common for people to simply use `hyper::server::conn` at this point,
than to bother with the `hyper::Server`.
While the `hyper::Client` is much easier to use, problems still exist:
- The whole `Connect` design isn't stable.
- ALPN and proxies can provide surprising extra configuration of connections.
- Some `Connect` implementations may wish to view the path, in addition to the scheme, host, and port.
- Wants `runtime` feature
- The Pool could be made more general or composable. At the same time, more customization is
desired, and it's not clear
how to expose it yet.
### Runtime woes
hyper has been able to support different runtimes, but it has sometimes awkward
default support for Tokio.
- The `runtime` cargo-feature isn't additive
- Built-in Tokio support can be confusing
- Executors and Timers
- The `runtime` feature currently enables a few options that require a timer, such as timeouts and
keepalive intervals. It implicitly relies on Tokio's timer context. This can be quite confusing.
- IO traits
- Should we publicly depend on Tokio's traits?
- `futures-io`?
- Definitely nope.
- Not stable. (0.3?)
- No uninitialized memory.
- Eventual `std` traits?
- They've been in design for years.
- We cannot base our schedule on them.
- When they are stable, we can:
- Provide a bridge in `hyper-util`.
- Consider a 2.0 of hyper.
- Define our own traits, provide util wrappers?
### Forwards-compatibility
There's a concern about forwards-compatibility. We want to be able to add
support for new HTTP features without needing a new major version. While most
of `http` and `hyper` are prepared for that, there's two potential problems.
- New frames on an HTTP stream (body)
- Receiving a new frame type would require a new trait method
- There's no way to implement a "receive unknown frame" that hyper doesn't know about.
- Sending an unknown frame type would be even harder.
- Besides being able to pass an "unknown" type through the trait, the user would need to be
able to describe how that frame is encoded in HTTP/2/3.
- New HTTP versions
- HTTP/3 will require a new transport abstraction. It's not as simple as just using some
`impl AsyncRead + AsyncWrite`. While HTTP/2 bundled the concept of stream creation internally,
and thus could be managed wholly on top of a read-write transport, HTTP/3 is different. Stream
creation is shifted to the QUIC protocol, and HTTP/3 needs to be able to use that directly.
- This means the existing `Connection` types for both client and server will not be able to
accept a QUIC transport so we can add HTTP/3 support.
### Errors
It's not easy to match for specific errors.
The `Error::source()` can leak an internal dependency. For example, a
`hyper::Error` may wrap an `h2::Error`. Users can downcast the source at
runtime, and hyper internally changing the version of its `h2` dependency can
cause runtime breakage for users.
Formatting errors is in conflict with the current expected norm. The
`fmt::Display` implementation for `hyper::Error` currently prints its own
message, and then prints the message of any wrapped source error. The Errors
Working Group currently recommends that errors only print their own message
(link?). This conflict means that error "reporters", which crawl a source chain
and print each error, has a lot of duplicated information.
```
error fetching website: error trying to connect: tcp connect error: Connection refused (os error 61)
tcp connect error: Connection refused (os error 61)
Connection refused (os error 61)
```
While there is a good reason for why hyper's `Error` types do this, at the very
least, it _is_ unfortunate.
### You call hyper, or hyper calls you?
> Note: this problem space, of who calls whom, will be explored more deeply in
> a future article.
At times, it's been wondered whether hyper should call user code, or if user
code should call hyper. For instance, should a `Service` be called with a
request when the connection receives one, or should the user always poll for
the next request.
There's a similar question around sending a message body. Should hyper ask the
body for more data to write, or should the user call a `write` method directly?
These both get at a root topic about [write
observability](https://github.com/hyperium/hyper/issues/2181). How do you know
when a response, or when body data, has been written successfully? This is
desirable for metrics, or for triggering other side-effects.
The `Service` trait also has some other frequently mentioned issues. Does
`poll_ready` pull its complexity weight for servers? What about returning
errors, what does that mean? Ideally users would turn all errors into
appropriate `http::Response`s. But in HTTP/2 and beyond, stream errors are
different from HTTP Server Error responses. Could the `Service::Error` type do
more to encourage best practices?
## Design
The goal is to get hyper closer to the [VISION][], using that to determine the
best way to solve the known issues above. The main thrust of the proposed
changes are to make hyper more **Flexible** and stable.
In order to keep hyper **Understandable**, however, the proposed changes *must*
be accompanied by providing utilities that solve the common usage patterns,
documentation explaining how to use the more flexible pieces, and guides on how
to reach for the `hyper-util`ity belt.
The majority of the changes are smaller and can be contained to the *Public
API* section, since they usually only apply to a single module or type. But the
biggest changes are explained in detail here.
### Split per HTTP version
The existing `Connection` types, both for the client and server, abstract over
HTTP version by requiring a generic `AsyncRead + AsyncWrite` transport type.
But as we figure out HTTP/3, that needs to change. So to prepare now, the
`Connection` types will be split up.
For example, there will now be `hyper::server::conn::http1::Connection` and
`hyper::server::conn::http2::Connection` types.
These specific types will still have a very similar looking API that, as the
VISION describes, provides **Correct** connection management as it pertains to
HTTP.
There will be still be a type to wrap the different versions. It will no longer
be generic over the transport type, to prepare for being able to wrap HTTP/3
connections. Exactly how it will wrap, either by using internal trait objects,
or an `enum Either` style, or using a `trait Connection` that each type
implements, is something to be determined. It's likely that this "auto" type
will start in `hyper-util`.
### Focus on the `Connection` level
As mentioned in the *Known Issues*, the higher-level `Client` and `Server` have
stability and complexity problems. Therefore, for hyper 1.0, the main API will
focus on the "lower-level" connection types. The `Client` and `Server` helpers
will be moved to `hyper-util`.
## Public API
### body
The `Body` struct is removed. Its internal "variants" are [separated into
distinct types](https://github.com/hyperium/hyper/issues/2345), and can start
in either `hyper-util` or `http-body-util`.
The exported trait `HttpBody` is renamed to `Body`.
A single `Body` implementation in `hyper` is the one provided by receiving
client responses and server requests. It has the name `Streaming`.
> **Unresolved**: Other names can be considered during implementation. Another
> option is to not publicly name the implementation, but return `Response<impl
Body>`s.
The `Body` trait will be experimented on to see about making it possible to
return more frame types beyonds just data and trailers.
> **Unresolved**: What exactly this looks like will only be known after
> experimentation.
### client
The high-level `hyper::Client` will be removed, along with the
`hyper::client::connect` module. They will be explored more in `hyper-util`.
As described in *Design*, the `client::conn` module will gain `http1` and
`http2` sub-modules, providing per-version `SendRequest`, `Connection`, and
`Builder` structs. An `auto` version can be explored in `hyper-util`.
### error
The `hyper::Error` struct remains in place.
All errors returned from `Error::source()` are made opaque. They are wrapped an
internal `Opaque` newtype that still allows printing, but prevents downcasting
to the internal dependency.
A new `hyper::error::Code` struct is defined. It is an opaque struct, with
associated constants defining various code variants.
> Alternative: define a non-exhaustive enum. It's not clear that this is
> definitely better, though. Keeping it an opaque struct means we can add
> secondary parts to the code in the future, or add bit flags, or similar
> extensions.
The purpose of `Code` is to provide an abstraction over the kind of error that
is encountered. The `Code` could be some behavior noticed inside hyper, such as
an incomplete HTTP message. Or it can be "translated" from the underlying
protocol, if it defines protocol level errors. For example, an
`h2::Reason::CANCEL`.
### rt
The `Executor` trait stays in here.
Define a new trait `Timer`, which describes a way for users to provide a source
of sleeping/timeout futures. Similar to `Executor`, a new generic is added to
connection builders to provide a `Timer`.
### server
The higher-level `hyper::Server` struct, its related `Builder`, and the
`Accept` trait are all removed.
The `AddrStream` struct will be completely removed, as it provides no value but
causes binary bloat.
Similar to `client`, and as describe in the *Design*, the `conn` modules will
be expanded to support `http1` and `http2` submodules. An `auto` version can be
explored in `hyper-util`.
### service
A vendored and simplified `Service` trait will be explored.
The error type for `Service`s used for a server will explore having the return
type changed from any error to one that can become a `hyper::error::Code`.
> **Unresolved**: Both of the above points are not set in stone. We will
> explore and decide if they are the best outcome during development.
The `MakeService` pieces will be removed.
### Cargo Features
Remove the `stream` feature. The `Stream` trait is not stable, and we cannot
depend on an unstable API.
Remove the `tcp` and `runtime` features. The automatic executor and timer parts
are handled by providing implementations of `Executor` and `Timer`. The
`connect` and `Accept` parts are also moving to `hyper-util`.
### Public Dependencies
- `http`
- `http-body`
- `bytes`
Cannot be public while "unstable":
- `tracing`
## `hyper-util`
### body
A channel implementation of `Body` that has an API to know when the data has
been successfully written is provided in `hyper_util::body::channel`.
### client
A `Pool` struct that implements `Service` is provided. It fills a similar role
as the previous `hyper::Client`.
> **Note**: The `Pool` might be something that goes into the `tower` crate
> instead. Or it might stay here as a slightly more specialized racing-connect
> pool. We'll find out as we go.
A `connect` submodule that mostly mirrors the existing `hyper::client::connect`
module is moved here. Connectors can be used as a source to provide `Service`s
used by the `Pool`.
### rt
We can provide Tokio-backed implementations of `Executor` and `Timer`.
### server
A `GracefulShutdown` helper is provided, to allow for similar style of graceful
shutdown as the previous `hyper::Server` did, but with better control.
# Appendix
## Unresolved Questions
There are some parts of the proposal which are not fully resolved. They are
mentioned in Design and API sections above, but also collected here for easy
finding. While they all have _plans_, they are more exploratory parts of the
API, and thus they have a higher possibility of changing as we implement them.
The goal is to have these questions resolved and removed from the document by
the time there is a [Release Candidate][timeline].
### Should there be `hyper::io` traits?
Depending on `tokio` just for `AsyncRead` and `AsyncWrite` is convenient, but
can be confusing for users integrating hyper with other runtimes. It also ties
our version directly to Tokio. We can consider having vendored traits, and
providing Tokio wrappers in `hyper-util`.
### Should returned body types be `impl Body`?
### How could the `Body` trait prepare for unknown frames?
We will experiment with this, and keep track of those experiments in a
dedicated issue. It might be possible to use something like this:
```rust
pub trait Body {
type Data;
fn poll_frame(..) -> Result<Option<Frame<Self::Data>>>;
}
pub struct Frame<T>(Kind<T>);
enum Kind<T> {
Data(T),
Trailers(HeaderMap),
Unknown(Box<dyn FrameThingy>),
}
```
### Should there be a simplified `hyper::Service` trait, or should hyper depend on `tower-service`?
- There's still a few uncertain decisions around tower, such as if it should be
changed to `async fn call`, and if `poll_ready` is the best way to handle
backpressure.
- It's not clear that the backpressure is something needed at the `Server`
boundary, thus meaning we should remove `poll_ready` from hyper.
- It's not 100% clear if we should keep the service pattern, or use a
pull-based API. This will be explored in a future blog post.
## FAQ
### Why did you pick _that_ name? Why not this other better name?
Naming is hard. We certainly should solve it, but discussion for particular
names for structs and traits should be scoped to the specific issues. This
document is to define the shape of the library API.
### Should I publicly depend on `hyper-util`?
The `hyper-util` crate will not reach 1.0 when `hyper` does. Some types and
traits are being moved to `hyper-util`. As with any pre-1.0 crate, you _can_
publicly depend on it, but it is explicitly less stable.
In most cases, it's recommended to not publicly expose your dependency on
`hyper-util`. If you depend on a trait, such as used by the moved higher-level
`Client` or `Server`, it may be better for your users to define your own
abstraction, and then make an internal adapter.
### Isn't this making hyper harder?
We are making hyper more **flexible**. As noted in the [VISION][], most use
cases of hyper require it to be flexible. That _can_ mean that the exposed API
is lower level, and that it feels more complicated. It should still be
**understandable**.
But the hyper 1.0 effort is more than just the single `hyper` crate. Many
useful helpers will be migrated to a `hyper-util` crate, and likely improved in
the process. The [timeline][] also points out that we will have a significant
documentation push. While the flexible pieces will be in hyper to compose how
they need, we will also write guides for the [hyper.rs][] showing people how to
accomplish the most common tasks.
[timeline]: https://seanmonstar.com/post/676912131372875776/hyper-10-timeline
[VISION]: https://github.com/hyperium/hyper/pull/2772
[hyper.rs]: https://hyper.rs

100
hyper/docs/TENETS.md Normal file
View file

@ -0,0 +1,100 @@
# 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
hyper is open source, always. The success of hyper depends on the health of the
community building and using it. All contributions are in the open. We don't
maintain private versions, and don't include features that aren't useful to
others.
[We prioritize kindness][CONDUCT], compassion and empathy towards all
contributors. Technical skill is not a substitute for human decency.
[CONDUCT]: https://github.com/hyperium/hyper/blob/master/docs/CODE_OF_CONDUCT.md
### Examples
It's not usually hard for an open source library to stay open and also meet its
other priorities. Here's some instances where being **Open** would be more
important than **Correct** or **Fast**:
- Say an individual were to bring forward a contribution that makes hyper more
correct, or faster, perhaps fixing some serious bug. But in doing so, they
also insulted people, harassed other contributors or users, or shamed
everyone for the previous code. They felt their contribution was "invaluable".
We would not accept such a contribution, instead banning the user and
rewriting the code amongst the kind collaborators of the project.
- Say someone brings a contribution that adds a new feature useful for
performance or correctness, but their work accomplishes this by integrating
hyper with a proprietary library. We would not accept such a contribution,
because we don't want such a feature limited only to those users willing to
compromise openness, and we don't want to bifurcate the ecosystem between those
who make that compromise and those who don't.
## 1. Correct
hyper is a memory safe and precise implementation of the HTTP specification.
Memory safety is vital in a core Internet technology. Following the HTTP
specifications correctly protects users. It makes the software durable to the
“real world”. Where feasible, hyper enforces correct usage.
This is more than just "don't write bugs". hyper actively protects the user.
### Examples
- Even though we follow the **HTTP/\*** specs, hyper doesn't blindly implement
everything without considering if it is safe to do so.
## 2. Fast
A fast experience delights users. A faster network library means a faster
application, resulting in delighting our users users. Whether with one request,
or millions.
Being _fast_ means we improve throughput, drive down CPU usage, and improve
sustainability.
Fast _enough_. We don't sacrifice sanity for speed.
## 3. HTTP/*
hyper is specifically focused on HTTP. Supporting new HTTP versions is in scope,
but supporting separate protocols is not.
This also defines what the abstraction layer is: the API is designed around
sending and receiving HTTP messages.
## 4. Flexible
hyper enables as many usecases as possible. It has no opinion on application
structure, and makes few assumptions about its environment. This includes being
portable to different operating systems.
### Examples
- While we choose safer defaults to be **Correct**, hyper includes options to
_allow_ different behavior, when the user requires them.
- Providing choice usually makes things more complex, so being **Flexible** does
mean it's less _easy_. That can sometimes conflict with simplest way of making
hyper **Understandable**.
## 5. Understandable
hyper is [no more complicated than it has to
be](https://en.wikipedia.org/wiki/Occam%27s_razor). HTTP is not simple. It may
not be as "easy" as 1-line to do everything, but it shouldn't be "hard" to find
the answers.
From logical and misuse-resistant APIs, to stellar documentation, to transparent
metrics.

230
hyper/docs/VISION.md Normal file
View file

@ -0,0 +1,230 @@
# 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.
![architecture diagram](./vision-arch.svg)
#### 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.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.7 KiB