http2nghttp2

Why 5 PRIORITY frames are sent from HTTP2 client before it sends a HEADERS frame ? Are they necessary for a successful HTTP2 connection?


I noticed that some HTTP2 clients (Firefox and nghttp) send 5 PRIORITY frames for stream 3, 5, 7, 9, 11 after http2 protocol is agreed and before they send a HEADERS frame. I am curious why? I know the meaning of PRIORITY frames, but I don't get the point of sending it, but both Firefox and nghttp do it, so there must be some reasons.

And most importantly, those streams (stream 3, 5, 7, 9, 11) are not used after PRIORITY frames according to the log.

Output information from server for Firefox is shown as follow.

$ nghttpd -d ~/Proxy 8080 key.pem cert.pem -v
Enter PEM pass phrase:
IPv4: listen 0.0.0.0:8080
IPv6: listen :::8080
[ALPN] client offers:
* h2
* spdy/3.1
* http/1.1
SSL/TLS handshake completed
The negotiated protocol: h2
[id=1] [ 18.917] send SETTINGS frame <length=6, flags=0x00, stream_id=0>
      (niv=1)
      [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[id=1] [ 18.920] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>
      (niv=2)
      [SETTINGS_INITIAL_WINDOW_SIZE(0x04):131072]
      [SETTINGS_MAX_FRAME_SIZE(0x05):16384]
[id=1] [ 18.920] recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
      (window_size_increment=12517377)
[id=1] [ 18.920] recv PRIORITY frame <length=5, flags=0x00, stream_id=3>
      (dep_stream_id=0, weight=201, exclusive=0)
[id=1] [ 18.920] recv PRIORITY frame <length=5, flags=0x00, stream_id=5>
      (dep_stream_id=0, weight=101, exclusive=0)
[id=1] [ 18.920] recv PRIORITY frame <length=5, flags=0x00, stream_id=7>
      (dep_stream_id=0, weight=1, exclusive=0)
[id=1] [ 18.920] recv PRIORITY frame <length=5, flags=0x00, stream_id=9>
      (dep_stream_id=7, weight=1, exclusive=0)
[id=1] [ 18.920] recv PRIORITY frame <length=5, flags=0x00, stream_id=11>
      (dep_stream_id=3, weight=1, exclusive=0)
[id=1] [ 18.920] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
      ; ACK
      (niv=0)
[id=1] [ 18.926] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
      ; ACK
      (niv=0)
[id=1] [ 25.773] recv (stream_id=13) :method: GET
[id=1] [ 25.773] recv (stream_id=13) :path: /plaintext.txt
[id=1] [ 25.773] recv (stream_id=13) :authority: 127.0.0.1:8080
[id=1] [ 25.773] recv (stream_id=13) :scheme: https
[id=1] [ 25.773] recv (stream_id=13) user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:45.0) Gecko/20100101 Firefox/45.0
[id=1] [ 25.773] recv (stream_id=13) accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
[id=1] [ 25.773] recv (stream_id=13) accept-language: en-US,en;q=0.5
[id=1] [ 25.773] recv (stream_id=13) accept-encoding: gzip, deflate, br
[id=1] [ 25.773] recv (stream_id=13) if-modified-since: Wed, 27 Apr 2016 13:10:07 GMT
[id=1] [ 25.773] recv HEADERS frame <length=196, flags=0x25, stream_id=13>
      ; END_STREAM | END_HEADERS | PRIORITY
      (padlen=0, dep_stream_id=11, weight=32, exclusive=0)
      ; Open new stream
[id=1] [ 25.774] recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=13>
      (window_size_increment=12451840)
[id=1] [ 25.774] send HEADERS frame <length=42, flags=0x05, stream_id=13>
      ; END_STREAM | END_HEADERS
      (padlen=0)
      ; First response header
      :status: 304
      server: nghttpd nghttp2/1.8.0
      date: Fri, 29 Apr 2016 08:07:25 GMT
[id=1] [ 25.774] stream_id=13 closed

But Chrome does not send them, as shown below. So they are not necessary for a successful connection?

$ nghttpd -d ~/Proxy 8080 key.pem cert.pem -v
Enter PEM pass phrase:
IPv4: listen 0.0.0.0:8080
IPv6: listen :::8080
[ALPN] client offers:
 * h2
 * spdy/3.1
 * http/1.1
SSL/TLS handshake completed
The negotiated protocol: h2
[id=1] [ 16.069] send SETTINGS frame <length=6, flags=0x00, stream_id=0>
      (niv=1)
      [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[id=1] [ 16.083] closed
[ALPN] client offers:
 * h2
 * spdy/3.1
 * http/1.1
 SSL/TLS handshake completed
 The negotiated protocol: h2
 [id=2] [ 16.298] send SETTINGS frame <length=6, flags=0x00, stream_id=0>
      (niv=1)
      [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
 [id=2] [ 16.299] closed
[ALPN] client offers:
 * h2
 * spdy/3.1
 * http/1.1
SSL/TLS handshake completed
The negotiated protocol: h2
[id=3] [ 16.303] send SETTINGS frame <length=6, flags=0x00, stream_id=0>
      (niv=1)
      [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[id=3] [ 16.303] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>
      (niv=2)
      [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):1000]
      [SETTINGS_INITIAL_WINDOW_SIZE(0x04):6291456]
[id=3] [ 16.303] recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
      (window_size_increment=15663105)
[id=3] [ 16.303] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
      ; ACK
      (niv=0)
[id=3] [ 16.303] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
      ; ACK
      (niv=0)
[id=3] [ 16.311] recv (stream_id=1) :method: GET
[id=3] [ 16.311] recv (stream_id=1) :authority: 127.0.0.1:8080
[id=3] [ 16.311] recv (stream_id=1) :scheme: https
[id=3] [ 16.311] recv (stream_id=1) :path: /plaintext.txt
[id=3] [ 16.311] recv (stream_id=1) accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
[id=3] [ 16.311] recv (stream_id=1) upgrade-insecure-requests: 1
[id=3] [ 16.311] recv (stream_id=1) user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36
[id=3] [ 16.311] recv (stream_id=1) accept-encoding: gzip, deflate, sdch
[id=3] [ 16.311] recv (stream_id=1) accept-language: en-US,en;q=0.8
[id=3] [ 16.311] recv HEADERS frame <length=238, flags=0x25, stream_id=1
....

Solution

  • They are not required for a successful connection.

    For the rest, I'm just guessing here. Firefox is using those streams as "virtual streams". Then it makes further real streams dependent on those virtual streams. The effect should be the creation of different priority groups, without needing to specify priorities per (real) streams.