Commit Graph

70 Commits

Author SHA1 Message Date
Alex Touchet
e13645c091 Update repo URLs (#370) 2019-06-04 23:06:13 -07:00
Sean McArthur
a3e59eb7e2 Prevent server Connection from returning same error after calling abrupt shutdown (#352) 2019-04-03 11:41:56 -07:00
Sean McArthur
e3a73f726e Add user PING support (#346)
- Add `share::PingPong`, which can send `Ping`s, and poll for the `Pong`
  from the peer.
2019-02-18 15:59:11 -08:00
Eliza Weisman
4b81e528d5 Log more information when rejecting malformed pseudo-headers (#342)
Currently, when a `h2` server receives a HEADERS frame with malformed
pseudo-headers, it logs which pseudo-heade was malformed at the debug
level before sending a reset. This behaviour is correct. However, it can
be difficult to debug misbehaving clients, as the server's log message
doesn't include the *value* of the invalid pseudo-header, or indicate
*why* it was incorrect. 

This branch changes the log message to include both the value of the
malformed header and the error that caused it to be rejected. 

For example, here is the output from the test
`server::recv_invalid_authority`, before and after making this change.

Before:
```
...
DEBUG 2019-01-23T19:16:28Z: h2::server: malformed headers: malformed authority
...
```

After:
```
...
DEBUG 2019-01-23T19:15:37Z: h2::server: malformed headers: malformed authority ("not:a/good authority"): invalid uri character
...
```

Note that it was necessary to clone the value of each pseudo-header
before passing it to the `uri::{Scheme, Authority, Path}::from_shared`
constructors, so that the value could be logged if those functions
return errors. However, since the pseudo-headers are internally
represented using `Bytes`, this should just increase the reference count
rather than copy the string, so I thought this was acceptable. 

If even a ref-count bump has an undesirable performance overhead, we
could consider using
```rust
if log_enabled!(Level::Debug) {
    // ...
}
```
to only clone if the message will be logged, but this makes the code
somewhat significantly more complicated. Therefore, I decided to punt on
that unless requested by a reviewer.

See also linkerd/linkerd2#2133

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2019-01-23 11:44:32 -08: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
Eliza Weisman
00ca534c4a Update examples to use new Tokio (#316)
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>
2018-09-25 14:33:49 -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
Arvid E. Picciani
74a5e072fe Fix tight loop on aborted connection (#285)
When the underlying IO returns 0 on read, we must stop polling it since
it's closed. Otherwise we'll be stuck in a tight loop.

this fixes https://github.com/sfackler/rust-openssl/issues/949
2018-06-15 16:04:13 -07:00
Arvid E. Picciani
2b59803866 fix doc typo (#286) 2018-06-15 15:40:26 -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
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
Oliver Gould
01d81b46c2 Add initial_connection_window_size to Builders (#249)
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.
2018-03-28 14:46:56 -07:00
Darren Tsung
4595b54cfa Add initial_max_send_streams() as builder option (#242) 2018-03-16 11:58:06 -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
walfie
73b4c03b55 Fix typos (#223) 2018-02-13 21:00:09 -08:00
Carl Lerche
5604372a8b Client documentation (#212)
Add documentation for client APIs.
2018-01-11 13:55:51 -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
Carl Lerche
d0b5b6246a Misc renames (#202)
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`.
2018-01-02 17:02:17 -08:00
Kenjiro Nakayama
0c67f7a390 Remove invalid brackets (#203) 2018-01-02 12:25:33 -08:00
Carl Lerche
4f963588a8 Add more library API documentation (#190)
This includes a section on inbound data control flow.
2017-12-19 12:00:03 -08:00
Carl Lerche
1a0b1eec2b Start writing API docs (#187)
This focuses mostly on the server module.
2017-12-18 14:27:30 -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
a437d46bee Remove most struct level bounds on handshake types (#182) 2017-12-13 22:49:07 -06: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
Carl Lerche
71888acea5 Additional debug/trace logging (#180) 2017-12-10 13:51:28 -06:00
Sean McArthur
b1d282799b Add must_use to futures, deny missing docs (#171) 2017-10-27 14:08:16 -07:00
Carl Lerche
17453dd307 Loosen some bounds. (#163) 2017-10-20 20:45:09 -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
Eliza Weisman
1e126aa752 Unbox server handshake future (#52)
Server-side version of #42. I've rewritten `server::Handshake` as a hand-rolled `Future` rather than as a `Box<Future>`. In addition to removing a `Box`, this also means that the `'static` lifetime bounds on the type parameters `T` and `B` can be removed.

The type of the server handshake future is somewhat more complex than the client-side handshake future. Note also that I've had to re-export `proto::streams::Prioritized` as `pub(crate)` from `proto`, as it appears in the type of the handshake future.

I've ran the tests against this branch and everything passes. Since no new functionality was added, I haven't added any additional tests.

This also fixes #158 - I had accidentally committed a Darwin h2spec executable and that's what was breaking CI.
2017-10-19 12:21:13 -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
Eliza Weisman
2fcf8c3740 Add methods to {client, server}::Builder to set max concurrent streams (#150)
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
2017-10-10 17:36:45 -05:00
Carl Lerche
4c7ecf158d Add ReleaseCapacity handle. (#148)
This enables releasing stream capacity without having the `Body` handle.
2017-10-09 14:00:28 -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
431442735d reset streams when receiving invalid psuedo headers 2017-10-06 13:48:30 -07:00
Sean McArthur
0c8bd75224 check for StreamId overflow (#68) 2017-09-19 13:10:48 -07:00
Oliver Gould
303b896095 Derive Clone for Builder types 2017-09-17 20:38:55 +00:00
Sean McArthur
c32015d48e add support for configuring max frame size
- 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
2017-09-14 17:03:43 -07:00
Sean McArthur
7531e5276b add Server Builder 2017-09-14 16:36:51 -07:00
Sean McArthur
ed472f109c add client::Builder to configure Clients 2017-09-13 14:32:27 -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
Carl Lerche
c2e6eb35d8 Track HTTP crate 2017-09-05 10:21:31 -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
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
9d45255c75 H2 headers must be lower case 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
Oliver Gould
f839443ece implement h2::server::Stream::send_reset(Reason) and Body::is_empty() (#22) 2017-08-23 12:48:00 -07:00