Giter Site home page Giter Site logo

h2's Introduction

H2

A Tokio aware, HTTP/2 client & server implementation for Rust.

License: MIT Crates.io Documentation

More information about this crate can be found in the crate documentation.

Features

  • Client and server HTTP/2 implementation.
  • Implements the full HTTP/2 specification.
  • Passes h2spec.
  • Focus on performance and correctness.
  • Built on Tokio.

Non goals

This crate is intended to only be an implementation of the HTTP/2 specification. It does not handle:

  • Managing TCP connections
  • HTTP 1.0 upgrade
  • TLS
  • Any feature not described by the HTTP/2 specification.

This crate is now used by hyper, which will provide all of these features.

Usage

To use h2, first add this to your Cargo.toml:

[dependencies]
h2 = "0.4"

Next, add this to your crate:

extern crate h2;

use h2::server::Connection;

fn main() {
    // ...
}

FAQ

How does h2 compare to solicit or rust-http2?

The h2 library has implemented more of the details of the HTTP/2 specification than any other Rust library. It also passes the h2spec set of tests. The h2 library is rapidly approaching "production ready" quality.

Besides the above, Solicit is built on blocking I/O and does not appear to be actively maintained.

Is this an embedded Java SQL database engine?

No.

h2's People

Contributors

95th avatar atouchet avatar briansmith avatar carllerche avatar darrentsung avatar davidkorczynski avatar djc avatar dswij avatar eaufavor avatar ehaydenr avatar f0rki avatar goffrie avatar gtsiam avatar hawkw avatar herbstein avatar ignatenkobrain avatar jxs avatar kornelski avatar luciofranco avatar magurotuna avatar michaelbeaumont avatar nak3 avatar nickelc avatar noah-kennedy avatar nox avatar olix0r avatar seanmonstar avatar sfackler avatar taiki-e avatar tottoto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

h2's Issues

receivers may not properly apply flow control

Here, we're looking at an h2 client talking to a grpc-go server:

Client sends a request:

   15   2.021388 55082 8888 HTTP2 173 HEADERS, DATA          ::1 → ::1         
Frame 15: 173 bytes on wire (1384 bits), 173 bytes captured (1384 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 43, Ack: 32, Len: 97
HyperText Transfer Protocol 2
    Stream: HEADERS, Stream ID: 1, Length 70
        Length: 70
        Type: HEADERS (1)
        Flags: 0x04
            .... ...0 = End Stream: False
            .... .1.. = End Headers: True

server responds with headers:

   17   2.023249 8888 55082 HTTP2 99 HEADERS          ::1 → ::1         
Frame 17: 99 bytes on wire (792 bits), 99 bytes captured (792 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 32, Ack: 140, Len: 23
HyperText Transfer Protocol 2
    Stream: HEADERS, Stream ID: 1, Length 14
        Length: 14
        Type: HEADERS (1)
        Flags: 0x04
            .... ...0 = End Stream: False
            .... .1.. = End Headers: True

server responds with data frames:

   20   2.023338 8888 55082 HTTP2 157 DATA          ::1 → ::1         
Frame 20: 157 bytes on wire (1256 bits), 157 bytes captured (1256 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 16367, Ack: 140, Len: 81
[2 Reassembled TCP Segments (16393 bytes): #19(16312), #20(81)]
HyperText Transfer Protocol 2
    Stream: DATA, Stream ID: 1, Length 16384

   23   2.023411 8888 55082 HTTP2 157 DATA          ::1 → ::1         
Frame 23: 157 bytes on wire (1256 bits), 157 bytes captured (1256 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 32760, Ack: 140, Len: 81
[2 Reassembled TCP Segments (16393 bytes): #22(16312), #23(81)]
HyperText Transfer Protocol 2
    Stream: DATA, Stream ID: 1, Length 16384

   26   2.023456 8888 55082 HTTP2 157 DATA          ::1 → ::1         
Frame 26: 157 bytes on wire (1256 bits), 157 bytes captured (1256 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 49153, Ack: 140, Len: 81
[2 Reassembled TCP Segments (16393 bytes): #25(16312), #26(81)]
HyperText Transfer Protocol 2
    Stream: DATA, Stream ID: 1, Length 16384
        Length: 16384

   29   2.023491 8888 55082 HTTP2 156 DATA          ::1 → ::1         
Frame 29: 156 bytes on wire (1248 bits), 156 bytes captured (1248 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65546, Ack: 140, Len: 80
[2 Reassembled TCP Segments (16392 bytes): #28(16312), #29(80)]
HyperText Transfer Protocol 2
    Stream: DATA, Stream ID: 1, Length 16383

At this point the client's receive window (65535) is totally consumed! So the client updates the windows after its flushed its data:

   31   2.028577 55082 8888 HTTP2 102 WINDOW_UPDATE, WINDOW_UPDATE          ::1 → ::1         
Frame 31: 102 bytes on wire (816 bits), 102 bytes captured (816 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 140, Ack: 65626, Len: 26
HyperText Transfer Protocol 2
    Stream: WINDOW_UPDATE, Stream ID: 0, Length 4
        Length: 4
        Type: WINDOW_UPDATE (8)
        Flags: 0x00
            0000 0000 = Unused: 0x00
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 1111 1111 1111 1111 = Window Size Increment: 65535
    Stream: WINDOW_UPDATE, Stream ID: 1, Length 4
        Length: 4
        Type: WINDOW_UPDATE (8)
        Flags: 0x00
            0000 0000 = Unused: 0x00
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 1111 1111 1111 1111 = Window Size Increment: 65535

The server the sends just one more byte of data, and then trailers, to complete the response:

   33   2.028713 8888 55082 HTTP2 86 DATA          ::1 → ::1         
Frame 33: 86 bytes on wire (688 bits), 86 bytes captured (688 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65626, Ack: 166, Len: 10
HyperText Transfer Protocol 2
    Stream: DATA, Stream ID: 1, Length 1

   35   2.028943 8888 55082 HTTP2 109 HEADERS          ::1 → ::1         
Frame 35: 109 bytes on wire (872 bits), 109 bytes captured (872 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65636, Ack: 166, Len: 33
HyperText Transfer Protocol 2
    Stream: HEADERS, Stream ID: 1, Length 24
        Length: 24
        Type: HEADERS (1)
        Flags: 0x05
            .... ...1 = End Stream: True
            .... .1.. = End Headers: True

But the client isn't happy about this at all, and it fails incorrectly with a flow control error:

Frame 37: 93 bytes on wire (744 bits), 93 bytes captured (744 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 166, Ack: 65669, Len: 17
HyperText Transfer Protocol 2
    Stream: GOAWAY, Stream ID: 0, Length 8
        Length: 8
        Type: GOAWAY (7)
        Flags: 0x00
            0000 0000 = Unused: 0x00
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0000 = Promised-Stream-ID: 0
        Error: FLOW_CONTROL_ERROR (3)

As the application fails, we see logging:

1504829194.779848 TRACE h2::proto::connection recv DATA; frame=Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None }
1504829194.779860 TRACE h2::proto::streams::recv recv_data; size=1; connection=65535; stream=0
1504829194.779870 DEBUG h2::proto::connection Connection::poll; err=FlowControlError

This was all collected with :; tshark -i lo0 -PO http2 -d 'tcp.port==8888,http2' -f 'tcp port 8888

    1   0.000000 55082 8888 TCP 88 55082 → 8888 [SYN, ECN, CWR] Seq=0 Win=65535 Len=0 MSS=16324 WS=32 TSval=1346047041 TSecr=0 SACK_PERM=1          ::1 → ::1         
Frame 1: 88 bytes on wire (704 bits), 88 bytes captured (704 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 0, Len: 0
2   0.000083 8888 55082 TCP 88 8888 → 55082 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=16324 WS=32 TSval=1346047041 TSecr=1346047041 SACK_PERM=1          ::1 → ::1         

Frame 2: 88 bytes on wire (704 bits), 88 bytes captured (704 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 0, Ack: 1, Len: 0

3   0.000096 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=1 Ack=1 Win=407776 Len=0 TSval=1346047041 TSecr=1346047041          ::1 → ::1         

Frame 3: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 1, Ack: 1, Len: 0

4   0.000111 8888 55082 TCP 76 [TCP Window Update] 8888 → 55082 [ACK] Seq=1 Ack=1 Win=407776 Len=0 TSval=1346047041 TSecr=1346047041          ::1 → ::1         

Frame 4: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 1, Ack: 1, Len: 0

5   0.000274 55082 8888 HTTP2 100 Magic          ::1 → ::1         

Frame 5: 100 bytes on wire (800 bits), 100 bytes captured (800 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 1, Ack: 1, Len: 24
HyperText Transfer Protocol 2
Stream: Magic
Magic: PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n

6   0.000295 8888 55082 TCP 76 8888 → 55082 [ACK] Seq=1 Ack=25 Win=407776 Len=0 TSval=1346047041 TSecr=1346047041          ::1 → ::1         

Frame 6: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 1, Ack: 25, Len: 0

7   0.000314 8888 55082 HTTP2 85 SETTINGS          ::1 → ::1         

Frame 7: 85 bytes on wire (680 bits), 85 bytes captured (680 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 1, Ack: 25, Len: 9
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 0
Length: 0
Type: SETTINGS (4)
Flags: 0x00
.... ...0 = ACK: False
0000 000. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0

8   0.000331 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=25 Ack=10 Win=407776 Len=0 TSval=1346047041 TSecr=1346047041          ::1 → ::1         

Frame 8: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 25, Ack: 10, Len: 0

9   0.000335 8888 55082 HTTP2 89 WINDOW_UPDATE          ::1 → ::1         

Frame 9: 89 bytes on wire (712 bits), 89 bytes captured (712 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 10, Ack: 25, Len: 13
HyperText Transfer Protocol 2
Stream: WINDOW_UPDATE, Stream ID: 0, Length 4
Length: 4
Type: WINDOW_UPDATE (8)
Flags: 0x00
0000 0000 = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 1110 1111 1111 1111 0001 = Window Size Increment: 983025

10 0.000343 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=25 Ack=23 Win=407776 Len=0 TSval=1346047041 TSecr=1346047041 ::1 → ::1
Frame 10: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 25, Ack: 23, Len: 0

11 0.000940 55082 8888 HTTP2 94 SETTINGS, SETTINGS ::1 → ::1
Frame 11: 94 bytes on wire (752 bits), 94 bytes captured (752 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 25, Ack: 23, Len: 18
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 0
Length: 0
Type: SETTINGS (4)
Flags: 0x00
.... ...0 = ACK: False
0000 000. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
Stream: SETTINGS, Stream ID: 0, Length 0
Length: 0
Type: SETTINGS (4)
Flags: 0x01
.... ...1 = ACK: True
0000 000. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0

12 0.000957 8888 55082 TCP 76 8888 → 55082 [ACK] Seq=23 Ack=43 Win=407744 Len=0 TSval=1346047042 TSecr=1346047042 ::1 → ::1
Frame 12: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 23, Ack: 43, Len: 0

13 0.001033 8888 55082 HTTP2 85 SETTINGS ::1 → ::1
Frame 13: 85 bytes on wire (680 bits), 85 bytes captured (680 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 23, Ack: 43, Len: 9
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 0
Length: 0
Type: SETTINGS (4)
Flags: 0x01
.... ...1 = ACK: True
0000 000. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0

14 0.001056 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=43 Ack=32 Win=407744 Len=0 TSval=1346047042 TSecr=1346047042 ::1 → ::1
Frame 14: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 43, Ack: 32, Len: 0

15 2.021388 55082 8888 HTTP2 173 HEADERS, DATA ::1 → ::1
Frame 15: 173 bytes on wire (1384 bits), 173 bytes captured (1384 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 43, Ack: 32, Len: 97
HyperText Transfer Protocol 2
Stream: HEADERS, Stream ID: 1, Length 70
Length: 70
Type: HEADERS (1)
Flags: 0x04
.... ...0 = End Stream: False
.... .1.. = End Headers: True
.... 0... = Padded: False
..0. .... = Priority: False
00.0 ..0. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Header Block Fragment: 8387418aa0e41d139d09b8ebaebb048f6109b0a84afb4a8a...
[Header Length: 194]
[Header Count: 7]
Header: :method: POST
Name Length: 7
Name: :method
Value Length: 4
Value: POST
Representation: Indexed Header Field
Index: 3
Header: :scheme: https
Name Length: 7
Name: :scheme
Value Length: 5
Value: https
Representation: Indexed Header Field
Index: 7
Header: :authority: localhost:7777
Name Length: 10
Name: :authority
Value Length: 14
Value: localhost:7777
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 1
Header: :path: /strest.Responder/Get
Name Length: 5
Name: :path
Value Length: 21
Value: /strest.Responder/Get
Representation: Literal Header Field without Indexing - Indexed Name
Index: 4
Header: content-type: application/grpc
Name Length: 12
Name: content-type
Value Length: 16
Value: application/grpc
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 31
Header: user-agent: grpc-go/1.4.0-dev
Name Length: 10
Name: user-agent
Value Length: 17
Value: grpc-go/1.4.0-dev
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 58
Header: te: trailers
Name Length: 2
Name: te
Value Length: 8
Value: trailers
Representation: Literal Header Field with Incremental Indexing - New Name
Padding:
Stream: DATA, Stream ID: 1, Length 9
Length: 9
Type: DATA (0)
Flags: 0x01
.... ...1 = End Stream: True
.... 0... = Padded: False
0000 .00. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Data: 000000000408edff03
Padding:

16 2.021431 8888 55082 TCP 76 8888 → 55082 [ACK] Seq=32 Ack=140 Win=407648 Len=0 TSval=1346049051 TSecr=1346049051 ::1 → ::1
Frame 16: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 32, Ack: 140, Len: 0

17 2.023249 8888 55082 HTTP2 99 HEADERS ::1 → ::1
Frame 17: 99 bytes on wire (792 bits), 99 bytes captured (792 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 32, Ack: 140, Len: 23
HyperText Transfer Protocol 2
Stream: HEADERS, Stream ID: 1, Length 14
Length: 14
Type: HEADERS (1)
Flags: 0x04
.... ...0 = End Stream: False
.... .1.. = End Headers: True
.... 0... = Padded: False
..0. .... = Priority: False
00.0 ..0. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Header Block Fragment: 885f8b1d75d0620d263d4c4d6564
[Header Length: 54]
[Header Count: 2]
Header: :status: 200
Name Length: 7
Name: :status
Value Length: 3
Value: 200
Representation: Indexed Header Field
Index: 8
Header: content-type: application/grpc
Name Length: 12
Name: content-type
Value Length: 16
Value: application/grpc
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 31
Padding:

18 2.023281 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=140 Ack=55 Win=407744 Len=0 TSval=1346049052 TSecr=1346049052 ::1 → ::1
Frame 18: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 140, Ack: 55, Len: 0

19 2.023332 8888 55082 TCP 16388 [TCP segment of a reassembled PDU] ::1 → ::1
Frame 19: 16388 bytes on wire (131104 bits), 16388 bytes captured (131104 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 55, Ack: 140, Len: 16312
HyperText Transfer Protocol 2

20 2.023338 8888 55082 HTTP2 157 DATA ::1 → ::1
Frame 20: 157 bytes on wire (1256 bits), 157 bytes captured (1256 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 16367, Ack: 140, Len: 81
[2 Reassembled TCP Segments (16393 bytes): #19(16312), #20(81)]
HyperText Transfer Protocol 2
Stream: DATA, Stream ID: 1, Length 16384
Length: 16384
Type: DATA (0)
Flags: 0x00
.... ...0 = End Stream: False
.... 0... = Padded: False
0000 .00. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Data: 000000fffb0aedff0378415767756a574276774676636943...
Padding:

21 2.023371 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=140 Ack=16448 Win=391328 Len=0 TSval=1346049052 TSecr=1346049052 ::1 → ::1
Frame 21: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 140, Ack: 16448, Len: 0

22 2.023405 8888 55082 TCP 16388 [TCP segment of a reassembled PDU] ::1 → ::1
Frame 22: 16388 bytes on wire (131104 bits), 16388 bytes captured (131104 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 16448, Ack: 140, Len: 16312
HyperText Transfer Protocol 2

23 2.023411 8888 55082 HTTP2 157 DATA ::1 → ::1
Frame 23: 157 bytes on wire (1256 bits), 157 bytes captured (1256 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 32760, Ack: 140, Len: 81
[2 Reassembled TCP Segments (16393 bytes): #22(16312), #23(81)]
HyperText Transfer Protocol 2
Stream: DATA, Stream ID: 1, Length 16384
Length: 16384
Type: DATA (0)
Flags: 0x00
.... ...0 = End Stream: False
.... 0... = Padded: False
0000 .00. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Data: 614553766d48726d49775258424a454874515656536f6149...
Padding:

24 2.023446 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=140 Ack=32841 Win=374944 Len=0 TSval=1346049052 TSecr=1346049052 ::1 → ::1
Frame 24: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 140, Ack: 32841, Len: 0

25 2.023449 8888 55082 TCP 16388 [TCP segment of a reassembled PDU] ::1 → ::1
Frame 25: 16388 bytes on wire (131104 bits), 16388 bytes captured (131104 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 32841, Ack: 140, Len: 16312
HyperText Transfer Protocol 2

26 2.023456 8888 55082 HTTP2 157 DATA ::1 → ::1
Frame 26: 157 bytes on wire (1256 bits), 157 bytes captured (1256 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 49153, Ack: 140, Len: 81
[2 Reassembled TCP Segments (16393 bytes): #25(16312), #26(81)]
HyperText Transfer Protocol 2
Stream: DATA, Stream ID: 1, Length 16384
Length: 16384
Type: DATA (0)
Flags: 0x00
.... ...0 = End Stream: False
.... 0... = Padded: False
0000 .00. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Data: 63737a534d644f48656647434d784d524f42685879594f71...
Padding:

27 2.023477 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=140 Ack=49234 Win=358560 Len=0 TSval=1346049052 TSecr=1346049052 ::1 → ::1
Frame 27: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 140, Ack: 49234, Len: 0

28 2.023486 8888 55082 TCP 16388 [TCP segment of a reassembled PDU] ::1 → ::1
Frame 28: 16388 bytes on wire (131104 bits), 16388 bytes captured (131104 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 49234, Ack: 140, Len: 16312
HyperText Transfer Protocol 2

29 2.023491 8888 55082 HTTP2 156 DATA ::1 → ::1
Frame 29: 156 bytes on wire (1248 bits), 156 bytes captured (1248 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65546, Ack: 140, Len: 80
[2 Reassembled TCP Segments (16392 bytes): #28(16312), #29(80)]
HyperText Transfer Protocol 2
Stream: DATA, Stream ID: 1, Length 16383
Length: 16383
Type: DATA (0)
Flags: 0x00
.... ...0 = End Stream: False
.... 0... = Padded: False
0000 .00. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Data: 4e6e465963446750796e7459796f71685964454171506542...
Padding:

30 2.023526 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=140 Ack=65626 Win=342144 Len=0 TSval=1346049052 TSecr=1346049052 ::1 → ::1
Frame 30: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 140, Ack: 65626, Len: 0

31 2.028577 55082 8888 HTTP2 102 WINDOW_UPDATE, WINDOW_UPDATE ::1 → ::1
Frame 31: 102 bytes on wire (816 bits), 102 bytes captured (816 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 140, Ack: 65626, Len: 26
HyperText Transfer Protocol 2
Stream: WINDOW_UPDATE, Stream ID: 0, Length 4
Length: 4
Type: WINDOW_UPDATE (8)
Flags: 0x00
0000 0000 = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 1111 1111 1111 1111 = Window Size Increment: 65535
Stream: WINDOW_UPDATE, Stream ID: 1, Length 4
Length: 4
Type: WINDOW_UPDATE (8)
Flags: 0x00
0000 0000 = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 1111 1111 1111 1111 = Window Size Increment: 65535

32 2.028616 8888 55082 TCP 76 8888 → 55082 [ACK] Seq=65626 Ack=166 Win=407616 Len=0 TSval=1346049057 TSecr=1346049056 ::1 → ::1
Frame 32: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65626, Ack: 166, Len: 0

33 2.028713 8888 55082 HTTP2 86 DATA ::1 → ::1
Frame 33: 86 bytes on wire (688 bits), 86 bytes captured (688 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65626, Ack: 166, Len: 10
HyperText Transfer Protocol 2
Stream: DATA, Stream ID: 1, Length 1
Length: 1
Type: DATA (0)
Flags: 0x00
.... ...0 = End Stream: False
.... 0... = Padded: False
0000 .00. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Data: 14
Padding:

34 2.028748 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=166 Ack=65636 Win=342144 Len=0 TSval=1346049057 TSecr=1346049057 ::1 → ::1
Frame 34: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 166, Ack: 65636, Len: 0

35 2.028943 8888 55082 HTTP2 109 HEADERS ::1 → ::1
Frame 35: 109 bytes on wire (872 bits), 109 bytes captured (872 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65636, Ack: 166, Len: 33
HyperText Transfer Protocol 2
Stream: HEADERS, Stream ID: 1, Length 24
Length: 24
Type: HEADERS (1)
Flags: 0x05
.... ...1 = End Stream: True
.... .1.. = End Headers: True
.... 0... = Padded: False
..0. .... = Priority: False
00.0 ..0. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Header Block Fragment: 40889acac8b21234da8f013040899acac8b5254207317f00
[Header Length: 40]
[Header Count: 2]
Header: grpc-status: 0
Name Length: 11
Name: grpc-status
Value Length: 1
Value: 0
Representation: Literal Header Field with Incremental Indexing - New Name
Header: grpc-message:
Name Length: 12
Name: grpc-message
Value Length: 0
Value:
Representation: Literal Header Field with Incremental Indexing - New Name
Padding:

36 2.028982 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=166 Ack=65669 Win=342112 Len=0 TSval=1346049057 TSecr=1346049057 ::1 → ::1
Frame 36: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 166, Ack: 65669, Len: 0

37 2.029726 55082 8888 HTTP2 93 GOAWAY ::1 → ::1
Frame 37: 93 bytes on wire (744 bits), 93 bytes captured (744 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 166, Ack: 65669, Len: 17
HyperText Transfer Protocol 2
Stream: GOAWAY, Stream ID: 0, Length 8
Length: 8
Type: GOAWAY (7)
Flags: 0x00
0000 0000 = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Promised-Stream-ID: 0
Error: FLOW_CONTROL_ERROR (3)

38 2.029759 8888 55082 TCP 76 8888 → 55082 [ACK] Seq=65669 Ack=183 Win=407616 Len=0 TSval=1346049058 TSecr=1346049058 ::1 → ::1
Frame 38: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65669, Ack: 183, Len: 0

39 2.032633 55082 8888 TCP 76 55082 → 8888 [FIN, ACK] Seq=183 Ack=65669 Win=342112 Len=0 TSval=1346049060 TSecr=1346049058 ::1 → ::1
Frame 39: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 183, Ack: 65669, Len: 0

40 2.032679 8888 55082 TCP 76 8888 → 55082 [ACK] Seq=65669 Ack=184 Win=407616 Len=0 TSval=1346049060 TSecr=1346049060 ::1 → ::1
Frame 40: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65669, Ack: 184, Len: 0

41 2.032740 8888 55082 TCP 76 8888 → 55082 [FIN, ACK] Seq=65669 Ack=184 Win=407616 Len=0 TSval=1346049060 TSecr=1346049060 ::1 → ::1
Frame 41: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 8888, Dst Port: 55082, Seq: 65669, Ack: 184, Len: 0

42 2.032783 55082 8888 TCP 76 55082 → 8888 [ACK] Seq=184 Ack=65670 Win=342112 Len=0 TSval=1346049060 TSecr=1346049060 ::1 → ::1
Frame 42: 76 bytes on wire (608 bits), 76 bytes captured (608 bits) on interface 0
Null/Loopback
Internet Protocol Version 6, Src: ::1, Dst: ::1
Transmission Control Protocol, Src Port: 55082, Dst Port: 8888, Seq: 184, Ack: 65670, Len: 0

Send aggregated window updates

I'm running some preliminary load testing on a proxy implemented with h2. It appears that there is a substantial performance impact caused by small window updates.

In this test, a client sends small multi-frame requests (HEADERS, DATA=5B) to a server that replies with small multi-frame responses (HEADERS, DATA=15B, HEADERS).

When the application communicates directly (on port 8888), it sends infrequent, large window updates:

:; (config=noproxy ; sudo tshark -i lo -a duration:60 -O http2 -q -V -d 'tcp.port==7777,http2' -d 'tcp.port==8888,http2' 2>/dev/null |tee ${config}.tshark | sed -nEe 's/.* = Window Size Increment: //p' |sort -n |uniq -c )                                                                
     19 262140

:; cat noproxy.tshark | sed -nEe 's/^.* Type: (\w+).*/\1/p' |sort |uniq -c|sort -rn                                              
 741369 HEADERS
 494246 DATA
     19 WINDOW_UPDATE

With an h2 proxy (on port 7777), we see that we are far too aggressive in sending window updates:

:; (config=proxy ; sudo tshark -i lo -a duration:60 -O http2 -q -V -d 'tcp.port==7777,http2' -d 'tcp.port==8888,http2' 2>/dev/null |tee ${config}.tshark | sed -nEe 's/.* = Window Size Increment: //p' |sort -n |uniq -c )                                                                  
   1349 5
   1371 15

:; cat proxy.tshark | sed -nEe 's/^.* Type: (\w+).*/\1/p' |sort |uniq -c|sort -rn
   6143 HEADERS
   4095 DATA
   2046 WINDOW_UPDATE

Other h2 implementations, like netty, support a configurable update ratio so that the receiver only sends window size increments greater than ratio * available window

Support configuration of max_concurrent_streams

server::Builder should support set_max_concurrent_streams(&mut self, u32) so that a server can constrain the number of streams per client.

Similarly, client::Builder should have this, though I think a client can only configure the number of concurrent server-initiated streams (i.e. Push Promises). While we're here, client::Builder should probalby also have a set_push_promise_enabled(&mut self, bool)

panic on closed stream

I'm able to transmit many small (~15B) payloads, but when using payloads that exceed the max frame size, the sender panics. This can be reproduced when writing a single response of size 16398B.

    Finished release [optimized] target(s) in 0.0 secs
starting gRPC server on :8888
1504792758.670191 TRACE tower_h2::client::new_service connecting to V6([::1]:8888)
1504792758.670497 TRACE tower_h2::client::new_service connected to TcpStream { sys: TcpStream { inner: TcpStream { addr: V6([::1]:49567), peer: V6([::1]:8888), fd: 7 } }, selector_id: SelectorId { id: AtomicUsize(1) } }; handshaking
1504792758.670537 DEBUG h2::client binding client connection
1504792758.670582 DEBUG h2::client client connection bound
1504792758.670646 DEBUG h2::codec::framed_write send; frame=Frame::Settings(Settings { flags: SettingsFlags(0), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None })
1504792758.670675 TRACE h2::frame::settings encoding SETTINGS; len=0
1504792758.670686 TRACE h2::codec::framed_write encoded settings; rem=9
1504792758.670697 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1504792758.670703 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1504792758.670710 TRACE h2::proto::streams::prioritize Prioritize::new; flow=FlowControl { window_size: 65535, available: 65535 }
1504792758.670796 TRACE h2::proto::settings send_pending_ack; pending=None
1504792758.670808 TRACE h2::codec::framed_read poll
1504792758.670852 TRACE h2::codec::framed_read poll; bytes=9B
1504792758.670857 TRACE h2::codec::framed_read decoding frame from 9B
1504792758.670862 TRACE h2::codec::framed_read     -> kind=Settings
1504792758.670870 TRACE h2::proto::connection recv SETTINGS; frame=Settings { flags: SettingsFlags(0), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None }
1504792758.670876 TRACE h2::proto::settings send_pending_ack; pending=Some(Settings { flags: SettingsFlags(0), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None })
1504792758.670882 DEBUG h2::codec::framed_write send; frame=Frame::Settings(Settings { flags: SettingsFlags(1), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None })
1504792758.670892 TRACE h2::frame::settings encoding SETTINGS; len=0
1504792758.670896 TRACE h2::codec::framed_write encoded settings; rem=18
1504792758.670899 TRACE h2::proto::settings ACK sent; applying settings
1504792758.670910 TRACE h2::codec::framed_read poll
1504792758.670914 TRACE h2::codec::framed_read poll; bytes=13B
1504792758.670917 TRACE h2::codec::framed_read decoding frame from 13B
1504792758.670921 TRACE h2::codec::framed_read     -> kind=WindowUpdate
1504792758.670926 TRACE h2::proto::connection recv WINDOW_UPDATE; frame=WindowUpdate { stream_id: StreamId(0), size_increment: 983025 }
1504792758.670932 TRACE h2::proto::streams::flow_control inc_window; sz=983025; old=65535; new=1048560
1504792758.670935 TRACE h2::proto::settings send_pending_ack; pending=None
1504792758.670938 TRACE h2::codec::framed_read poll
1504792758.670953 TRACE h2::proto::streams::prioritize try reclaim frame
1504792758.670956 TRACE h2::proto::streams::prioritize poll_complete
1504792758.670961 TRACE h2::proto::streams::prioritize pop_frame
1504792758.670967 TRACE h2::codec::framed_write flush
1504792758.670997 TRACE h2::codec::framed_write flushing buffer
1504792758.671001 TRACE h2::proto::streams::prioritize try reclaim frame
1504792758.671098 TRACE h2::proto::settings send_pending_ack; pending=None
1504792758.671106 TRACE h2::codec::framed_read poll
1504792758.671117 TRACE h2::codec::framed_read poll; bytes=9B
1504792758.671121 TRACE h2::codec::framed_read decoding frame from 9B
1504792758.671125 TRACE h2::codec::framed_read     -> kind=Settings
1504792758.671130 TRACE h2::proto::connection recv SETTINGS; frame=Settings { flags: SettingsFlags(1), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None }
1504792758.671137 DEBUG h2::proto::settings received remote settings ack
1504792758.671142 TRACE h2::proto::settings send_pending_ack; pending=None
1504792758.671154 TRACE h2::codec::framed_read poll
1504792758.671165 TRACE h2::proto::streams::prioritize try reclaim frame
1504792758.671170 TRACE h2::proto::streams::prioritize poll_complete
1504792758.671174 TRACE h2::proto::streams::prioritize pop_frame
1504792758.671178 TRACE h2::codec::framed_write flush
1504792758.671182 TRACE h2::codec::framed_write flushing buffer
1504792758.671185 TRACE h2::proto::streams::prioritize try reclaim frame
1504792759.691449 DEBUG h2::codec::framed_write send; frame=Frame::Settings(Settings { flags: SettingsFlags(0), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None })
1504792759.691465 TRACE h2::frame::settings encoding SETTINGS; len=0
1504792759.691484 TRACE h2::codec::framed_write encoded settings; rem=9
1504792759.691530 TRACE h2::codec::framed_write flush
1504792759.691549 TRACE h2::codec::framed_write flushing buffer
1504792759.691639 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1504792759.691647 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1504792759.691651 TRACE h2::proto::streams::prioritize Prioritize::new; flow=FlowControl { window_size: 65535, available: 65535 }
1504792759.691679 TRACE h2::proto::settings send_pending_ack; pending=None
1504792759.691685 TRACE h2::codec::framed_read poll
1504792759.691709 TRACE h2::codec::framed_read poll; bytes=9B
1504792759.691714 TRACE h2::codec::framed_read decoding frame from 9B
1504792759.691718 TRACE h2::codec::framed_read     -> kind=Settings
1504792759.691725 TRACE h2::proto::connection recv SETTINGS; frame=Settings { flags: SettingsFlags(0), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None }
1504792759.691739 TRACE h2::proto::settings send_pending_ack; pending=Some(Settings { flags: SettingsFlags(0), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None })
1504792759.691746 DEBUG h2::codec::framed_write send; frame=Frame::Settings(Settings { flags: SettingsFlags(1), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None })
1504792759.691755 TRACE h2::frame::settings encoding SETTINGS; len=0
1504792759.691759 TRACE h2::codec::framed_write encoded settings; rem=9
1504792759.691763 TRACE h2::proto::settings ACK sent; applying settings
1504792759.691775 TRACE h2::codec::framed_read poll
1504792759.691780 TRACE h2::codec::framed_read poll; bytes=13B
1504792759.691784 TRACE h2::codec::framed_read decoding frame from 13B
1504792759.691788 TRACE h2::codec::framed_read     -> kind=WindowUpdate
1504792759.691801 TRACE h2::proto::connection recv WINDOW_UPDATE; frame=WindowUpdate { stream_id: StreamId(0), size_increment: 983025 }
1504792759.691810 TRACE h2::proto::streams::flow_control inc_window; sz=983025; old=65535; new=1048560
1504792759.691813 TRACE h2::proto::settings send_pending_ack; pending=None
1504792759.691817 TRACE h2::codec::framed_read poll
1504792759.691831 TRACE h2::codec::framed_read poll; bytes=9B
1504792759.691835 TRACE h2::codec::framed_read decoding frame from 9B
1504792759.691837 TRACE h2::codec::framed_read     -> kind=Settings
1504792759.691840 TRACE h2::proto::connection recv SETTINGS; frame=Settings { flags: SettingsFlags(1), header_table_size: None, enable_push: None, max_concurrent_streams: None, initial_window_size: None, max_frame_size: None, max_header_list_size: None }
1504792759.691844 DEBUG h2::proto::settings received remote settings ack
1504792759.691847 TRACE h2::proto::settings send_pending_ack; pending=None
1504792759.691850 TRACE h2::codec::framed_read poll
1504792759.691857 TRACE h2::proto::streams::prioritize try reclaim frame
1504792759.691860 TRACE h2::proto::streams::prioritize poll_complete
1504792759.691865 TRACE h2::proto::streams::prioritize pop_frame
1504792759.691868 TRACE h2::codec::framed_write flush
1504792759.691882 TRACE h2::codec::framed_write flushing buffer
1504792759.691885 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.686162 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.686184 TRACE h2::codec::framed_read poll
1504792760.686220 TRACE h2::codec::framed_read poll; bytes=79B
1504792760.686241 TRACE h2::codec::framed_read decoding frame from 79B
1504792760.686249 TRACE h2::codec::framed_read     -> kind=Headers
1504792760.686256 TRACE h2::frame::headers loading headers; flags=HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false }
1504792760.686274 TRACE h2::hpack::decoder decode
1504792760.686284 TRACE h2::hpack::decoder     Indexed; rem=70
1504792760.686303 TRACE h2::hpack::decoder     Indexed; rem=69
1504792760.686309 TRACE h2::hpack::decoder     LiteralWithIndexing; rem=68
1504792760.686340 TRACE h2::hpack::decoder     LiteralWithIndexing; rem=51
1504792760.686349 TRACE h2::hpack::decoder     LiteralWithIndexing; rem=39
1504792760.686369 TRACE h2::hpack::decoder     LiteralWithIndexing; rem=26
1504792760.686379 TRACE h2::hpack::decoder     LiteralWithIndexing; rem=11
1504792760.686391 TRACE h2::proto::connection recv HEADERS; frame=Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } }
1504792760.686412 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1504792760.686419 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1504792760.686429 TRACE h2::proto::streams::recv opening stream; init_window=65535
1504792760.686476 TRACE h2::proto::streams::store Queue::push
1504792760.686483 TRACE h2::proto::streams::store  -> first entry
1504792760.686492 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.686497 TRACE h2::codec::framed_read poll
1504792760.686503 TRACE h2::codec::framed_read poll; bytes=17B
1504792760.686508 TRACE h2::codec::framed_read decoding frame from 17B
1504792760.686513 TRACE h2::codec::framed_read     -> kind=Data
1504792760.686519 TRACE h2::proto::connection recv DATA; frame=Data { stream_id: StreamId(1), flags: DataFlags { end_stream: true }, pad_len: None }
1504792760.686531 TRACE h2::proto::streams::recv recv_data; size=8; connection=65535; stream=65535
1504792760.686539 TRACE h2::proto::streams::flow_control send_data; sz=8; window=65535; available=65535
1504792760.686554 TRACE h2::proto::streams::flow_control send_data; sz=8; window=65535; available=65535
1504792760.686561 TRACE h2::proto::streams::state recv_close: Open => HalfClosedRemote(AwaitingHeaders)
1504792760.686576 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.686582 TRACE h2::codec::framed_read poll
1504792760.686603 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.686610 TRACE h2::proto::streams::prioritize poll_complete
1504792760.686614 TRACE h2::proto::streams::prioritize pop_frame
1504792760.686620 TRACE h2::codec::framed_write flush
1504792760.686624 TRACE h2::codec::framed_write flushing buffer
1504792760.686629 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.686635 TRACE h2::server received incoming
1504792760.686647 TRACE tower_h2::client::service request: POST https://localhost:7777/strest.Responder/Get
1504792760.686660 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.686667 TRACE h2::codec::framed_read poll
1504792760.686677 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.686683 TRACE h2::proto::streams::prioritize poll_complete
1504792760.686688 TRACE h2::proto::streams::prioritize pop_frame
1504792760.686692 TRACE h2::codec::framed_write flush
1504792760.686699 TRACE h2::codec::framed_write flushing buffer
1504792760.686705 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.686727 TRACE tower_h2::server ~> poll response
1504792760.686736 TRACE tower_h2::client::service GetResponse::poll
1504792760.686741 TRACE tower_h2::client::service send
1504792760.686769 TRACE tower_h2::client::service sending request: Parts { method: POST, uri: https://localhost:7777/strest.Responder/Get, version: HTTP/2.0, headers: {"content-type": "application/grpc", "user-agent": "grpc-go/1.4.0-dev", "te": "trailers"} } empty=false
1504792760.686799 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1504792760.686806 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1504792760.686825 TRACE h2::proto::streams::send send_headers; frame=Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } }; init_window=65535
1504792760.686838 TRACE h2::proto::streams::store Queue::push
1504792760.686843 TRACE h2::proto::streams::store  -> first entry
1504792760.686851 TRACE tower_h2::client::service ~> recv
1504792760.686860 TRACE tower_h2::client::service response not ready
1504792760.686869 TRACE tower_h2::client::service sender: poll
1504792760.686876 TRACE tower_h2::recv_body poll_data
1504792760.686885 TRACE tower_h2::recv_body poll_data
1504792760.686890 TRACE tower_h2::client::service sender: poll_trailers
1504792760.686896 TRACE tower_h2::recv_body poll_trailers
1504792760.686904 TRACE tower_h2::client::service poll: send_data eos
1504792760.686913 TRACE h2::proto::streams::prioritize send_data; sz=8; buffered=8; requested=0
1504792760.686923 TRACE h2::proto::streams::prioritize try_assign_capacity; requested=8; additional=8; window=65535; conn=1048560
1504792760.686929 TRACE h2::proto::streams::prioritize try_assign_capacity; available=8; requested=8; buffered=8; has_unavailable=true
1504792760.686936 TRACE h2::proto::streams::store Queue::push
1504792760.686941 TRACE h2::proto::streams::store  -> already queued
1504792760.686962 TRACE h2::proto::streams::state send_close: Open => HalfClosedLocal(AwaitingHeaders)
1504792760.686977 TRACE h2::proto::streams::prioritize send_data (2); available=8; buffered=8
1504792760.686985 TRACE h2::proto::streams::store Queue::push
1504792760.687002 TRACE h2::proto::streams::store  -> already queued
1504792760.687025 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.687033 TRACE h2::codec::framed_read poll
1504792760.687044 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.687050 TRACE h2::proto::streams::prioritize poll_complete
1504792760.687055 TRACE h2::proto::streams::prioritize pop_frame
1504792760.687060 TRACE h2::proto::streams::prioritize pop_frame; stream=StreamId(1)
1504792760.687068 TRACE h2::proto::streams::prioritize pop_frame; frame=Frame::Headers(Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } })
1504792760.687078 TRACE h2::proto::streams::store Queue::push
1504792760.687082 TRACE h2::proto::streams::store  -> first entry
1504792760.687087 TRACE h2::proto::streams::prioritize writing frame=Frame::Headers(Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } })
1504792760.687096 DEBUG h2::codec::framed_write send; frame=Frame::Headers(Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } })
1504792760.687134 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.687140 TRACE h2::proto::streams::prioritize pop_frame
1504792760.687144 TRACE h2::proto::streams::prioritize pop_frame; stream=StreamId(1)
1504792760.687150 TRACE h2::proto::streams::prioritize  --> data frame; stream=StreamId(1); sz=8; eos=true; window=8; available=8; requested=8
1504792760.687155 TRACE h2::proto::streams::prioritize  -- updating stream flow --
1504792760.687160 TRACE h2::proto::streams::flow_control send_data; sz=8; window=65535; available=8
1504792760.687165 TRACE h2::proto::streams::prioritize  -- updating connection flow --
1504792760.687169 TRACE h2::proto::streams::flow_control send_data; sz=8; window=1048560; available=1048560
1504792760.687174 TRACE h2::proto::streams::prioritize pop_frame; frame=Frame::Data(Data { stream_id: StreamId(1), flags: DataFlags { end_stream: true }, pad_len: None })
1504792760.687182 TRACE h2::proto::streams::prioritize writing frame=Frame::Data(Data { stream_id: StreamId(1), flags: DataFlags { end_stream: true }, pad_len: None })
1504792760.687191 DEBUG h2::codec::framed_write send; frame=Frame::Data(Data { stream_id: StreamId(1), flags: DataFlags { end_stream: true }, pad_len: None })
1504792760.687211 TRACE h2::proto::streams::store Queue::push
1504792760.687223 TRACE h2::proto::streams::store  -> first entry
1504792760.687230 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.687236 TRACE h2::proto::streams::prioritize   -> reclaimed; frame=Data { stream_id: StreamId(1), flags: DataFlags { end_stream: true }, pad_len: None }; sz=0
1504792760.687250 TRACE h2::proto::streams::prioritize pop_frame
1504792760.687280 TRACE h2::codec::framed_write flush
1504792760.687330 TRACE h2::codec::framed_write flushing buffer
1504792760.687339 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.687356 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.687364 TRACE h2::codec::framed_read poll
1504792760.687381 DEBUG h2::codec::framed_write send; frame=Frame::WindowUpdate(WindowUpdate { stream_id: StreamId(0), size_increment: 8 })
1504792760.687395 TRACE h2::frame::window_update encoding WINDOW_UPDATE; id=StreamId(0)
1504792760.687404 TRACE h2::codec::framed_write encoded window_update; rem=13
1504792760.687423 TRACE h2::proto::streams::flow_control inc_window; sz=8; old=65527; new=65535
1504792760.687432 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.687477 TRACE h2::proto::streams::prioritize poll_complete
1504792760.687494 TRACE h2::proto::streams::prioritize pop_frame
1504792760.687503 TRACE h2::codec::framed_write flush
1504792760.687549 TRACE h2::codec::framed_write flushing buffer
1504792760.687558 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.688528 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.688548 TRACE h2::codec::framed_read poll
1504792760.688592 TRACE h2::codec::framed_read poll; bytes=23B
1504792760.688603 TRACE h2::codec::framed_read decoding frame from 23B
1504792760.688612 TRACE h2::codec::framed_read     -> kind=Headers
1504792760.688621 TRACE h2::frame::headers loading headers; flags=HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false }
1504792760.688635 TRACE h2::hpack::decoder decode
1504792760.688642 TRACE h2::hpack::decoder     Indexed; rem=14
1504792760.688653 TRACE h2::hpack::decoder     LiteralWithIndexing; rem=13
1504792760.688674 TRACE h2::proto::connection recv HEADERS; frame=Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } }
1504792760.688701 TRACE h2::proto::streams::recv opening stream; init_window=65535
1504792760.688719 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.688728 TRACE h2::codec::framed_read poll
1504792760.688816 TRACE h2::codec::framed_read poll; bytes=16393B
1504792760.688826 TRACE h2::codec::framed_read decoding frame from 16393B
1504792760.688831 TRACE h2::codec::framed_read     -> kind=Data
1504792760.688837 TRACE h2::proto::connection recv DATA; frame=Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None }
1504792760.688845 TRACE h2::proto::streams::recv recv_data; size=16384; connection=65535; stream=65535
1504792760.688850 TRACE h2::proto::streams::flow_control send_data; sz=16384; window=65535; available=65535
1504792760.688855 TRACE h2::proto::streams::flow_control send_data; sz=16384; window=65535; available=65535
1504792760.688861 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.688875 TRACE h2::codec::framed_read poll
1504792760.688881 TRACE h2::codec::framed_read poll; bytes=26B
1504792760.688886 TRACE h2::codec::framed_read decoding frame from 26B
1504792760.688891 TRACE h2::codec::framed_read     -> kind=Data
1504792760.688898 TRACE h2::proto::connection recv DATA; frame=Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None }
1504792760.688907 TRACE h2::proto::streams::recv recv_data; size=17; connection=49151; stream=49151
1504792760.688913 TRACE h2::proto::streams::flow_control send_data; sz=17; window=49151; available=49151
1504792760.688919 TRACE h2::proto::streams::flow_control send_data; sz=17; window=49151; available=49151
1504792760.688926 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.688932 TRACE h2::codec::framed_read poll
1504792760.688938 TRACE h2::codec::framed_read poll; bytes=33B
1504792760.688959 TRACE h2::codec::framed_read decoding frame from 33B
1504792760.688973 TRACE h2::codec::framed_read     -> kind=Headers
1504792760.688980 TRACE h2::frame::headers loading headers; flags=HeadersFlag { end_stream: true, end_headers: true, padded: false, priority: false }
1504792760.689000 TRACE h2::hpack::decoder decode
1504792760.689006 TRACE h2::hpack::decoder     LiteralWithIndexing; rem=24
1504792760.689030 TRACE h2::hpack::decoder     LiteralWithIndexing; rem=12
1504792760.689039 TRACE h2::proto::connection recv HEADERS; frame=Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: true, end_headers: true, padded: false, priority: false } }
1504792760.689048 TRACE h2::proto::streams::state recv_close: HalfClosedLocal => Closed
1504792760.689055 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.689060 TRACE h2::codec::framed_read poll
1504792760.689076 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.689084 TRACE h2::proto::streams::prioritize poll_complete
1504792760.689088 TRACE h2::proto::streams::prioritize pop_frame
1504792760.689093 TRACE h2::codec::framed_write flush
1504792760.689101 TRACE h2::codec::framed_write flushing buffer
1504792760.689108 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.689120 TRACE tower_h2::server ~> poll response
1504792760.689126 TRACE tower_h2::client::service GetResponse::poll
1504792760.689131 TRACE tower_h2::client::service ~> recv
1504792760.689137 TRACE tower_h2::client::service ~> response: Parts { status: 200, version: HTTP/1.1, headers: {"content-type": "application/grpc"} }
1504792760.689155 TRACE tower_h2::server ~> response: Parts { status: 200, version: HTTP/1.1, headers: {"content-type": "application/grpc"} }
1504792760.689169 TRACE h2::proto::streams::send send_headers; frame=Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } }; init_window=65535
1504792760.689178 TRACE h2::proto::streams::store Queue::push
1504792760.689184 TRACE h2::proto::streams::store  -> first entry
1504792760.689207 TRACE tower_h2::server sending response body
1504792760.689231 TRACE tower_h2::recv_body poll_data
1504792760.689238 TRACE tower_h2::recv_body poll_send
1504792760.689243 TRACE tower_h2::client::service sender: poll
1504792760.689249 TRACE tower_h2::server poll: send_data
1504792760.689255 TRACE h2::proto::streams::prioritize send_data; sz=16384; buffered=16384; requested=0
1504792760.689260 TRACE h2::proto::streams::prioritize try_assign_capacity; requested=16384; additional=16384; window=65535; conn=1048560
1504792760.689266 TRACE h2::proto::streams::prioritize try_assign_capacity; available=16384; requested=16384; buffered=16384; has_unavailable=true
1504792760.689271 TRACE h2::proto::streams::store Queue::push
1504792760.689276 TRACE h2::proto::streams::store  -> already queued
1504792760.689280 TRACE h2::proto::streams::prioritize send_data (2); available=16384; buffered=16384
1504792760.689296 TRACE h2::proto::streams::store Queue::push
1504792760.689303 TRACE h2::proto::streams::store  -> already queued
1504792760.689309 TRACE tower_h2::recv_body poll_data
1504792760.689314 TRACE tower_h2::server poll: send_data
1504792760.689319 TRACE h2::proto::streams::prioritize send_data; sz=17; buffered=16401; requested=16384
1504792760.689324 TRACE h2::proto::streams::prioritize try_assign_capacity; requested=16401; additional=17; window=65535; conn=1032176
1504792760.689329 TRACE h2::proto::streams::prioritize try_assign_capacity; available=16401; requested=16401; buffered=16401; has_unavailable=true
1504792760.689334 TRACE h2::proto::streams::store Queue::push
1504792760.689338 TRACE h2::proto::streams::store  -> already queued
1504792760.689343 TRACE h2::proto::streams::prioritize send_data (2); available=16401; buffered=16401
1504792760.689348 TRACE h2::proto::streams::store Queue::push
1504792760.689352 TRACE h2::proto::streams::store  -> already queued
1504792760.689356 TRACE tower_h2::recv_body poll_data
1504792760.689362 TRACE tower_h2::server poll: poll_trailers
1504792760.689368 TRACE tower_h2::recv_body poll_trailers
1504792760.689376 TRACE tower_h2::server poll: send_trailers
1504792760.689381 TRACE h2::proto::streams::state send_close: HalfClosedRemote => Closed
1504792760.689386 TRACE h2::proto::streams::send send_trailers -- queuing; frame=Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: true, end_headers: true, padded: false, priority: false } }
1504792760.689397 TRACE h2::proto::streams::store Queue::push
1504792760.689402 TRACE h2::proto::streams::store  -> already queued
1504792760.689407 TRACE tower_h2::recv_body poll_close
1504792760.689430 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.689436 TRACE h2::codec::framed_read poll
1504792760.689449 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.689454 TRACE h2::proto::streams::prioritize poll_complete
1504792760.689458 TRACE h2::proto::streams::prioritize pop_frame
1504792760.689463 TRACE h2::proto::streams::prioritize pop_frame; stream=StreamId(1)
1504792760.689469 TRACE h2::proto::streams::prioritize pop_frame; frame=Frame::Headers(Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } })
1504792760.689476 TRACE h2::proto::streams::store Queue::push
1504792760.689480 TRACE h2::proto::streams::store  -> first entry
1504792760.689494 TRACE h2::proto::streams::prioritize writing frame=Frame::Headers(Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } })
1504792760.689502 DEBUG h2::codec::framed_write send; frame=Frame::Headers(Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: false, end_headers: true, padded: false, priority: false } })
1504792760.689516 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.689522 TRACE h2::proto::streams::prioritize pop_frame
1504792760.689527 TRACE h2::proto::streams::prioritize pop_frame; stream=StreamId(1)
1504792760.689532 TRACE h2::proto::streams::prioritize  --> data frame; stream=StreamId(1); sz=16384; eos=false; window=16401; available=16401; requested=16401
1504792760.689540 TRACE h2::proto::streams::prioritize  -- updating stream flow --
1504792760.689560 TRACE h2::proto::streams::flow_control send_data; sz=16384; window=65535; available=16401
1504792760.689586 TRACE h2::proto::streams::prioritize  -- updating connection flow --
1504792760.689591 TRACE h2::proto::streams::flow_control send_data; sz=16384; window=1048560; available=1048543
1504792760.689604 TRACE h2::proto::streams::prioritize pop_frame; frame=Frame::Data(Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None })
1504792760.689613 TRACE h2::proto::streams::store Queue::push
1504792760.689620 TRACE h2::proto::streams::store  -> first entry
1504792760.689624 TRACE h2::proto::streams::prioritize writing frame=Frame::Data(Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None })
1504792760.689632 DEBUG h2::codec::framed_write send; frame=Frame::Data(Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None })
1504792760.689648 TRACE h2::codec::framed_write flush
1504792760.689815 TRACE h2::proto::streams::store Queue::push
1504792760.689836 TRACE h2::proto::streams::store  -> first entry
1504792760.689846 TRACE h2::codec::framed_write flushing buffer
1504792760.689854 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.689862 TRACE h2::proto::streams::prioritize   -> reclaimed; frame=Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None }; sz=0
1504792760.689895 TRACE h2::proto::streams::prioritize pop_frame
1504792760.689905 TRACE h2::proto::streams::prioritize pop_frame; stream=StreamId(1)
1504792760.689914 TRACE h2::proto::streams::prioritize  --> data frame; stream=StreamId(1); sz=17; eos=false; window=17; available=17; requested=16401
1504792760.689928 TRACE h2::proto::streams::prioritize  -- updating stream flow --
1504792760.689934 TRACE h2::proto::streams::flow_control send_data; sz=17; window=49151; available=17
1504792760.689941 TRACE h2::proto::streams::prioritize  -- updating connection flow --
1504792760.689947 TRACE h2::proto::streams::flow_control send_data; sz=17; window=1032176; available=1032176
1504792760.689956 TRACE h2::proto::streams::prioritize pop_frame; frame=Frame::Data(Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None })
1504792760.689965 TRACE h2::proto::streams::store Queue::push
1504792760.689971 TRACE h2::proto::streams::store  -> first entry
1504792760.689978 TRACE h2::proto::streams::prioritize writing frame=Frame::Data(Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None })
1504792760.689986 DEBUG h2::codec::framed_write send; frame=Frame::Data(Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None })
1504792760.689995 TRACE h2::proto::streams::store Queue::push
1504792760.690000 TRACE h2::proto::streams::store  -> already queued
1504792760.690007 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.690015 TRACE h2::proto::streams::prioritize   -> reclaimed; frame=Data { stream_id: StreamId(1), flags: DataFlags, pad_len: None }; sz=0
1504792760.690023 TRACE h2::proto::streams::prioritize pop_frame
1504792760.690030 TRACE h2::proto::streams::prioritize pop_frame; stream=StreamId(1)
1504792760.690038 TRACE h2::proto::streams::prioritize pop_frame; frame=Frame::Headers(Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: true, end_headers: true, padded: false, priority: false } })
1504792760.690050 TRACE h2::proto::streams::prioritize writing frame=Frame::Headers(Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: true, end_headers: true, padded: false, priority: false } })
1504792760.690061 DEBUG h2::codec::framed_write send; frame=Frame::Headers(Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: true, end_headers: true, padded: false, priority: false } })
1504792760.690078 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.690091 TRACE h2::proto::streams::prioritize pop_frame
1504792760.690098 TRACE h2::codec::framed_write flush
1504792760.690127 TRACE h2::codec::framed_write flushing buffer
1504792760.690137 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.690158 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.690168 TRACE h2::codec::framed_read poll
1504792760.690180 DEBUG h2::codec::framed_write send; frame=Frame::WindowUpdate(WindowUpdate { stream_id: StreamId(0), size_increment: 16401 })
1504792760.690191 TRACE h2::frame::window_update encoding WINDOW_UPDATE; id=StreamId(0)
1504792760.690207 TRACE h2::codec::framed_write encoded window_update; rem=13
1504792760.690216 TRACE h2::proto::streams::flow_control inc_window; sz=16401; old=49134; new=65535
1504792760.690226 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.690233 TRACE h2::proto::streams::prioritize poll_complete
1504792760.690240 TRACE h2::proto::streams::prioritize pop_frame
1504792760.690247 TRACE h2::codec::framed_write flush
1504792760.690273 TRACE h2::codec::framed_write flushing buffer
1504792760.690282 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.690301 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.690311 TRACE h2::codec::framed_read poll
1504792760.690339 TRACE h2::codec::framed_read poll; bytes=13B
1504792760.690348 TRACE h2::codec::framed_read decoding frame from 13B
1504792760.690355 TRACE h2::codec::framed_read     -> kind=WindowUpdate
1504792760.690363 TRACE h2::proto::connection recv WINDOW_UPDATE; frame=WindowUpdate { stream_id: StreamId(1), size_increment: 16384 }
1504792760.690380 TRACE h2::proto::streams::prioritize recv_stream_window_update; stream=StreamId(1); state=State { inner: Closed(None) }; inc=16384; flow=FlowControl { window_size: 49134, available: 0 }
1504792760.690398 TRACE h2::proto::streams::flow_control inc_window; sz=16384; old=49134; new=65518
1504792760.690407 TRACE h2::proto::streams::prioritize try_assign_capacity; requested=16401; additional=16401; window=65518; conn=1032159
1504792760.690417 TRACE h2::proto::streams::prioritize try_assign_capacity; available=16401; requested=16401; buffered=16401; has_unavailable=true
1504792760.690431 TRACE h2::proto::streams::store Queue::push
1504792760.690437 TRACE h2::proto::streams::store  -> first entry
1504792760.690444 TRACE h2::proto::settings send_pending_ack; pending=None
1504792760.690452 TRACE h2::codec::framed_read poll
1504792760.690468 TRACE h2::proto::streams::prioritize try reclaim frame
1504792760.690476 TRACE h2::proto::streams::prioritize poll_complete
1504792760.690491 TRACE h2::proto::streams::prioritize pop_frame
1504792760.690496 TRACE h2::proto::streams::prioritize pop_frame; stream=StreamId(1)
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:335:20
2017-09-07T13:59:29Z  16.0KB      1/0 10s L:   0 [4947 4947 ] 4944 J:   0   0
stack backtrace:
   0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
   1: std::panicking::default_hook::{{closure{
  "good": 1,
  "bad": 0,
  "bytes": 16383,
  "latency": {
    "50": 4947,
    "95": 4947,
    "99": 4947,
    "999": 4947
  },
  "jitter": {
    "50": 0,
    "95": 0,
    "99": 0,
    "999": 0
  }
}
}}
   2: std::panicking::default_hook
   3: std::panicking::rust_panic_with_hook
   4: std::panicking::begin_panic
   5: std::panicking::begin_panic_fmt
   6: rust_begin_unwind
   7: core::panicking::panic_fmt
   8: core::panicking::panic
   9: >::pop_frame
  10: >::poll
  11:  as futures::stream::Stream>::poll
  12:  as futures::future::Future>::poll
  13:  as futures::future::Future>::poll
  14:  as futures::future::Future>::poll
  15: ::poll
  16: ::poll
  17: tokio_core::reactor::Core::poll
  18: buoxy::main
  19: __rust_maybe_catch_panic
  20: std::rt::lang_start
./strest.sh: line 92: 89711 Terminated: 15          ./strest-grpc-server -address :8888

Beware: Idle states

I noticed the following:

The first use of a new stream identifier implicitly closes all streams in the "idle" state that might have been initiated by that peer with a lower-valued stream identifier. For example, if a client sends a HEADERS frame on stream 7 without ever sending a frame on stream 5, then stream 5 transitions to the "closed" state when the first frame for stream 7 is sent or received.

We need to be careful that we don't initialize streams in the idle state such that they may be moved into reserved/open out of order. We should probably only ever initialize streams directly to a Reserved or Open (or HalfOpenRemote) state.

Receiving a SETTINGS frame that reduces window size causes queued streams to panic

This test panics. This may be resolved by #79

#[test]
fn something_funky() {
    let _ = ::env_logger::init();
    let (io, srv) = mock::new();

    let h2 = Client::handshake(io).unwrap()
        .and_then(|mut h2| {
            let request = Request::builder()
                .method(Method::POST)
                .uri("https://http2.akamai.com/")
                .body(()).unwrap();

            let mut stream = h2.request(request, false).unwrap();

            stream.reserve_capacity(11);

            h2.drive(util::wait_for_capacity(stream, 11))
        })
        .and_then(|(h2, mut stream)| {
            assert_eq!(stream.capacity(), 11);

            stream.send_data("hello world".into(), true).unwrap();

            h2.drive(GetResponse { stream: Some(stream) })
        })
        .and_then(|(h2, (response, _))| {
            assert_eq!(response.status(), StatusCode::NO_CONTENT);

            // Wait for the connection to close
            h2.unwrap()
        })
        ;

    let mut settings = frame::Settings::default();
    settings.set_initial_window_size(0);

    let srv = srv.assert_client_handshake_with_settings(settings).unwrap()
        .recv_settings()
        .recv_frame(
            frames::headers(1)
                .request("POST", "https://http2.akamai.com/")
        )
        .idle_ms(100)
        .send_frame(
            frames::window_update(0, 11))
        .send_frame(
            frames::window_update(1, 11))
        .recv_frame(
            frames::data(1, "hello world").eos())
        .send_frame(
            frames::headers(1)
                .response(204)
                .eos()
        )
        /*
        .recv_frame(frames::data(1, "hello").eos())
        .send_frame(frames::window_update(1, 5))
        */
        .map(drop)
        ;

    let _ = h2.join(srv)
        .wait().unwrap();
}

Handle malformed messages with continuation frames

When a HEADERS frame is received that is malformed, the stream is reset. However, any continuation frame that is received after that must still be have HPACK decoding performed in order to maintain the hpack state.

panic on invalid :authority

When the value of :authority is invalid, we get the following panic:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: InvalidUriBytes(InvalidUri(InvalidUriChar))', src/libcore/result.rs:906:4

   9: core::result::unwrap_failed
  10: <h2::server::Peer as h2::proto::peer::Peer>::convert_poll_message
  11: <h2::proto::connection::Connection<T, P, B>>::poll2
  12: <h2::server::Server<T, B> as futures::stream::Stream>::poll

This should probably be a User error and not a panic.

Fix mod / type visibility

I started the code making everything public. This was just to get things to compile and because I wasn't sure what the public API would be yet.

We probably should fix this before going too much further as it might require some refactoring.

Roughly, the visibility should be:

Public

  • client mod
  • server mod
  • error mod

Private

  • hpack mod
  • frame mod
  • proto mod

client must not exceed max concurrent streams

Wrote a naive client like:

    let done = h2.new_service()
        .map_err(|e| e.into())
        .and_then(move |h2| {
            reactor.spawn(h2.clone().map_err(|e| println!("error: {:#?}", e)));

            let futs = (0..500).map(move |n| {
                let pfx = format!("{}", n);
                h2.call(mkreq()).and_then(move |rsp| handle(pfx, rsp))
            });

            future::join_all(futs)
        })
        .map(|_| println!("done"))
        .map_err(|e| println!("error: {:?}", e));

This causes the server to fail with

  2.033] [INVALID; error=Protocol error] recv HEADERS frame <length=4, flags=0x05, stream_id=585>
          ; END_STREAM | END_HEADERS
          (padlen=0)
          ; Open new stream
[id=1] [  2.033] send GOAWAY frame <length=56, flags=0x00, stream_id=0>
          (last_stream_id=199, error_code=PROTOCOL_ERROR(0x01), opaque_data(48)=[request HEADERS: max concurrent streams exceeded])

Additionally, go aways do not appear to trigger errors for pending requests.

Provide a way to shutdown a connection on quiescence

Both the server and the client need a way to initiate a clean shutdown. The process should be:

  • Stop accepting new streams
  • Wait until all existing streams are complete
  • Send a GO_AWAY frame
  • Close the connection.

API polish

  • Client::request should be renamed Client::send_request
  • send_trailers and send_reset should take self
  • Client is missing send_reset
  • Dropping the read body should reset the stream.

handle stream id overflow

RFC7540§5.1.1 Stream Identifiers says:

Stream identifiers cannot be reused. Long-lived connections can result in an endpoint exhausting the available range of stream identifiers. A client that is unable to establish a new stream identifier can establish a new connection for new streams. A server that is unable to establish a new stream identifier can send a GOAWAY frame so that the client is forced to open a new connection for new streams.

On the client side, we should return some sort of refusal (either through a poll_ready() with a dedicated failure type or with an error type that returns the Request<T> to the application).

On the server side, we'll need to send a GOAWAY with a last stream id of the maximum stream id.

hang with concurrency and payloads

I'm running tests with varying stream concurrency and response payload size (to exercise flow control, etc).

With a stream concurrency of 32 (on one connection) and a response payload size of 16300 B, i'm able to process an arbitrary number of requests.

Changing the response payload to 16400 B, the test hangs after only a few hundred requests and no further work is done (and the CPU is totally idle). This behavior can reproduced with stream concurrencies as low as 4.

I have a guess that this has to do with send-side stream notification on connection-level window updates. I need more evidence to support that theory, though.

Improve noise of logs

There is a lot logged, and while it's useful, it can make it hard to see slightly more important information in the logs. Perhaps we can promote many of the logs to debug level, especially those with useful arguments included. Some of the less important logs could stay at trace (things like poll), or possibly be removed entirely.

I suspect @olix0r has noticed the noise :)

flow controller panic when sending data when available > window

It's possible to panic the stream-level flow controller:

thread 'main' panicked at 'assertion failed: sz <= (self.window_size as WindowSize)', /home/ver/.cargo/git/checkouts/h2-5627e19d2c95dbee/d56531f/src/proto/streams/flow_control.rs:136:8
stack backtrace:

This is because FlowController::available() is used to determine stream capacity, but FlowController::send_data uses FlowController::window_size() as an upper bound. Because available is intended to be greater than window_size at times, this leads to a panic.

Changing prioritize to check window_size() appears to resolve this issue:

--- a/src/proto/streams/prioritize.rs
+++ b/src/proto/streams/prioritize.rs
@@ -450,7 +450,7 @@ impl<B, P> Prioritize<B, P>
                             // window.
                             //
-                            // TODO: Is this the right thing to check?
-                            let stream_capacity = stream.send_flow.available();
+                            let stream_capacity = stream.send_flow.window_size();
                             let sz = frame.payload().remaining();

It's unclear to me how available is to be used on the send-side, if at all.

Change frame::Reason from an enum to an opaque struct

The Reason is exposed as the public API, so we don't want a show it as an enum that may need to be extended later. (Bonus, this will also remove a byte for needing the discriminant.)

It should be like:

pub struct Reason(u32);

impl Reason {
    pub const NO_ERROR: Reason = Reason(0);
    // ...
}

There is a question of whether some of the reasons should be pub(crate), since users shouldn't need to signal some errors (they happen at the protocol layer), but if we keep the public From<u32> for Reason, people can create any reason they want, so it may be moot.

Split `Client` into connection & `start_request` handles.

Conflating the handle the advances the connection state with the handle that is used to start requests is limiting. These handles should be split into two types.

Open questions

  • What should the two types be named
  • Should the start_request handle impl Clone.

Specifically, if StartRequest (naming tbd) impls Clone this would allow streams to be initialized from multiple tasks/threads, which seems like a good feature. The difficulty lies in coordinating access to a single resource across tasks. When the concurrent stream limit is reached, StartRequest::poll_ready calls would race to get access to stream IDs. The solution to this could be to model how mpsc::Sender behaves when cloned.

Simplify hpack encoding

The encoder does some interesting stuff w/ splitting up encoding across continuation frames. This may be able to be simplified.

expose APIs to set target window size

There is no API to change the target window size to be different from SETTINGS_INITIAL_WINDOW_SIZE. An endpoint may wish to this on either a connection or individual stream.

Clients, servers, and their streams should probably have window_target(&self) -> u32 and set_window_target(&mut self, sz: u32) functions.

Account for invalid frames against connection flow control window

A receiver that receives a flow-controlled frame MUST always account for its contribution against the connection flow-control window, unless the receiver treats this as a connection error (Section 5.4.1). This is necessary even if the frame is in error. The sender counts the frame toward the flow-control window, but if the receiver does not, the flow-control window at the sender and receiver can become different.

If a RST_STREAM frame is sent, any data frames received on this stream must be accounted for against the connection level flow control window.

Write documentation for h2

The crate needs docs so that people can figure out how to use it! This issue will be used to track specific points that should be documented.

  • The h2 library can accept / return request / response values that are set to HTTP version 1.1.

Recv.next_stream_id should be updated in `open`

It is currently updated in recv_headers, which could result in receiving a HEADERS frame that gets rejected (due to being malformed), then the same stream ID is received with a valid HEADERS frame which gets accepted.

The client::Body should not be generic over the sending Buf type

After a request, you get back a Response<Body<B>>, where B is the kind of Buf a user can be sending for the request bodies. It is useless on the Body, as the user will only get back Bytes.

Technically it's currently there because the Body owns a StreamRef, which contains this generic.

compile error: no method named `set_max_frame_size`

Projects that depend on h2 can no longer compile due to accessing an unstable feature from the stable API:

error[E0599]: no method named `set_max_frame_size` found for type `codec::framed_read::FramedRead<codec::framed_write::FramedWrite<T, _>>` in the current scope
  --> /Users/ver/b/rs/h2/src/codec/mod.rs:53:15
   |
53 |         inner.set_max_frame_size(max_frame_size);
   |               ^^^^^^^^^^^^^^^^^^

   Compiling ring v0.11.0
error[E0599]: no method named `set_max_recv_frame_size` found for type `codec::Codec<T, _>` in the current scope
   --> /Users/ver/b/rs/h2/src/client.rs:213:19
    |
213 |             codec.set_max_recv_frame_size(max as usize);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^

error[E0599]: no method named `set_max_recv_frame_size` found for type `codec::Codec<T, _>` in the current scope
  --> /Users/ver/b/rs/h2/src/server.rs:97:19
   |
97 |             codec.set_max_recv_frame_size(max as usize);
   |                   ^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

error: Could not compile `h2`.
warning: build failed, waiting for other jobs to finish...
error: build failed

The public Client and Server interfaces attempt to call codec.set_max_recv_frame_size:

impl<T, B: IntoBuf> Future for Handshake<T, B>
where
    T: AsyncRead + AsyncWrite,
{
    type Item = Client<T, B>;
    type Error = ::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let (io, _) = try_ready!(self.inner.poll());

        debug!("client connection bound");

        // Create the codec
        let mut codec = Codec::new(io);

        if let Some(max) = self.settings.max_frame_size() {
            codec.set_max_recv_frame_size(max as usize);
        }
impl<T, B> Server<T, B>
where
    T: AsyncRead + AsyncWrite + 'static,
    B: IntoBuf + 'static,
{
    fn handshake2(io: T, settings: Settings) -> Handshake<T, B> {
        // Create the codec
        let mut codec = Codec::new(io);

        if let Some(max) = settings.max_frame_size() {
            codec.set_max_recv_frame_size(max as usize);
        }

The Codec::new (which must be stable, since it's called from client and server stable APIs above) calls the unstable FramedRead::set_max_frame_size.

#[derive(Debug)]
pub struct Codec<T, B> {
    inner: FramedRead<FramedWrite<T, B>>,
}

impl<T, B> Codec<T, B>
where
    T: AsyncRead + AsyncWrite,
    B: Buf,
{
    /// Returns a new `Codec` with the default max frame size
    #[inline]
    pub fn new(io: T) -> Self {
        Self::with_max_recv_frame_size(io, frame::DEFAULT_MAX_FRAME_SIZE as usize)
    }

    /// Returns a new `Codec` with the given maximum frame size
    pub fn with_max_recv_frame_size(io: T, max_frame_size: usize) -> Self {
        ...

        let mut inner = FramedRead::new(delimited);

        // Use FramedRead's method since it checks the value is within range.
        inner.set_max_frame_size(max_frame_size);

        Codec {
            inner,
        }
    }
}


impl<T, B> Codec<T, B> {
    /// Updates the max received frame size.
    ///
    /// The change takes effect the next time a frame is decoded. In other
    /// words, if a frame is currently in process of being decoded with a frame
    /// size greater than `val` but less than the max frame size in effect
    /// before calling this function, then the frame will be allowed.
    #[cfg(feature = "unstable")]
    #[inline]
    pub fn set_max_recv_frame_size(&mut self, val: usize) {
        self.inner.set_max_frame_size(val)
    }
impl<T> FramedRead<T> {
    ...

    /// Updates the max frame size setting.
    ///
    /// Must be within 16,384 and 16,777,215.
    #[cfg(feature = "unstable")]
    #[inline]
    pub fn set_max_frame_size(&mut self, val: usize) {
        assert!(
            frame::DEFAULT_MAX_FRAME_SIZE as usize <= val &&
                val <= frame::MAX_MAX_FRAME_SIZE as usize
        );
        self.inner.set_max_frame_length(val)
    }
}

RFC: flow control

HTTP/2 flow control applies on individual streams as well as on connections. Flow control
applies bidirectionally: receiving from the remote to the local peer, and sending from
local to remote peer.

Receiver Flow Control

  • Track the local window size.
    • Configured with local SETTINGS_INITIAL_WINDOW_SIZE (including updates)
    • Count received DATA frames against flow control.
    • Reset stream / fail connection on violation.
  • Send WINDOW_UPDATE frames to the remote.
    • When received DATA is dropped to allow effective memory constraints.
    • With buffering (for small frames) -- nagle's algorithm?

Sender Flow Control

  • Track the remote flow control window.
    • Configured with local SETTINGS_INITIAL_WINDOW_SIZE (including updates)
    • Count sent DATA frames against flow control.
    • Ensure the outbound window is not violated.
    • Apply backpressure when writing would violate window.
  • Allow reset/data eos/trailers to be transmitted even when window is closed.
  • Receive WINDOW_UPDATE frames from the remote.
    • Unblock writer

Example: assymetric windows

Intermediary proxies may forward between endpoints with assymetric window sizes and must
buffer.

  • A proxy is forwarding a stream from the src remote to the dst remote.
  • The src local window size is 1000B. The dst remote window size is 100B.
  • A 300B frame is received from sbrc and 100B is sent to dst.
  • The src local window size is now 700B. The dst remote window is empty. And 200B are
    buffered in memory.
  • A 700B frame is received from src and buffered since the dst window is empty.
  • The src window is now empty. 900B are buffered. The src receiver MAY send a 100B
    window update.
  • The dst sends a window update of 100B.
  • 100B are sent to dst and now 800B are buffered.
  • ...

Challenges

  1. Sender flow control should cause backpressure. A sender must not be able to violate
    the flow control window. However, it's inappropriate to apply this backpressure on a
    connection's frames, since resets/trailers/etc must proceed even when windows are empty.
  2. Receivers must not send window updates until the memory is released. This should
    allow for the partial contents of a data frame to be released, and should not
    necessarily cause an immediate window update (esp in the case of small frames).
  3. Flow controllers must receive settings updates.

Thoughts

This seems to suggest that, at the highest level, we want to model a stream's data as
something like AsyncRead and AsyncWrite. Specifically, we want to allow for partial
writes on a sender -- trying to send 1000B on a stream with a 300B window should write
300B and return the remaining 700B to be buffered.

Flow control cannot enforce backpressure on streams of frames, only on bytes themselves.
It seems natural, then, for flow control to be integrated directly with buffering so that
creation of a buffer can deduct from a local window and dropping part of a buffer can
deposit into a remote window.

Something like:

trait ReceiverStream {
    fn read(&mut self) -> Poll<Data, StreamError>;
}

trait SenderStream {
    /// Writes to the local side of a stream, to be read by the Remote.
    fn write<D: Buf>(&mut self, data: D) -> LocalWrite<D>;
}

type LocalWrite<D> = Result<AsyncWrite<D>, StreamError>;
enum AsyncWrite<D> {
    Complete,
    Incomplete(D),
}

struct Data {
    flow_controller: FlowControllerReleaser,
    ..
}
impl Buf for Data {
    fn advance(&mut self, sz: usize) {
        self.flow_controller.release(sz);
        ..
    }
}

It seems like this API would have to sit on top of a muxer/demuxer -- if we're enforcing buffering/backpressure, we'd want that buffer to be associated with an Http message (and above the Frame based API).

panic: 'attempt to subtract with overflow'

Triggered by running the following against an h2 server:

/usr/local/opt/curl/bin/curl --http2 --http2-prior-knowledge http://localhost:7777
RUST_LOG=h2::proto=trace
1506195186.415549 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1506195186.415734 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1506195186.415819 TRACE h2::proto::streams::prioritize Prioritize::new; flow=FlowControl { window_size: 65535, available: 65535 }
1506195186.415898 TRACE h2::proto::settings send_pending_ack; pending=None
1506195186.416754 TRACE h2::proto::connection recv SETTINGS; frame=Settings { flags: SettingsFlags(0), header_table_size: None, enable_push: Some(0), max_concurrent_streams: Some(100), initial_window_size: Some(1073741824), max_frame_size: None, max_header_list_size: None }
1506195186.416808 TRACE h2::proto::settings send_pending_ack; pending=Some(Settings { flags: SettingsFlags(0), header_table_size: None, enable_push: Some(0), max_concurrent_streams: Some(100), initial_window_size: Some(1073741824), max_frame_size: None, max_header_list_size: None })
1506195186.416850 TRACE h2::proto::settings ACK sent; applying settings
1506195186.416920 TRACE h2::proto::connection recv WINDOW_UPDATE; frame=WindowUpdate { stream_id: StreamId(0), size_increment: 1073676289 }
1506195186.416962 TRACE h2::proto::streams::flow_control inc_window; sz=1073676289; old=65535; new=1073741824
1506195186.417012 TRACE h2::proto::settings send_pending_ack; pending=None
1506195186.418192 TRACE h2::proto::connection recv HEADERS; frame=Headers { stream_id: StreamId(1), stream_dep: None, flags: HeadersFlag { end_stream: true, end_headers: true, padded: false, priority: false } }
1506195186.418316 TRACE h2::proto::streams::flow_control inc_window; sz=65535; old=0; new=65535
1506195186.418357 TRACE h2::proto::streams::flow_control inc_window; sz=1073741824; old=0; new=1073741824
1506195186.418484 TRACE h2::proto::streams::streams recv_headers; stream=StreamId(1); state=State { inner: Idle }
1506195186.418538 TRACE h2::proto::streams::recv opening stream; init_window=65535
1506195186.418589 DEBUG h2::proto::connection Connection::poll; err=ProtocolError
1506195186.418631 TRACE h2::proto::streams::state recv_err; err=Proto(ProtocolError)
thread 'main' panicked at 'attempt to subtract with overflow', /Users/ver/.cargo/git/checkouts/h2-5627e19d2c95dbee/a72a6bc/src/proto/streams/counts.rs:141:13
stack backtrace:
   0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
   1: std::sys_common::backtrace::_print
   2: std::panicking::default_hook::{{closure}}
   3: std::panicking::default_hook
   4: std::panicking::rust_panic_with_hook
   5: std::panicking::begin_panic
   6: std::panicking::begin_panic_fmt
   7: rust_begin_unwind
   8: core::panicking::panic_fmt
   9: core::panicking::panic
  10: <h2::proto::streams::counts::Counts<P>>::dec_num_streams
  11: <h2::proto::streams::counts::Counts<P>>::transition_after
  12: <h2::proto::streams::counts::Counts<P>>::transition
  13: <h2::proto::streams::streams::Streams<B, P>>::recv_err::{{closure}}
  14: <h2::proto::streams::store::Store<B, P>>::for_each
  15: <h2::proto::streams::streams::Streams<B, P>>::recv_err
  16: <h2::proto::connection::Connection<T, P, B>>::poll
  17: <h2::server::Server<T, B>>::poll_close
  18: <h2::server::Server<T, B> as futures::stream::Stream>::poll
  19: <futures::stream::fold::Fold<S, F, Fut, T> as futures::future::Future>::poll
  20: <futures::future::map_err::MapErr<A, F> as futures::future::Future>::poll
  21: <futures::future::chain::Chain<A, B, C>>::poll
  22: <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll
  23: <futures::future::map::Map<A, F> as futures::future::Future>::poll
  24: <futures::future::chain::Chain<A, B, C>>::poll
  25: <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll
  26: <alloc::boxed::Box<F> as futures::future::Future>::poll
  27: <tower_h2::server::ServeConnection as futures::future::Future>::poll
  28: <futures::future::map_err::MapErr<A, F> as futures::future::Future>::poll
  29: <alloc::boxed::Box<F> as futures::future::Future>::poll
  30: <futures::task_impl::Spawn<F>>::poll_future_notify::{{closure}}
  31: <futures::task_impl::Spawn<T>>::enter::{{closure}}
  32: futures::task_impl::std::set
  33: <futures::task_impl::Spawn<T>>::enter
  34: <futures::task_impl::Spawn<F>>::poll_future_notify
  35: tokio_core::reactor::Core::dispatch_task::{{closure}}
  36: <scoped_tls::ScopedKey<T>>::set
  37: tokio_core::reactor::Core::dispatch_task
  38: tokio_core::reactor::Core::dispatch
  39: tokio_core::reactor::Core::poll
  40: tokio_core::reactor::Core::run
  41: buoxy::main
  42: __rust_maybe_catch_panic
  43: std::rt::lang_start
  44: main
tshark output
Transmission Control Protocol, Src Port: 7777, Dst Port: 55059, Seq: 1, Ack: 1, Len: 9
HyperText Transfer Protocol 2
    Stream: SETTINGS, Stream ID: 0, Length 0
        Length: 0
        Type: SETTINGS (4)
        Flags: 0x00
            .... ...0 = ACK: False
            0000 000. = Unused: 0x00
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0

Transmission Control Protocol, Src Port: 55059, Dst Port: 7777, Seq: 25, Ack: 10, Len: 27
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 18
Length: 18
Type: SETTINGS (4)
Flags: 0x00
.... ...0 = ACK: False
0000 000. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
Settings - Max concurrent streams : 100
Settings Identifier: Max concurrent streams (3)
Max concurrent streams: 100
Settings - Initial Windows size : 1073741824
Settings Identifier: Initial Windows size (4)
Initial Windows Size: 1073741824
Settings - Enable PUSH : 0
Settings Identifier: Enable PUSH (2)
Enable PUSH: 0

Transmission Control Protocol, Src Port: 55059, Dst Port: 7777, Seq: 52, Ack: 10, Len: 13
HyperText Transfer Protocol 2
Stream: WINDOW_UPDATE, Stream ID: 0, Length 4
Length: 4
Type: WINDOW_UPDATE (8)
Flags: 0x00
0000 0000 = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
0... .... .... .... .... .... .... .... = Reserved: 0x0
.011 1111 1111 1111 0000 0000 0000 0001 = Window Size Increment: 1073676289

Transmission Control Protocol, Src Port: 55059, Dst Port: 7777, Seq: 65, Ack: 10, Len: 39
HyperText Transfer Protocol 2
Stream: HEADERS, Stream ID: 1, Length 30
Length: 30
Type: HEADERS (1)
Flags: 0x05
.... ...1 = End Stream: True
.... .1.. = End Headers: True
.... 0... = Padded: False
..0. .... = Priority: False
00.0 ..0. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Header Block Fragment: 828486418aa0e41d139d09b8ebaebb7a8825b650c3abb6da...
[Header Length: 129]
[Header Count: 6]
Header: :method: GET
Name Length: 7
Name: :method
Value Length: 3
Value: GET
Representation: Indexed Header Field
Index: 2
Header: :path: /
Name Length: 5
Name: :path
Value Length: 1
Value: /
Representation: Indexed Header Field
Index: 4
Header: :scheme: http
Name Length: 7
Name: :scheme
Value Length: 4
Value: http
Representation: Indexed Header Field
Index: 6
Header: :authority: localhost:7777
Name Length: 10
Name: :authority
Value Length: 14
Value: localhost:7777
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 1
Header: user-agent: curl/7.55.1
Name Length: 10
Name: user-agent
Value Length: 11
Value: curl/7.55.1
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 58
Header: accept: /
Name Length: 6
Name: accept
Value Length: 3
Value: /
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 19
Padding:

Transmission Control Protocol, Src Port: 55059, Dst Port: 7777, Seq: 104, Ack: 10, Len: 9
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 0
Length: 0
Type: SETTINGS (4)
Flags: 0x01
.... ...1 = ACK: True
0000 000. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0

Strip connection level header fields

Such intermediaries SHOULD also remove other connection-specific header fields, such as Keep-Alive, Proxy-Connection, Transfer-Encoding, and Upgrade, even if they are not nominated by the Connection header field.

If a header frame is sent that includes a Connection field, it should be stripped including all fields referenced by the Connection field value.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.