nghttp2.org

HTTP/2 C library and tools

Nghttp2 v0.7.14

We released nghttp2 v0.7.14.

This release fixes global-buffer-overflow bug in HPACK compression code introduced in nghttp2 v0.7.12. We strongly recommend to upgrade the old installation to this latest release.

Previously, the example code in nghttp2_select_next_protocol documentation had a wrong code which could lead to segmentation fault, due to incorrect return value if no protocol was selected. Now it is corrected.

Previously, when header decompression failed for incoming PUSH_PROMISE, RST_STREAM was sent to the associated stream, instead of the promised stream. Now it is corrected, and RST_STREAM is sent to the promised stream.

Zhuoyun Wei kindly offered systemd and upstart configuration file for nghttpx proxy. Zhuoyun Wei also offered a patch to improve logrotate configuration file for nghttpx.

We updated sphinx_rtd_theme to the latest, which includes even nicer UI.

h2load now shows 2 new metrics: time to connect and TTFB (time to first byte). Thank you to ericcarlschwartz for bringing this awesome feature.

nghttpd now has -m option to specify its SETTINGS_MAX_CONCURRENT_STREAMS limit.

nghttpx now logs absolute URI in access log if it is configured as HTTP/2 or client proxy. It also gets --header-field-buffer and --max-header-fields options to specify maximum header field buffer size it can be received. Previously, it was hardcoded as 32KiB.

We fixed the bug in nghttp that it aborted with assertion error if very large value was given to -t option.

Nghttp2 v0.7.13

We released nghttp2 v0.7.13.

This release fixes the bug that promised stream was reset if NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE was returned from nghttp2_on_header_callback for PUSH_PROMISE. Instead, associated stream was reset.

nghttp2_on_begin_headers_callback now accepts NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as return code just like nghttp2_on_header_callback.

h2load now effectively disables flow control by setting large window size. Previously h2load used default flow control window as described in HTTP/2 and SPDY specification. The window size is 64KiB, which is a bit small, and cannot utilize full server performance when response size is not too small. Basically, we do this kind of benchmarking test to measure server’s throughput, and optimal performance. Smaller window certainly degrades performance even in local testing because server is so fast that it has to wait for WINDOW_UPDATE from h2load. To make default behaviour suitable for peak performance test, we decided to disable flow control in h2load by setting large enough window size. Most users used h2load without -w or -W options, so they were implicitly throttled by flow control and the result was affected by that negatively. Now flow control is disabled by default, the result may improve depending on the implementations.

libnghttp2_asio server’s listen_and_serve function now takes asynchronous parameter, and if it is true, the function returns immediately and caller can gracefully shutdown server. This patch was contributed from Xiaoguang Sun.

Nghttp2 v0.7.12

We released nghttp2 v0.7.12.

This release fixes the bug that nghttp2_session_set_next_stream_id() accepts invalid stream ID as paremter. It also fixes the installation issue where libnghttp2_asio header files are installed even if build configuration disables it.

We did some optimization in HPACK code, and it is a bit faster than the previous version. We also made compressor encode “authorization” and “cookie” header fields with small values with never indexing representation automatically.

For documentation, previously some hyperlinks in man pages of bundled application pointed to wrong direction. Now they are corrected.

For libnghttp2_asio client library, error_cb is now called when error occurred in libnghttp2 code or async read/write code.

Previously nghttp uses its own dependency priority scheme by default and switches to Firefox style one if --idle-dep option is used. Now we rewrite --idle-dep feature, and now we closely mimics Firefox’s behaviour (not entirely the same, of course), and now it is the default priority scheme for nghttp. So we removed --idle-dep option.

With -s option, nghttp shows some statistics of request/response times. Now stream ID is included there.

nghttp also gets --no-push option to disable server push (for HTTP/2 expert, this sends SETTINGS_ENABLE_PUSH with 0 value).

Nghttp2 v0.7.11

We released nghttp2 v0.7.11.

This release fixes waitpid race condition in ocsp response update in nghttpx.

Nghttp2 v0.7.10

We released nghttp2 v0.7.10.

This release adds new APIs. We added nghttp2_session_consume_connection and nghttp2_session_consume_stream functions. The existing nghttp2_session_consume function affects both connection and stream level flow control window. The new nghttp2_session_consume_connection only affects connection level flow control window and nghttp2_session_consume_stream only affects stream level.

We also added nghttp2_send_data_callback to avoid data copy when sending request/response body. We saw meaningful performance improvement in nghttpd and tiny-nghttpd server using this new feature.

To make building libnghttp2 under Windows easier, we added NGHTTP2_EXTERN macro to export public functions in Windows build. lib/Makefile.msvc is also updated by Remo E.

For documentation, now .rst file is generated per API function, which we hope makes the documentation more readable and easy to navigate.

We fixed incorrect header field ordering bug in Python binding. We also added async request/response body generation.

nghttpx proxy server gets OCSP stapling support. We use external Perl script developed under h2o project, to update OCSP response. --tls-ctx-per-worker option was removed since it did not show any performance improvement and just complicated code base. To make debugging easier, now stderr is redirected to errorlog file.

Nghttp2 v0.7.9

We released nghttp2 v0.7.9.

This release fixes corrupted header fields in PUSH_PROMISE issued by nghttpx. The bug that h2load crashes if the number of thread given in -t is greater than the number of client given in -c has also been fixed. For examples, the bug that system header location has precedence over in-package header files has been fixed.

nghttp and nghttpd get new option --hexdump, which hexdumps incoming traffic, similar format as hexdump -C. It could be useful for further debugging.

h2load gets -d option to upload data to server. With this option, h2load now can load test gRPC server (probably unary RPC only?). For example, suppose we are going to load test gRPC greeter_server contained in grpc-common/cpp/helloworld. We have to add following 2 header fields to mimic gRPC request: “te: trailers” and “content-type: application/grpc”. We captured gRPC request body from greeter_client and wrote it in file called grpc-upload. For this particular request body, you can create this file using following python script:

1
2
d='\x00\x00\x00\x00\x07\x0a\x05\x77\x6f\x72\x6c\x64'
with open('grpc-upload', 'w') as f: f.write(d)

The final command-line code is something like this:

1
2
3
4
5
$ h2load http://localhost:50051/helloworld.Greeter/SayHello \
      -d grpc-upload \
      -H 'te: trailers'
      -H 'content-type: application/grpc'
      -n1000000 -c100 -m100

Proxying gRPC With Nghttpx

Google announced gRPC back in February and everyone was excited about it. It is a RPC framework using new ProtocolBuffer3 based on HTTP/2 as transport. Because it is RPC framework, user should look into its API and ProtocolBuffer basics. But as HTTP/2 implementor, we are interested in how HTTP/2 is used under the hood. So we decided to proxy the communication between gRPC client and server with nghttpx proxy server and see what’s going on in transport level.

We used C++ client and server pulled from grpc-common. Build everything as instructed in README. We made one modification to the greeter_client.cc to change remote port number to 3000 to connect to nghttpx proxy. We used nghttpx --http2-bridge mode. The configuration was like this:

1
2
3
4
5
6
greeter_client --HTTP/2-- nghttpx --HTTP/2-- greeter_server
gRPC                 --http2-bridge          gRPC
                     -f127.0.0.1,3000
                     -b127.0.0.1,50051
                     --frontend-no-tls
                     --backend-no-tls

Then we observed the traffic between greeter_client and greeter_server.

greeter_client sent the following request header fields:

1
2
3
4
5
6
:method: POST
:scheme: http
:path: /helloworld.Greeter/SayHello
:authority: localhost:3000
te: trailers
content-type: application/grpc

This is the usual HTTP/2 request, but one thing to note is te: trailers. According to RFC 7230, section 4.3.:

The “TE” header field in a request indicates what transfer codings, besides chunked, the client is willing to accept in response, and whether or not the client is willing to accept trailer fields in a chunked transfer coding.

HTTP/2 disallows transfer-encoding stuff, but it only allows “trailers” in “TE” header field:

The presence of the keyword “trailers” indicates that the client is willing to accept trailer fields in a chunked transfer coding, as defined in Section 4.1.2, on behalf of itself and any downstream clients.

So in HTTP/1.1, trailer fields are only allowed in chunked transfer encoding. In HTTP/2, chunked transfer encoding is deprecated because it has more elegant framing and thanks to it, trailer fields are always allowed.

gRPC does not work without “TE” header field.

The request body was like this (in hexdump):

1
2
00000000  00 00 00 00 07 0a 05 77  6f 72 6c 64              |.......world|
0000000c

This would be data serialized by ProtocolBuffer. We don’t go down the detail in ProtocolBuffer here.

nghttpx forwarded this requests to greeter_server with additional header fields, like “Via” header field.

Upon receiving request, greeter_server processed the request and responded with the following response header fields:

1
:status: 200

Well, that’t the most simple HTTP/2 response, followed by response body (again, in hexdump):

1
2
3
00000000  00 00 00 00 0d 0a 0b 48  65 6c 6c 6f 20 77 6f 72  |.......Hello wor|
00000010  6c 64                                             |ld|
00000012

Then server sent trailer fields:

1
2
grpc-status: 0
grpc-message:

nghttpx forwarded this reponse to the greeter_client and it shows the result to the console:

1
Greeter received: Hello world

So in tranport wise, gRPC uses POST request and response uses trailer fields. This means that we can proxies the gRPC traffic using HTTP/1.1 path as well, since we can forward it in chunked transfer encoding. This just comes from our curiosity and we have no idea this is useful in practice. But this shows the great effort we put in HTTP/2 to interoperate with existing HTTP/1.1 infrastructure.

To prove this, we added another nghttpx to set up HTTP/1.1 path:

1
2
3
4
5
6
greeter_client --HTTP/2-- nghttpx[1] --HTTP/1-- nghttpx[2] --HTTP/2-- greeter_server
gRPC                  -f127.0.0.1,3000        --http2-bridge          gRPC
                      -b127.0.0.1,3001       -f127.0.0.1,3001
                      --frontend-no-tls       -b127.0.0.1,50051
                                              --frontend-no-tls
                                              --backend-no-tls

And this works! nghttpx[1] forwarded gRPC request in HTTP/1.1 chunked transfer-encoding:

1
2
3
4
5
6
7
POST /helloworld.Greeter/SayHello HTTP/1.1
Host: 127.0.0.1:3001
Te: trailers
Content-Type: application/grpc
Transfer-Encoding: chunked
X-Forwarded-Proto: http
Via: 2 nghttpx

In response chain, nghttpx[2] forwarded response header to nghttpx[1]:

1
2
3
4
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Server: nghttpx nghttp2/0.7.9-DEV
Via: 2 nghttpx

… with trailer fields appended after the last chunk.

Nghttp2 v0.7.8

We released nghttp2 v0.7.8.

This release fixes the h2load crash bug if multiple threads are used (-t option). The patch was contributed from Stefan Eissing.

For “http” or “https” URIs, nghttp2 library now validate “:path” pseudo header field strictly. Now it requires to start with “/”. The only exception is OPTIONS request and in that case “:path” pseudo header field can include “*” to represent system-wide OPTIONS request.

Now all header field name and value presented by callback (e.g., nghttp2_on_frame_recv_callback, nghttp2_on_header_callback, etc) are guaranteed to be NULL-terminated. This is useful because most C library string functions require NULL-terminated string.

Nghttp2 v0.7.7

We released nghttp2 v0.7.7.

This is basically the same as v0.7.6. We missed updating man pages in v0.7.6 release, so v0.7.7.

Nghttp2 v0.7.6

We released nghttp2 v0.7.6.

This release made several enhancements to the library. First we made sending trailer part (trailer header field) easier. Previously, nghttp2_submit_request() and nghttp2_submit_response() sets END_STREAM flag set for the last DATA frame and we have no way to send trailer part. To fix this issue, we added NGHTTP2_DATA_FLAG_NO_END_STREAM flag. If application sets this flag along side with NGHTTP2_DATA_FLAG_EOF in nghttp2_data_source_read_callback, the library does not set END_STREAM flag. Then the application can use new nghttp2_submit_trailer() function to send trailer part, which is a HEADERS frame with END_STREAM flag set. The all bundled applications and libnghttp2_asio utilize this feature to send trailer part.

Second enhancement is that now library refuses PUSH_PROMISE frame if unacked local SETTINGS includes ENABLE_PUSH == 0 (disabling server push). Previously the library refuses PUSH_PROMISE only after SETTINGS are acked.

nghttpx has several enhancements in this release. It now accepts multiple backend server addresses for HTTP/2 backend. Previously the number of HTTP/2 backend server is limited to 1 per worker. In this release, we added --backend-http2-connections-per-worker option to specify the number of HTTP/2 backend connection per worker. As the library gets enhanced support for trailer part, nghttpx now supports trailer part for both HTTP/2 and HTTP/1. That means nghttpx can proxy gRPC traffic, which requires trailer support. we also fixed the bug that server push is broken after HTTP upgrade. The another bug, which crashes nghttpx when upgrading HTTP/2 failed, was also fixed.

Stefan Eissing wrote a patch to nghttpx to replace C++11 thread_local keyword with traditional pthread functions. Since Mac OS X’s xcode toolchain does not support thread_local, it may be possible to use nghttpx in multi-threaded mode on Mac OS X finally.

For nghttpd and nghttp, we added --trailer option to send trailer part to exercise trailer part functionality.

For nghttp, Kazuho Oku kindly sent us a patch not to send pseudo-headers in HTTP Upgrade request (which itself is HTTP/1.1 message).

nghttp now treats request as success only if it sees the END_STREAM from peer. Previously it treated a request as success if it is closed (with/without error), before connection close.

We fixed nghttpd bug that “date” header field value is not updated.

For python binding, we fixed bug that push response header fields are not passed to callback in client library.

We rewrite libnghttp2_asio library and its API is not compatible to the earlier versions. Also we added client API. See libnghttp2_asio documentation about the example use of these APIs.