Commit Graph

78 Commits

Author SHA1 Message Date
Sean McArthur
c7d4182ffe Release closed streams capacity back to connection (#334)
Previously, any streams that were dropped or closed while not having
consumed the inflight received window capacity would simply leak that
capacity for the connection. This could easily happen if a `RecvStream`
were dropped before fully consuming the data, and therefore a user would
have no idea how much capacity to release in the first place. This
resulted in stalled connections that would never have capacity again.
2018-12-05 09:44:20 -08:00
Carl Lerche
8387355e1b Avoid locking when printing (#333)
* Avoid locking when printing

It is not obvious that attempting to print the
value of a struct could cause a deadlock. To avoid
this, this patch does not lock the mutex when generating
a debug representation of the h2 struct.

* Use try_lock
2018-11-29 21:50:53 -08:00
Michael Beaumont
fc5efe73d6 Add OpaqueStreamRef constructor (#325)
Closes #318
2018-10-17 23:09:28 -07:00
Michael Beaumont
6b23542a55 Add client support for server push (#314)
This patch exposes push promises to the client API.

Closes #252
2018-10-16 12:51:08 -07:00
Geoffry Song
6d8554a23c Reassign capacity from reset streams. (#320)
I believe this was an oversight - a stream that is reset can still have some
capacity assigned to it (e.g. if said capacity was assigned in the same poll as
the reset), which should be redistributed.
2018-10-16 12:14:42 -07:00
Robert Ying
b116605560 Check whether the send side is not idle, not the recv side (#313)
* Check whether the send side is not idle, not the recv side
* Ensure sure we're handling window updates for the right side
* Add failing test
2018-10-16 12:03:56 -07:00
Eliza Weisman
f3806d5144 Add stream_id accessors to public API types (#292)
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>
2018-07-12 21:01:57 -07:00
Geoffry Song
23234fa14f Promote SendRequest::pending to an OpaqueStreamRef. (#281)
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.
2018-06-06 10:16:22 -07:00
Sean McArthur
3a4633d205 add SendResponse::poll_reset and SendStream::poll_reset to listen for reset streams (#279) 2018-05-30 22:57:43 +02:00
Carl Lerche
bb454e017c Enforce monotonic stream IDs for push promises (#275)
Previously, monotonic stream IDs (spec 5.1.1) for push promises were not
enforced. This was due to push promises going through an entirely
separate code path than normally initiated streams.

This patch unifies the code path for initializing streams via both
HEADERS and PUSH_PROMISE. This is done by first calling `recv.open` in
both cases.

Closes #272
2018-05-14 10:20:57 -07:00
Carl Lerche
cf62b783e0 Misc bug fixes related to stream state (#273)
This patch includes two new significant debug assertions:

* Assert stream counts are zero when the connection finalizes.
* Assert all stream state has been released when the connection is 
  dropped.

These two assertions were added in an effort to test the fix provided
by #261. In doing so, many related bugs have been discovered and fixed.
The details related to these bugs can be found in #273.
2018-05-09 15:03:21 -07:00
Sean McArthur
fadec67fdf prevent a leak of 'active streams' if client request has user error (#266) 2018-04-26 18:20:32 -07:00
Geoffry Song
11f914150e Add some missing bounds checks. (#260) 2018-04-23 14:38:42 -07:00
Sean McArthur
1c5d4ded50 Add Graceful Shutdown support
If graceful shutdown is initiated, a GOAWAY of the max stream ID - 1 is
sent, followed by a PING frame, to measure RTT. When the PING is ACKed,
the connection sends a new GOAWAY with the proper last processed stream
ID. From there, once all active streams have completely, the connection
will finally close.
2018-03-29 13:51:30 -07:00
Darren Tsung
f8baeb7211 Streams receiving peer reset clear pending send (#238)
Because streams that were being peer reset were not clearing pending
send frames / buffered_send_data, they were not being counted towards
the concurrency limit.
2018-03-13 12:47:57 -07:00
Darren Tsung
0c59957d88 When Streams are dropped, close Connection (#221) (#222)
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.
2018-02-15 13:14:18 -08:00
Sean McArthur
aa23a9735d SETTINGS_MAX_HEADER_LIST_SIZE (#206)
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 #18 
Closes #191
2018-01-05 09:23:48 -08:00
Sean McArthur
a89401dd91 reset pending push promises if user drops all refs (#199) 2017-12-20 16:50:20 -08:00
Sean McArthur
1552d62e7c ignore trailers for some time on locally reset streams (#194) 2017-12-19 15:06:05 -08:00
Sean McArthur
eafd6bfd98 release connection capacity when recv_data has stream error (#186) 2017-12-18 15:08:21 -08:00
Sean McArthur
1ea9a8fc7e ignore received frames on a stream locally reset for some time (#174)
- Adds config duration for how long to ignore frames on a reset stream
- Adds config for how many reset streams can be held at a time
2017-12-18 11:09:38 -08:00
Carl Lerche
9378846da8 Client should validate request URI. (#181)
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
2017-12-11 13:42:00 -06:00
Sean McArthur
6c68f72fbd notify stream send task when receiving EOF (#178)
* notify stream send task when receiving EOF

* record a conn_error on eof so client can see it

* fix stream id overflow test
2017-12-01 15:58:04 -08:00
Sean McArthur
2be2523162 notify stream refs when the connection receives EOF (#176) 2017-11-28 13:42:22 -08:00
Carl Lerche
c23d11306e Add RecvStream::is_end_stream. (#165)
This function returns true if the `RecvStream` has reached an end of
stream state. This is intended to replace `is_empty` which has confusing
behavior.
2017-10-21 09:59:27 -07:00
Carl Lerche
c4fc2928fe API cleanup (#155)
* 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
2017-10-19 20:02:08 -07:00
Sean McArthur
5c1bde7d62 add set_target_window_size methods to Server and Client (#149)
Closes #101
2017-10-13 11:19:56 -07:00
Holt Chesley
2aee78c7d7 Issue 128: Convert frame::Reason to struct (#142)
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.
2017-10-08 13:13:07 -07:00
Sean McArthur
bc679035f9 remove panic from Debug of StreamRef is mutex is poisoned 2017-10-06 14:20:32 -07:00
Eliza Weisman
2e3dcf602c StreamRef sends RST_STREAM on drop (#109)
This PR modifies the `Drop` implementation for `StreamRef` to reset the underlying stream if it is the last reference to that stream. Since both `Stream` and `Body` are internally just a `StreamRef`, this means they will both reset the stream on drop; thus, this closes #100.

The assertion that the store no longer contains the dropped stream ID at the end of the `Drop` method  had to be removed, as the stream has to be reset from inside of a `transition` block (which now manages releasing that ID for us), and the `transition` closure moves the value of `stream`, making the assertion no longer possible.

Modifications to some of the tests in `flow_control.rs` were also necessary, in order to prevent `StreamRef`s from being dropped too early.
2017-10-05 18:05:18 -05:00
Sean McArthur
ecd2764f4b when receiving a GOAWAY, allow earlier streams to still process (#133)
Once all active streams have finished, send a GOAWAY back and close the
connection.
2017-10-05 15:32:13 -07:00
Sean McArthur
c4ca8f7def Client::poll_ready and send_request may return Connection Errors (#132)
Closes #131
2017-10-04 15:22:10 -07:00
Sean McArthur
f8efb053b9 split Client into (Client, Connection) (#107)
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.
2017-09-28 16:55:12 -07:00
Oliver Gould
dad113e17b Disallow nightly failures (#115)
Always install rustfmt since nightly may change underneath it, causing
linking to break.

Apply rustfmt
2017-09-24 19:25:50 -07:00
Sean McArthur
db8c109817 Client::poll_ready() returns an Error if next stream ID would overflow (#103)
Closes #102
2017-09-19 14:16:32 -07:00
Sean McArthur
f7d14861e5 rustfmt: add trailing commas in match arms, set fn call to block stle (#85) 2017-09-12 19:29:06 -07:00
Oliver Gould
897bf84163 Use rustfmt to enforce consistent formatting
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.
2017-09-12 22:29:35 +00:00
Eliza Weisman
9448a19408 Factor out reset on RecvError::Stream (#76) 2017-09-11 13:07:37 -07:00
Carl Lerche
5c0efcf8c4 Ref count stream state and release when final (#73)
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.
2017-09-10 16:01:19 -07:00
Sean McArthur
452e49dc3e aggregate WINDOW_UPDATE frames until change is over 50% available 2017-09-07 08:20:03 -07:00
Carl Lerche
c2e6eb35d8 Track HTTP crate 2017-09-05 10:21:31 -07:00
Carl Lerche
b4fa5134f9 Data frame (#50)
* Rename DataFlag -> DataFlags
* Polish Data frame API
2017-09-05 10:00:05 -07:00
Carl Lerche
c122e97127 Refactor errors (#46)
This patch does a bunch of refactoring, mostly around error types, but it also
paves the way to allow `Codec` to be used standalone.

* `Codec` (and `FramedRead` / `FramedWrite`) is broken out into a codec module.
* An h2-codec crate is created that re-exports the frame and codec modules.
* New error types are introduced in the internals:
  * `RecvError` represents errors caused by trying to receive a frame.
  * `SendError` represents errors caused by trying to send a frame.
  * `UserError` is an enum of potential errors caused by invalid usage
    by the user of the lib.
  * `ProtoError` is either a `Reason` or an `io::Error`. However it doesn't
    specify connection or stream level.
  * `h2::Error` is an opaque error type and is the only error type exposed
    by the public API (used to be `ConnectionError`).

There are misc code changes to enable this as well. The biggest is a new "sink"
API for `Codec`. It provides buffer which queues up a frame followed by flush
which writes everything that is queued. This departs from the `Sink` trait in
order to provide more accurate error values. For example, buffer can never fail
(but it will panic if `poll_ready` is not called first).
2017-09-02 11:12:50 -07:00
Carl Lerche
6fd9674759 Validate received content-length header (#43)
If a content-length header is provided, the value should match the sum
of all data frame lengths. If there is a mismatch, then the stream is
reset.
2017-08-31 12:40:02 -04:00
Carl Lerche
2452cc4423 Validate & convert messages before buffering
Malformed requests and responses should immediately result in a
RST_STREAM. To support this, received header frames are validated and
converted to Request / Response values immediately on receipt and before
buffering.
2017-08-30 18:16:21 -04:00
Carl Lerche
9bb34d907a Thread P generic through all 2017-08-30 18:16:21 -04:00
Carl Lerche
14f35f1be6 Handle malformed HEADERS 2017-08-30 18:16:21 -04:00
Carl Lerche
91aa1db2ff Misc protocol fixes
* Verify contiuation frame stream ID
* Fix sending RST_STREAM in certain cases.
2017-08-30 18:16:21 -04:00
Carl Lerche
11d5f95236 Wire in trailers (#34)
Add send and receive trailer support.
2017-08-25 10:20:47 -07:00
Carl Lerche
b0e6867877 Fix warnings 2017-08-24 15:52:01 -07:00