From a3bda62da36060a38638fba983a0c07c0ab6259d Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Tue, 10 Dec 2024 11:55:08 -0500 Subject: [PATCH] docs(roadmap): update ROADMAP post v1.0 (#3763) --- docs/ROADMAP-1.0.md | 406 ++++++++++++++++++++++++++++++++++++++++ docs/ROADMAP.md | 443 ++++++++------------------------------------ 2 files changed, 481 insertions(+), 368 deletions(-) create mode 100644 docs/ROADMAP-1.0.md diff --git a/docs/ROADMAP-1.0.md b/docs/ROADMAP-1.0.md new file mode 100644 index 0000000000..f3894fa0bb --- /dev/null +++ b/docs/ROADMAP-1.0.md @@ -0,0 +1,406 @@ +# hyper 1.0 Roadmap + +> This was the roadmap to arrive at hyper v1.0. It is kept for historical purposes. See [ROADMAP](./ROADMAP.md) for the latest. + +## 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`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>>; +} + +pub struct Frame(Kind); + +enum Kind { + Data(T), + Trailers(HeaderMap), + Unknown(Box), +} +``` + +### 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 diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 184cc7adf5..5207438840 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,404 +1,111 @@ -# hyper 1.0 Roadmap +# Roadmap ## Goal -Align current hyper to the [hyper VISION][VISION]. +Align current hyper to the [hyper VISION](./VISION.md). 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. +of hyper. This roadmap describes the focus areas to continue to improve hyper +to look more like what is in the VISION. -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. +## Focus Areas -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. +While open source is not a company, open source can be guiding. We _can_ focus +attention to specific areas of improvement, which are based on conversations +with users, and prioritized by frequency and impact. -``` -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) -``` +To that end, the following 4 areas are current focus of the project: -While there is a good reason for why hyper's `Error` types do this, at the very -least, it _is_ unfortunate. +1. Documentation +2. `hyper-util` +3. HTTP/3 +4. Observability -### You call hyper, or hyper calls you? +Each area benefits from having a top level description and goal, a place to +track progress, and a champion (or two) that helps push the effort. -> Note: this problem space, of who calls whom, will be explored more deeply in -> a future article. +### Documentation -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. +hyper has stabilized, so investing in documentation is wise! The way it is used +won't change much, so documentation won't become outdated quickly. A tool that +people don't know how to use isn't helpful at all. This helps hyper be +**Understandable**. -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? +The documentation focus area includes several different forms: -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 API docs as a reference. +- Examples as form of how-to. +- Website guides as tutorials. -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. +Each of these could benefit from dedicated planning of their overall structure, +editing the content that already exists, and creating the rest that is sorely +missing. -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. +### hyper-util -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. +`hyper-util` serves two main purposes: -### Split per HTTP version +1. Provide useful patterns that build on top of hyper. +2. Explore, stabilize, and graduate some of those patterns into hyper itself. -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. +To that end, there are several new features that can be worked on and iterated +on in `hyper-util` right now: -For example, there will now be `hyper::server::conn::http1::Connection` and -`hyper::server::conn::http2::Connection` types. +- New design for a higher-level `Client`. +- Breaking apart some patterns from `reqwest`, such as proxy helpers. +- Server automatic version detection. +- Improved builder patterns that make it easier to configure complicated + options. -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. +### HTTP/3 -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`. +hyper has an HTTP/3 crate, `h3`, that is generic over any QUIC implementation, +similar to how hyper's HTTP/1 and HTTP/2 can be provided any IO transport. It +supports much of HTTP/3 already, and interoperates with most other +implementations. While some brave users have been trying it out the hard way +(such as reqwest), it's time to bring HTTP/3 to more users. -### Focus on the `Connection` level +The aim is to eventually support `hyper::client::conn::http3` and +`hyper::server::conn::http3`. -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`. +To do so, work is needed: -## Public API +- Harden the `h3` crate itself, such as fixing any straggling interop issues, + and filling out the spec conformance tags we use for accountability. +- Proposal for (initially unstable) `hyper::rt::quic` integration, allowing + people to bring their own QUIC. +- Write the `hyper::proto::http3` glue that translates hyper's connection + patterns with the `h3` crate. -### body +### Observability -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`. +It's extremely common once operating a service using hyper to want more +visibility in what exactly is happening. It's important to realize that there +are 3 concepts involved that frequently get conflated: events, tracing, and +metrics. -The exported trait `HttpBody` is renamed to `Body`. +Some existing ways to get some of these: -A single `Body` implementation in `hyper` is the one provided by receiving -client responses and server requests. It has the name `Streaming`. +- Unstable `tracing` integraton inside hyper. +- `tower_http::trace` which instruments outside of hyper, using `Service` and + `Body`. -> **Unresolved**: Other names can be considered during implementation. Another -> option is to not publicly name the implementation, but return `Response`s. +However, there are some events and metrics that are only known inside hyper, +and having official, stable support would be very helpful. -The `Body` trait will be experimented on to see about making it possible to -return more frame types beyonds just data and trailers. +Some potential options would be: -> **Unresolved**: What exactly this looks like will only be known after -> experimentation. +- Stabilizing specific `tracing` events (blocked on the `tracing` crate + stabilizing...) +- Provide a rudimentary, programmatic way to query metrics without another + crate. +- Provide some sort of `hyper-metrics` helper. -### client +## Beyond -The high-level `hyper::Client` will be removed, along with the -`hyper::client::connect` module. They will be explored more in `hyper-util`. +The above are focus areas that are the most frequently asked for, and so have +the most attention. That doesn't mean that nothing else can be worked on. -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`. +Motivated individuals that want to help make other improvements are certainly +welcome! -### 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>>; -} - -pub struct Frame(Kind); - -enum Kind { - Data(T), - Trailers(HeaderMap), - Unknown(Box), -} -``` - -### 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