1 of 41

nghttp2

The heir of spdylay

2 of 41

nghttp2 is HTTP/2.0 C library

  • Started as a fork from spdylay
  • Only updated for the draft marked as “implementation”
    • draft-ietf-httpbis-http2-04
    • draft-ietf-httpbis-http2-06 (we are here)
  • Support only latest draft protocol version
  • No SPDY support
  • Similar API with spdylay, but some refinements
  • Development happens on github

3 of 41

Why did you name it as “nghttp2”?

  • “Name is important”
  • First candidate: tachyon
    • A tachyon /ˈtæki.ɒn/ or tachyonic particle is a hypothetical particle that always moves faster than light.” (from wikipedia)
    • Watch X-Files Season 6 Episode “Dream land”
    • Rejected: someone used it already
    • http://packages.debian.org/squeeze/libtachyon-0.98
  • What about “http-ng”?
    • Of course, “ng” means “Next Generation”
    • Rejected: http://www.w3.org/Protocols/HTTP-NG/

4 of 41

Why did you name it as “nghttp2”?

  • OK, so let’s move “ng” to the front: nghttp
    • Hmm, it does not sound like HTTP/2.0
    • Might be a problem if it does not hit when searched with “HTTP2” keyword
    • Well, add “2” at the end: nghttp2
    • LGTM

5 of 41

First Iteration

HTTP-draft-04/2.0

6 of 41

First Iteration: HTTP-draft-04/2.0

  • draft-04 is the first draft marked as “for implementation”
  • First, I needed to migrate spdylay codebase into HTTP/2.0 spec

7 of 41

How did you migrate from spdylay?

  • git clone … and change remotes
  • Use sed magic to rename everything
    • -i option is your friend
  • Remove dreadful CREDENTIAL frame
  • Remove junk callbacks for CREDENTIAL
  • Change framing and adjust error codes
  • Employ connection level flow control stuff
  • How hard can it be?

8 of 41

417 Expectation Failed

  • spdylay relies heavily on frame types of message transaction
    • SYN_STREAM, SYN_REPLY, HEADERS
    • Now only HEADERS; rewrite was necessary
  • Dealing with flow control cancellation by SETTINGS and WINDOW_UPDATE was a bit tedious
  • But the biggest hurdle was, of course,...

9 of 41

HEADER COMPRESSION (HPACK)

  • Hard to understand
  • Several ambiguous sections
  • ... which is critical for the interop
    • working set: value (n,v) or reference?
    • index in working set is also renumbered on eviction?
  • You have to dig into mailing list to get those answers

10 of 41

HPACK encoding algo in nghttp2

  • Encoding
    • Use indexed rep if (n,v) is in header table
    • Else, use literal rep with indexed name if name is in header table
    • Else, use literal rep with new name
  • Incremental only
  • No substitution
    • Data shows not so effective (ratio 0.37 vs 0.39):
    • It is not trivial to efficiently utilize it
    • Further experiments needed

11 of 41

Tools in nghttp2

  • Just like spdylay, nghttp2 has several tools for debugging and experiments
    • nghttp … client
    • nghttpd … server
    • nghttpx … proxy

12 of 41

nghttp: HTTP/2.0 client

  • Based on to spdycat in spdylay
  • … but rewritten using libevent
  • Supports TLS-NPN, Upgrade and direct
    • No ALPN, why?
    • … because ALPN enabled OpenSSL has not been released yet (even not in beta)
    • … also libevent must be rebuild with it
  • Verbose output inherited from spdycat
  • -m=<N> … Send <N> requests
  • -a … Download assets (e.g., css, img and js)
  • -d=<FILE> … Perform POST

13 of 41

nghttpd: HTTP/2.0 server

  • Based on spdyd in spdylay
  • … but rewritten using libevent
  • Supports TLS-NPN and direct; No Upgrade
  • Verbose output inherited from spdyd

14 of 41

nghttpx: HTTP/2.0 proxy

  • Based on shrpx in spdylay
  • Support SPDY using spdylay
    • … so still can still be used as SPDY proxy
  • Protocol conversions:
    • HTTP/1 → HTTP/2
    • HTTP/2 → HTTP/1
    • HTTP/2, SPDY(TLS) → HTTP/1 or HTTP/2
  • Turn ordinary HTTP/1 server (e.g., apache) into HTTP/2 server
  • CONNECT is undefined in the draft 04
    • … but we use same semantics as SPDY proxy for now

15 of 41

nghttpx: HTTP/2.0 proxy

  • Useful for header compression testing
  • Configuration:
    • Firefox
    • ⇔ (HTTP/1, N conn) ⇔
    • nghttpx as HTTP/1 proxy
    • ⇔ (HTTP/2, 1 conn) ⇔ ← Hdr comp/decomp
    • nghttpx as HTTP/2 proxy
    • ⇔ (HTTP/1, N conn) ⇔
    • squid
    • ⇔ Internet (aka Wild West)
  • Lots of exercise for compressor
  • Eviction occurs frequently

16 of 41

First Interop Test

HTTP-draft-04/2.0

17 of 41

First Interop Test (draft-04)

  • I did go to the Hamburg interim
  • Test was conducted personally
  • … in the same time frame just for fun
  • Detailed results are here:

18 of 41

First Interop Results (1)

  • MSOpenTech/http2-katana
    • Tested with nghttp client via HTTP Upgrade
    • HTTP Upgrade succeeded
    • ... but the HTTP request in the HTTP Upgrade request was ignored
  • molnarg/node-http2
    • Tested with nghttp client via NPN
    • There was flow control issue
    • Other than that, they got to work with each other
    • … but node-http2 only returned 1 HTTP header, so there might be some glitches on header compression on several request/response exchanges

19 of 41

First Interop Results (2)

  • Mozilla/Firefox
    • Tested with nghttpd server via NPN
    • The first request/response was good
    • But Firefox does not toggle off the indexed entry if the same index is substituted
    • This makes duplicated name/value appears in the subsequent request/response
  • shigeki/interop-iij-http2
    • Tested with nghttp client via NPN and direct
    • Single request/response worked fine
    • But sending 2 requests in parallel caused connection loss

20 of 41

First Interop Results (3)

  • Chromium
    • Tested with nghttpd server and nghttpx reverse proxy via NPN
    • They worked fine
    • … except that Chromium does not support disabling connection-level flow control with WINDOW_UPDATE
    • Chromium just ignored it on purpose
    • … knowing that it will be removed on the next draft
    • And eventually, half-connection was stalled

21 of 41

First Interop Summary

  • Overall, it was better than I expected
  • For header compression, we need several and parallel request/response transactions to see it really works
  • Single request only does not reveal the bug behind it
  • Use nghttp with -m and -a option to test multiple requests

22 of 41

Second Iteration

HTTP-draft-06/2.0

23 of 41

Second Iteration: HTTP-draft-06/2.0

  • Well, I just did it according to the spec
  • HPACK draft was improved
  • … but still a bit hard for mere mortals like me
  • HPACK has a common pitfall and it seems everyone was trapped by that.

24 of 41

HPACK 03 Best Pitfall

  • Suppose the header table is like this:
    • 0: (k1, v1)
    • 1: (k2, v2)
    • 2: (k3, v3)
  • Reference set is like this:
    • 0: (k1, v1)
  • Now encoder encodes following headers:
    • (k1, v1)
    • (k4, v4)

25 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k1, v1)
    • 1: (k2, v2)
    • 2: (k3, v3)
  • Reference set
    • 0: (k1, v1) ← here
  • Emitted

1. Encode (k1, v1)

in the reference set, which means it is common (aka implied) header. Nothing emitted.

26 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k1, v1)←del
    • 1: (k2, v2)
    • 2: (k3, v3)
  • Reference set
    • 0: (k1, v1) ←del
  • Emitted

2. Encode (k4, v4)

Use Literal rep with incremental indexing

Adding (k4, v4) will remove (k1, v1) because of size limitation.

27 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k2, v2)
    • 1: (k3, v3)
    • 2: (k4, v4) ←add
  • Reference set
    • 2: (k4, v4) ←add
  • Emitted
    • Literal inc (k4,v4)

Encoding is over.

28 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k1, v1)
    • 1: (k2, v2)
    • 2: (k3, v3)
  • Reference set
    • 0: (k1, v1)
  • Received block
    • Literal inc (k4,v4)
  • Emitted

Decoding

Process (k4,v4)

29 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k2, v2)
    • 1: (k3, v3)
    • 2: (k4, v4)
  • Reference set
    • 2: (k4, v4) (emitted)
  • Received block
    • Literal inc (k4,v4)
  • Emitted
    • (k4, v4) ← decoded

Decoding

Emit (k4, v4),

Remove (k1, v1) and add (k4, v4) to header table,

30 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k2, v2)
    • 1: (k3, v3)
    • 2: (k4, v4)
  • Reference set
    • 2: (k4, v4) (emitted)
  • Received block
    • Literal inc (k4,v4)
  • Emitted
    • (k4, v4)

Decoding

Emit common header, which is in the reference set but not emitted: NONE

31 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k2, v2)
    • 1: (k3, v3)
    • 2: (k4, v4)
  • Reference set
    • 2: (k4, v4) (emitted)
  • Received block
    • Literal inc (k4,v4)
  • Emitted
    • (k4, v4)

Decoding is over

Decoder misses

(k1, v1)!

32 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k1, v1)←del
    • 1: (k2, v2)
    • 2: (k3, v3)
  • Reference set
    • 0: (k1, v1) ←del
  • Emitted

How to fix?

When encoding (k4, v4), if adding (k4, v4) will remove (k1, v1), and (k1, v1) is common header and not emitted, emit indexed representation twice.

33 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k1, v1)←del
    • 1: (k2, v2)
    • 2: (k3, v3)
  • Reference set
    • 0: (k1, v1) ←del
  • Emitted
    • Indexed 0
    • Indexed 0

How to fix?

When encoding (k4, v4), if adding (k4, v4) will remove (k1, v1), and (k1, v1) is common header and not emitted, emit indexed representation twice.

34 of 41

HPACK 03 Best Pitfall

  • Header table
    • 0: (k2, v2)
    • 1: (k3, v3)
    • 2: (k4, v4)
  • Reference set
    • 2: (k4, v4)
  • Emitted
    • Indexed 0
    • Indexed 0
    • Literal inc (k4,v4)

How to fix?

When encoding (k4, v4), if adding (k4, v4) will remove (k1, v1), and (k1, v1) is common header and not emitted, emit indexed representation twice.

35 of 41

Prepare for the consequences of removing implied header from the table

When you are implementing HPACK, relay these words:

36 of 41

Upcoming HPACK changes

37 of 41

Upcoming HPACK Changes

  • Unified request/response initial header table
    • And it is now static.
  • For dynamic header table, add index 0 and remove last.
  • Drop substitution.
  • Header table buffer size negotiation in the core spec
  • Experiment with Huffman encoding

38 of 41

Upcoming HPACK Changes

  • Unified request/response initial header table
    • And it is now static.
  • For dynamic header table, add index 0 and remove last.
  • Drop substitution.

We can achieve 0.36 compression ratio

(0.37 with HPACK-03) → 1 point improvement

Test case: mnot data set https://github.com/http2/http_samples

39 of 41

Upcoming HPACK Changes

  • Header table buffer size negotiation in the core spec

Experiment with various size of table buffer size

Buffer (KiB) Ratio�2 0.42�4 0.36 ← Default�8 0.32�16 0.30�32 0.29�64 0.28�128 0.28�256 0.28 ← Saturation point because no eviction occurs�512 0.28�

40 of 41

Upcoming HPACK Changes

  • Experiment with Huffman encoding

I have actually experimented it

Used huffman codes described in: http://tools.ietf.org/html/draft-rpeon-httpbis-header-compression-03

We can achieve 0.28 compression ratio

(0.37 with HPACK-03) → 9 point improvement

�Code is here

https://github.com/tatsuhiro-t/nghttp2/tree/hpack-exp

41 of 41

Any Questions?

Exploits of a Mom