The old `tokio-core` crate is deprecated in favour of the `tokio` crate,
which also provides the new multithreaded Tokio runtime. Although `h2`
is generic over the runtime, the examples do depend on `tokio`.
This branch update the example code to use the new `tokio` library
rather than `tokio-core`. It also updates the examples in `RustDoc`.
For the most part, this was pretty trivial --- simply replacing
`handle.spawn(...)` with `tokio::spawn(...)` and `core.run(...)` with
`tokio::run(...)`. There were a couple of cases where error and item
types from spawned futures had to be mapped to `(), ()`. Alternatively,
this could have been avoided by using the single-threaded runtime and
calling `block_on` instead to await the value of those futures, but I
thought it was better to reduce the amount of tokio-specific code in the
examples.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Problem:
Applications may want to access the underlying h2 stream ID for
diagnostics, etc. Stream IDs were not previously exposed in public APIs.
Solution:
Added a new public `share::StreamId` type, which has a more restricted
API than the internal `frame::StreamId` type. The public API types
`SendStream`, `RecvStream`, `ReleaseCapacity`,
`client::ResponseFuture`, and `server::SendResponse` now all have
`stream_id` methods which return the stream ID of the corresponding
stream.
Closes#289.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Because `self.pending` doesn't necessarily get cleaned up in a timely fashion -
rather, only when the user calls `poll_ready()` - it was possible for it to
refer to a stream that has already been closed. This would lead to a panic the
next time that `poll_ready()` was called.
Instead, use an `OpaqueStreamRef`, bumping the refcount.
A change to an existing test is included which demonstrates the issue.
There is currently no way to configure the initial target window size
for connections. The `Builder::initial_connection_window_size` utilities
make this configurable so that all new connections have this target
window size set.
When all Streams are dropped / finished, the Connection was held
open until the peer hangs up. Instead, the Connection should hang up
once it knows that nothing more will be sent.
To fix this, we notify the Connection when a stream is no longer
referenced. On the Connection poll(), we check that there are no
active, held, reset streams or any references to the Streams
and transition to sending a GOAWAY if that is case.
The specific behavior depends on if running as a client or server.
This, uh, grew into something far bigger than expected, but it turns out, all of it was needed to eventually support this correctly.
- Adds configuration to client and server to set [SETTINGS_MAX_HEADER_LIST_SIZE](http://httpwg.org/specs/rfc7540.html#SETTINGS_MAX_HEADER_LIST_SIZE)
- If not set, a "sane default" of 16 MB is used (taken from golang's http2)
- Decoding header blocks now happens as they are received, instead of buffering up possibly forever until the last continuation frame is parsed.
- As each field is decoded, it's undecoded size is added to the total. Whenever a header block goes over the maximum size, the `frame` will be marked as such.
- Whenever a header block is deemed over max limit, decoding will still continue, but new fields will not be appended to `HeaderMap`. This is also can save wasted hashing.
- To protect against enormous string literals, such that they span multiple continuation frames, a check is made that the combined encoded bytes is less than the max allowed size. While technically not exactly what the spec suggests (counting decoded size instead), this should hopefully only happen when someone is indeed malicious. If found, a `GOAWAY` of `COMPRESSION_ERROR` is sent, and the connection shut down.
- After an oversize header block frame is finished decoding, the streams state machine will notice it is oversize, and handle that.
- If the local peer is a server, a 431 response is sent, as suggested by the spec.
- A `REFUSED_STREAM` reset is sent, since we cannot actually give the stream to the user.
- In order to be able to send both the 431 headers frame, and a reset frame afterwards, the scheduled `Canceled` machinery was made more general to a `Scheduled(Reason)` state instead.
Closes#18Closes#191
This patch renames a number of types and functions making
the API more consistent.
* `Server` -> `Connection`
* `Client` -> `SendRequest`
* `Respond` -> `SendResponse`.
It also moves the handshake fns off of `Connection` and make
them free fns in the module. And `Connection::builder` is removed
in favor of `Builder::new`.
This patch adds checks for the request URI and rejects invalid URIs. In
the case of forwarding an HTTP 1.1 request with a path, an "http" pseudo
header is added to satisfy the HTTP/2.0 spec.
Closes#179
* Change send_reset to take &mut self.
While calling this function is the last thing that should be done with
the instance, the intent of the h2 library is not to be used directly by
users, but to be used as an implementation detail by other libraries.
Requiring `self` on `send_reset` is pretty annoying when calling the
function from inside a `Future` implementation. Also, all the other fns
on the type take `&mut self`.
* Remove the P: Peer generic from internals
* Split out `Respond` from `server::Stream`
This new type is used to send HTTP responses to the client as well as
reserve streams for push promises.
* Remove unused `Send` helper.
This could be brought back later when the API becomes stable.
* Unite `client` and `server` types
* Remove `B` generic from internal proto structs
This is a first step in removing the `B` generic from public API types
that do not strictly require it.
Currently, all public API types must be generic over `B` even if they do
not actually interact with the send data frame type. The first step in
removing this is to remove `B` as a generic on all internal types.
* Remove `Buffer<B>` from inner stream state
This is the next step in removing the `B` generic from all public API
types. The send buffer is the only type that requires `B`. It has now
been extracted from the rest of the stream state.
The strategy used in this PR requires an additional `Arc` and `Mutex`,
but this is not a fundamental requirement. The additional overhead can
be avoided with a little bit of unsafe code. However, this optimization
should not be made until it is proven that it is required.
* Remove `B` generic from `Body` + `ReleaseCapacity`
This commit actually removes the generic from these two public API
types. Also note, that removing the generic requires that `B: 'static`.
This is because there is no more generic on `Body` and `ReleaseCapacity`
and the compiler must be able to ensure that `B` outlives all `Body` and
`ReleaseCapacity` handles.
In practice, in an async world, passing a non 'static `B` is never going
to happen.
* Remove generic from `ResponseFuture`
This change also makes generic free types `Send`. The original strategy
of using a trait object meant that those handles could not be `Send`.
The solution was to avoid using the send buffer when canceling a stream.
This is done by transitioning the stream state to `Canceled`, a new
`Cause` variant.
* Simplify Send::send_reset
Now that implicit cancelation goes through a separate path, the
send_reset function can be simplified.
* Export types common to client & server at root
* Rename Stream -> SendStream, Body -> RecvStream
* Implement send_reset on server::Respond
This PR adds `max_concurrent_streams()` methods to the client and server `Builder`s to set the `max_concurrent_streams` setting. I've added unit tests to ensure the correct SETTINGS frame is sent.
Closes#106
Alter frame::Reason to a struct with a single u32 member.
Introduce Constants to the impl for existing Reasons. Change all usage
in the library and its tests to adopt this change,
using the new constants.
The Connection type is a `Future` that drives all of the IO of the
client connection.
The Client type is separate, and is used to send requests into the
connection.
- Adds `max_frame_size` to client and server builders
- Pushes max_frame_size into Codec
- Detects when the Codec triggers an error from a frame too big
- Sends a GOAWAY when FRAME_SIZE_ERROR is encountered reading a frame
This change adds a .rustfmt.toml that includes ALL supported settings,
12 of which we have overridden to attempt to cater to our own
proclivities.
rustfmt is checked in the rust-nightly CI job.
Previously, stream state was never released so that long-lived connections
leaked memory.
Now, stream states are reference-counted and freed from the stream slab
when complete. Locally reset streams are retained so that received frames
may be ignored.