Compare commits

..

342 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
53dfaad925 Update manual pages 2021-09-21 20:46:13 +09:00
Tatsuhiro Tsujikawa
2f2da110a1 Bump version number to 1.45.1 2021-09-21 20:15:07 +09:00
Tatsuhiro Tsujikawa
8a14435aa8 Fix issue that libev cannot be found with autotools under mac osx 2021-09-21 20:14:03 +09:00
Tatsuhiro Tsujikawa
dbaa59908e Fix compile error with libressl 2021-09-21 20:14:03 +09:00
Tatsuhiro Tsujikawa
ca41f2faab Make sure that nghttp2 can be built from tar archive 2021-09-21 20:14:03 +09:00
Tatsuhiro Tsujikawa
daae20d4a5 Always include optional files to EXTRA_DIST 2021-09-21 20:14:03 +09:00
Tatsuhiro Tsujikawa
6d9667dc74 Add missing cmake files to EXTRA_DIST 2021-09-21 20:14:03 +09:00
Tatsuhiro Tsujikawa
58499f256b Update bash_completion 2021-09-20 17:07:58 +09:00
Tatsuhiro Tsujikawa
afb455ef80 python3 2021-09-20 17:07:44 +09:00
Tatsuhiro Tsujikawa
f4515e9034 Update manual pages 2021-09-20 17:02:54 +09:00
Tatsuhiro Tsujikawa
aab07d00d7 Bump version number to 1.45.0, LT revision to 35:0:21 2021-09-20 16:58:28 +09:00
Tatsuhiro Tsujikawa
32ecfc6a86 Use https 2021-09-20 16:54:47 +09:00
Tatsuhiro Tsujikawa
e866f9fae7 Update AUTHORS 2021-09-20 16:53:55 +09:00
Tatsuhiro Tsujikawa
a029f6ed2c Rename sphinxcontrib to rubydomain to avoid module loading error
Rename sphinxcontrib to rubydomain to avoid module loading error when
sphinx-build docker image is used.
2021-09-20 13:43:40 +09:00
Tatsuhiro Tsujikawa
5b6e2cb5e0 Allow SPHINXBUILD to be overridden by environment variable 2021-09-20 12:19:26 +09:00
Tatsuhiro Tsujikawa
0264847a37 bpf: Use LINUX_KERNEL_VERSION extern variable 2021-09-19 21:07:40 +09:00
Tatsuhiro Tsujikawa
d276ca0adc Update doc 2021-09-18 19:28:03 +09:00
Tatsuhiro Tsujikawa
6a099ee50a nghttpx: QUIC requires TLS 2021-09-18 19:27:47 +09:00
Tatsuhiro Tsujikawa
be88846972 Build HTTP/3 and eBPF enabled nghttpx with Dockerfile 2021-09-18 18:08:40 +09:00
Tatsuhiro Tsujikawa
9a6b623c25 Update doc 2021-09-18 15:19:15 +09:00
Tatsuhiro Tsujikawa
97b36b8c74 make -C 2021-09-17 23:57:26 +09:00
Tatsuhiro Tsujikawa
0df332e7b8 Update doc 2021-09-17 23:53:35 +09:00
Tatsuhiro Tsujikawa
2d7e6fbb11 Update doc 2021-09-17 21:21:42 +09:00
Tatsuhiro Tsujikawa
fd107ab47c nghttpx: Refactor quic 2021-09-17 19:35:31 +09:00
Tatsuhiro Tsujikawa
1320d7efab nghttpx: Do not accept new connection during graceful shutdown period 2021-09-17 18:30:16 +09:00
Tatsuhiro Tsujikawa
7cdc6cfa6d nghttpx: Store Retry in CloseWait to rate limit its transmission 2021-09-17 17:52:05 +09:00
Tatsuhiro Tsujikawa
095ee9683d integration: Adds tests for chunked response 2021-09-16 22:37:33 +09:00
Tatsuhiro Tsujikawa
1e2081a1c5 Fix integration test error 2021-09-16 22:24:53 +09:00
Tatsuhiro Tsujikawa
e167e07a9a nghttpx: Check that HTTP response message finished safely 2021-09-16 22:00:36 +09:00
Tatsuhiro Tsujikawa
f3b9cd8404 bpf: Add workaround for ubuntu 20.04 2021-09-16 20:20:02 +09:00
Tatsuhiro Tsujikawa
8f9744c07b nghttpx: Pass hashed_scid_ to CloseWait 2021-09-15 23:40:46 +09:00
Tatsuhiro Tsujikawa
684a219e39 nghttpx: Tweak close wait handling 2021-09-15 23:07:46 +09:00
Tatsuhiro Tsujikawa
e2e6d827c7 Update bash_completion 2021-09-15 22:55:38 +09:00
Tatsuhiro Tsujikawa
f0108ece6f Update manual pages 2021-09-15 22:55:21 +09:00
Tatsuhiro Tsujikawa
789b7a5ff1 Update doc 2021-09-15 22:50:47 +09:00
Tatsuhiro Tsujikawa
0961295a82 nghttpx: Transform odcid into hashed cid 2021-09-15 22:19:52 +09:00
Tatsuhiro Tsujikawa
fd060eb9f1 nghttpx: Connection ID encryption 2021-09-15 21:31:03 +09:00
Tatsuhiro Tsujikawa
1feeda4514 nghttpx: Fix bug that worker process never exit 2021-09-15 21:00:41 +09:00
Tatsuhiro Tsujikawa
6d29de0f1e Fix compile error 2021-09-14 17:22:25 +09:00
Tatsuhiro Tsujikawa
74162850f0 nghttpx: Compile with the latest nghttp3 2021-09-14 16:45:11 +09:00
Tatsuhiro Tsujikawa
8903bd1e8a nghttpx: Deal with error from ngtcp2_conn_read_pkt 2021-09-13 23:09:38 +09:00
Tatsuhiro Tsujikawa
4b79a4a10d Add message when checking UDP_SEGMENT in linux/udp.h 2021-09-13 21:46:41 +09:00
Tatsuhiro Tsujikawa
8f419a4869 nghttpx: Add --frontend-quic-congestion-controller option 2021-09-13 21:35:46 +09:00
Tatsuhiro Tsujikawa
fcdac50f79 Should run program 2021-09-13 21:19:18 +09:00
Tatsuhiro Tsujikawa
4541134c88 Add missing include 2021-09-13 21:19:00 +09:00
Tatsuhiro Tsujikawa
b5e5972c2a Update doc 2021-09-12 18:11:11 +09:00
Tatsuhiro Tsujikawa
525d59fdf6 Remove util::make_hostport returning std::string 2021-09-12 18:07:54 +09:00
Tatsuhiro Tsujikawa
00f65afe20 nghttpx: Fix incorrect quic frontend address matching 2021-09-12 18:07:54 +09:00
Tatsuhiro Tsujikawa
fc402f5804 Cleanup 2021-09-12 16:55:56 +09:00
Tatsuhiro Tsujikawa
f74b6d9a43 nghttpx: Add --frontend-quic-require-token option 2021-09-12 15:04:54 +09:00
Tatsuhiro Tsujikawa
ccaf2333ca nghttpx: Enable websocket over h3 2021-09-11 17:56:25 +09:00
Tatsuhiro Tsujikawa
0066bf8eed h2load: Cleanup 2021-09-11 17:00:11 +09:00
Tatsuhiro Tsujikawa
bc8f88f5fa Compile with the latest ngtcp2 2021-09-11 16:57:14 +09:00
Tatsuhiro Tsujikawa
10c9d917ad Fix compile error 2021-09-10 22:55:33 +09:00
Tatsuhiro Tsujikawa
cc5f752f2d nghttpx: Use secure random to create websocket nonce 2021-09-10 22:43:03 +09:00
Tatsuhiro Tsujikawa
39b1a51ff4 Compile with the latest ngtcp2 2021-09-09 23:41:27 +09:00
Tatsuhiro Tsujikawa
a2e2e46af3 Build with OpenSSL v3.0.0 2021-09-09 18:35:35 +09:00
Tatsuhiro Tsujikawa
9d53a7e0a6 Fix compile error 2021-09-07 14:55:30 +09:00
Tatsuhiro Tsujikawa
7ea57eaa18 h2load: Add --max-udp-payload-size option 2021-09-07 14:42:35 +09:00
Tatsuhiro Tsujikawa
1657a425c1 Build with the latest ngtcp2 2021-09-07 13:40:41 +09:00
Tatsuhiro Tsujikawa
e929e92245 nghttpx: Fix typo 2021-09-06 20:59:11 +09:00
Tatsuhiro Tsujikawa
5994e48b28 nghttpx: Add more logging for token validation 2021-09-06 20:58:35 +09:00
Tatsuhiro Tsujikawa
50662c9c9e nghttpx: Guard TLS1_3_VERSION 2021-09-06 20:07:38 +09:00
Tatsuhiro Tsujikawa
addd614e94 nghttpx: Add qlog support 2021-09-06 20:06:38 +09:00
Tatsuhiro Tsujikawa
fbb228050a nghttpx: Fix uninitialized dnf fields 2021-09-06 00:12:04 +09:00
Tatsuhiro Tsujikawa
9bda8e266e nghttpx: Remove BoringSSL early data for QUIC for now 2021-09-05 22:37:20 +09:00
Tatsuhiro Tsujikawa
d977005126 nghttpx: Disable session cache for QUIC since it solely uses ticket 2021-09-05 22:36:43 +09:00
Tatsuhiro Tsujikawa
8b579bc7d0 nghttpx: Always renew TLS ticket for TLSv1.3 2021-09-05 22:26:45 +09:00
Tatsuhiro Tsujikawa
ab16a11aa3 nghttpx: Add --frontend-quic-early-data, disable early data by default 2021-09-05 21:39:45 +09:00
Tatsuhiro Tsujikawa
85347e12de nghttpx: Rate limit Stateless Reset transmission 2021-09-05 19:23:50 +09:00
Tatsuhiro Tsujikawa
67afbbbaa6 nghttpx: Use ngtcp2_cid as a hash key 2021-09-05 19:00:26 +09:00
Tatsuhiro Tsujikawa
b743ee21f0 nghttpx: Implement closing and draining state 2021-09-05 18:01:27 +09:00
Tatsuhiro Tsujikawa
72702a042e Cleanup 2021-09-05 17:47:50 +09:00
Tatsuhiro Tsujikawa
649c69fa9e nghttpx: Do not send CONNECTION_CLOSE on idle timeout 2021-09-04 19:04:22 +09:00
Tatsuhiro Tsujikawa
9fd0b87925 Add missing APIDOCS entry 2021-09-04 18:41:13 +09:00
Tatsuhiro Tsujikawa
1c7a001489 bpf: Take into account entire DCID 2021-09-04 18:31:21 +09:00
Tatsuhiro Tsujikawa
47edc33b0d nghttpx: Use ULOG 2021-09-04 17:48:02 +09:00
Tatsuhiro Tsujikawa
2afad0c650 nghttpx: Use ngtcp2_conn_get_client_initial_dcid 2021-09-04 17:43:24 +09:00
Tatsuhiro Tsujikawa
fb53a6a686 Follow the latest ngtcp2 change 2021-09-04 17:37:00 +09:00
Tatsuhiro Tsujikawa
31b5b78dc1 Use switch to avoid many if-else-if 2021-09-04 17:35:33 +09:00
Tatsuhiro Tsujikawa
2f941c7fb3 Update doc 2021-09-04 17:32:57 +09:00
Tatsuhiro Tsujikawa
ba483b4032 Update doc 2021-09-04 17:30:06 +09:00
Tatsuhiro Tsujikawa
977b0ceee4 make clang-format 2021-09-04 17:27:43 +09:00
Tatsuhiro Tsujikawa
fcc20334da Merge pull request #1613 from mkauf/check_pseudo_header_chars
Stricter checks for pseudo-headers :method and :path
2021-09-04 17:26:47 +09:00
Michael Kaufmann
83c063346d Stricter checks for pseudo-headers :method and :path
Check the allowed characters for ":method" (see RFC 7230, section 3.2.6) and
":path". For ":path", the space and tab characters are now forbidden, but
other special characters are still allowed for compatibility reasons.

Update genvchartbl.py so that it generates the same table as in the code.

Fixes #1611
2021-08-31 21:47:35 +02:00
Tatsuhiro Tsujikawa
c2e29ad06f nghttpx: Enforce worker-frontend-connections for QUIC 2021-08-31 19:48:26 +09:00
Tatsuhiro Tsujikawa
9194d40da7 Update bash_completions 2021-08-31 19:24:41 +09:00
Tatsuhiro Tsujikawa
002073ef57 Update manual pages 2021-08-31 19:24:41 +09:00
Tatsuhiro Tsujikawa
ef3066a1bd nghttpx: Update doc 2021-08-31 19:24:41 +09:00
Tatsuhiro Tsujikawa
65db5b94e4 nghttpx: Document "quic" parameter 2021-08-31 19:24:41 +09:00
Tatsuhiro Tsujikawa
3122038c48 Add HTTP/3 documentation 2021-08-31 19:24:41 +09:00
Tatsuhiro Tsujikawa
54fd0efdfe nghttpx: Return error if quic param is specified when quic is disabled 2021-08-31 17:15:44 +09:00
Tatsuhiro Tsujikawa
f0d1e50d5a cmake: Build bpf 2021-08-31 17:15:37 +09:00
Tatsuhiro Tsujikawa
a87ea20b7c configure: Avoid compile failure 2021-08-31 16:49:55 +09:00
Tatsuhiro Tsujikawa
8e7e40d0cc bpf: Remove redundant -g 2021-08-31 16:49:55 +09:00
Tatsuhiro Tsujikawa
de4d4f6609 Fix cmake Systemd warning 2021-08-31 16:49:55 +09:00
Tatsuhiro Tsujikawa
e01d61484d Fix compile error with cmake 2021-08-31 16:49:55 +09:00
Tatsuhiro Tsujikawa
51f83087f2 nghttpx: Add missing HTTP/3 timer handling 2021-08-31 14:19:31 +09:00
Tatsuhiro Tsujikawa
17012654e1 nghttpx: Add HTTP/3 graceful shutdown 2021-08-31 14:06:59 +09:00
Tatsuhiro Tsujikawa
e998d125ab nghttpx: Send CONNECTION_CLOSE if Retry token validation failed 2021-08-31 13:23:52 +09:00
Tatsuhiro Tsujikawa
95601d3179 nghttpx: Utilize the latest ngtcp2 features 2021-08-31 12:13:06 +09:00
Tatsuhiro Tsujikawa
0566a5833b nghttpx: Fix infinite loop 2021-08-30 18:39:28 +09:00
Tatsuhiro Tsujikawa
c50459b81a bpf: use __builtin_memcpy explicitly to build under ubuntu 20.04 2021-08-30 18:34:26 +09:00
Tatsuhiro Tsujikawa
0e52cf76eb bpf: Add -g flag by default 2021-08-30 18:33:27 +09:00
Tatsuhiro Tsujikawa
0baf725073 Remove unneeded include files 2021-08-30 18:32:58 +09:00
Tatsuhiro Tsujikawa
e77fd7ddb9 Build libbpf on CI 2021-08-29 22:08:42 +09:00
Tatsuhiro Tsujikawa
e5cb5dca61 Fix reuseport_kern.c to work under ubuntu 20.04 2021-08-29 21:09:27 +09:00
Tatsuhiro Tsujikawa
7941b559c5 Fix libbpf configure help message 2021-08-29 21:08:41 +09:00
Tatsuhiro Tsujikawa
58d81dbc52 nghttpx: Send Stateless Reset in response to Short packet only for now 2021-08-29 21:08:41 +09:00
Tatsuhiro Tsujikawa
2b4dc4496f nghttpx: Forward QUIC UDP datagram to lingering worker in graceful shutdown
Forward QUIC UDP datagram to lingering worker process which is in
graceful shutdown.  Both SIGHUP and SIGUSR2 work.  To make this work
correctly, eBPF is required.
2021-08-29 18:35:41 +09:00
Tatsuhiro Tsujikawa
c5e9d0096a nghttpx: Fix crash when ConnectionHandler is deleted while doing memcached request 2021-08-29 17:17:36 +09:00
Tatsuhiro Tsujikawa
c6f9780b1b Add accidentally deleted BPFCFLAGS 2021-08-29 15:47:45 +09:00
Tatsuhiro Tsujikawa
ef694923f7 Provide enum bpf_stats_type if not defined in linux/bpf.h for older kernel 2021-08-29 14:30:59 +09:00
Tatsuhiro Tsujikawa
8d02203bb6 Add LIBBPF_CFLAGS for eBPF program and nghttpx 2021-08-29 13:58:10 +09:00
Tatsuhiro Tsujikawa
1e75be3b5d Find libbpf with pkg-config 2021-08-29 13:43:07 +09:00
Tatsuhiro Tsujikawa
7d13891066 nghttpx: Rename eBPF options 2021-08-27 21:34:18 +09:00
Tatsuhiro Tsujikawa
4292bd7ad9 nghttpx: Set max udp payload size to IPv4 minimum payload size for now 2021-08-27 21:26:50 +09:00
Tatsuhiro Tsujikawa
82cd110dbe nghttpx: Use SHRPX_MAX_UDP_PAYLOAD_SIZE 2021-08-27 21:13:26 +09:00
Tatsuhiro Tsujikawa
d2729193c7 nghttpx: Add --frontend-http3-max-concurrent-streams option 2021-08-27 21:11:03 +09:00
Tatsuhiro Tsujikawa
87fb325357 nghttpx: Add window size options for HTTP/3 connection 2021-08-27 21:02:45 +09:00
Tatsuhiro Tsujikawa
fb8ff7b892 nghttpx: Format duration for frontend-quic-idle-timeout default value 2021-08-27 19:52:24 +09:00
Tatsuhiro Tsujikawa
5aeae7444f nghttpx: Add --frontend-quic-debug-log option 2021-08-27 19:16:25 +09:00
Tatsuhiro Tsujikawa
c9b11e9fbf nghttpx: Rename --quic-idle-timeout to --frontend-quic-idle-timeout 2021-08-27 19:03:06 +09:00
Tatsuhiro Tsujikawa
0005efa508 nghttpx: --frontend-http3-read-timeout should be noop if HTTP/3 is disabled 2021-08-27 18:45:19 +09:00
Tatsuhiro Tsujikawa
6931cb9d65 nghttpx: Add --quic-idle-timeout option 2021-08-27 18:44:33 +09:00
Tatsuhiro Tsujikawa
c1bcf0f11a nghttpx: Do not dump HTTP/3 header fields 2021-08-27 18:35:27 +09:00
Tatsuhiro Tsujikawa
717e7ae8b2 nghttpx: Add --frontend-http3-read-timeout option
Add --frontend-http3-read-timeout option.  QUIC idle timeout option
will be added later.
2021-08-27 18:29:06 +09:00
Tatsuhiro Tsujikawa
bed00fb8e1 nghttpx: Use buf.size() 2021-08-27 18:20:17 +09:00
Tatsuhiro Tsujikawa
2010401b81 nghttpx: Send APPLICATION_CLOSE on app read timeout 2021-08-27 18:19:44 +09:00
Tatsuhiro Tsujikawa
23e09e3b3c Mention libbpf-dev in README.rst 2021-08-26 22:12:54 +09:00
Tatsuhiro Tsujikawa
80c9d46b70 Update doc 2021-08-26 22:10:02 +09:00
Tatsuhiro Tsujikawa
0aa107426c Bump QUIC flavored OpenSSL 2021-08-26 21:41:06 +09:00
Tatsuhiro Tsujikawa
1517c77d9c h2load: Do not use legacy QUIC transport_parameters code point 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
51bf79bb8c nghttpx: Add --http2-altsvc option 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
d88eadff13 nghttpx: Make sure each quic frontend endpoint has a unique address 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
0d35e8e15e nghttpx: Do not allow quic on UNIX domain socket for now 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
a0066a1ccf nghttpx: Send NEW_TOKEN and very token from client 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
7a5082e8c4 nghttpx: Clean up confusing dcid/scid mixup 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
dfc345756c nghttpx: Send Retry packet 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
137da6adf6 nghttpx: Generate and set QUIC secrets 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
8563ec5a7a nghttpx: Add options to specify eBPF program file path and disable eBPF 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
8ac4bee3bc nghttpx: Add eBPF program to steer QUIC datagram to a correct socket 2021-08-26 21:34:49 +09:00
Tatsuhiro Tsujikawa
579fb478b5 nghttpx: Fix heap-use-after-free on initialization failure 2021-08-26 13:26:37 +09:00
Tatsuhiro Tsujikawa
33c580ebbf Forward QUIC packet to the correct worker 2021-08-23 22:21:48 +09:00
Tatsuhiro Tsujikawa
ff389b3e97 Merge branch 'quic' 2021-08-23 18:41:35 +09:00
Tatsuhiro Tsujikawa
50fe8e7852 Check the availability of SSL_is_quic 2021-08-22 23:59:09 +09:00
Tatsuhiro Tsujikawa
cdb6d19989 Enable HTTP/3 build for cmake on CI 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
29694e2945 nghttpx: Fix build error regarding RAND_bytes 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
9fe08d3913 nghttpx: Fix build without mruby 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
c07a0d9005 Allow HTTP/3 in cmake build 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
cbd45478e0 Cleanup flags/libs order 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
6f243108e9 nghttpx: Fix CI build error 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
0dcdf7ae21 Run http3 build on CI 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
e7ef2bec8b Rename h2load Dockerfile to Dockerfile-h2load-http3 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
4f4dce82c6 Update h2load Dockerfile 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
a619e7a88c Define UDP_SEGMENT if linux/udp.h has it 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
102d960106 nghttpx: Compile without UDP_SEGMENT 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
7de71b29a0 Update doc 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
4eced8a393 Build without HTTP/3 support 2021-08-22 23:54:29 +09:00
Tatsuhiro Tsujikawa
710b9c35e5 Merge pull request #1610 from amirlivneh/comment-typo
Fix reference to non-existing nghttp2_option_set_max_send_header_block_size() in comment
2021-08-22 23:35:05 +09:00
Tatsuhiro Tsujikawa
f46984d218 nghttpx: Enable QUIC 0RTT 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
44663a7e6e nghttpx: Handle backend reset and early response 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
446124f378 nghttpx: Process request body 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
c45f2085d5 nghttpx: Fix veccnt assertion 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
3abf62b41a nghttpx: Send stateless reset token in TP 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
9b2982510e nghttpx: Send stateless reset 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
48bb1ebe01 nghttpx: Add configuration to enable ngtcp2 logging (no cmd-line opt yet) 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
fe4c6e4c56 nghttpx: Generate stateless reset secret 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
37bd9ffc48 nghttpx: Implement http_reset_stream and http_send_stop_sending 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
b0548b4944 nghttpx: Complete HTTP request and response 2021-08-21 18:34:08 +09:00
Tatsuhiro Tsujikawa
12425556c1 nghttpx: Extend Downstream stream_id to 64 bits 2021-08-21 18:34:07 +09:00
Tatsuhiro Tsujikawa
3ed2da562b nghttpx: Add HTTP3 skeleton and minor SSL_CTX fix 2021-08-21 18:34:07 +09:00
Tatsuhiro Tsujikawa
354f46d8c5 nghttpx: Add QUIC timeouts 2021-08-21 18:34:07 +09:00
Tatsuhiro Tsujikawa
e70f0db83c nghttpx: QUIC handshake now works 2021-08-21 18:34:07 +09:00
Tatsuhiro Tsujikawa
49b8c56fde nghttpx: Use existing QUIC error object 2021-08-21 18:34:07 +09:00
Tatsuhiro Tsujikawa
940fdd5573 nghttpx: Read quic packet 2021-08-21 18:34:04 +09:00
Tatsuhiro Tsujikawa
ef53db201e nghttpx: Create QUIC SSL_CTX
We choose an easier route to duplicate SSL_CTX for QUIC.
2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
aeb0b0728d nghttpx: Add QUICConnectionHandler and HTTP3Upstream skeleton 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
8b2746abf1 nghttpx: Add QUICListener 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
01da060496 nghttpx: Create quic server socket 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
20cbd269c4 Compile with the latest ngtcp2 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
7c2cd43dfa Compile with the latest ngtcp2 and nghttp3 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
de5feff720 Compile with the latest nghttp3 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
7342de837d Compile with the latest ngtcp2 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
aa2c648918 Just use h3 ALPN 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
e914b50d16 Compile with the latest ngtcp2 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
f79554f918 Count outgoing packets 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
213cc9c4b5 Enlarge receive buffer 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
05f3b8fa0f Adopt ngtcp2_crypto_recv_crypto_data_cb 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
bc53624133 Do not specify max_udp_payload_size for now 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
5944d034da Avoid std::ostringstream 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
df400feb61 make clang-format 2021-08-21 18:33:39 +09:00
Hajime Fujita
48e10c57da h2load: Add qlog output support 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
1eb818b64c QUIC UDP GSO 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
0954932091 Rewrite docker file
Rewrite docker file so that:

- avoid k8s debian-base
- build h2load as statically as possible
2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
e584d9cd2e Measure the number of UDP datagrams sent and received 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
4d140ea6bd Update Dockerfile 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
09a2e50fc2 Support both h3 and h3-29 ALPN and their corresponding QUIC versions 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
35d8ef33ef Compile with the latest ngtcp2 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
f1ff2af47a Deal with 0 length HTTP data write case 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
d2d2c31ec7 Follow ngtcp2_conn_writev_stream specification change 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
95102c1c6c Compile with the latest ngtcp2 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
fa8c16ae01 Compile with the latest ngtcp2 and nghttp3 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
7ca2a8213d h2load: Enable --data for HTTP/3 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
1c8e5046e5 Compile with the latest ngtcp2 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
68a5652733 Build with draft-32 openssl 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
6b4be30c64 Cap --window-bits to 26 for QUIC 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
6ce952ad4a Set X25519 as default 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
5ae62dd9d7 Cap --window-bits to 23 for QUIC 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
51987107a2 Compile with the latest ngtcp2 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
e4a8c4813c Compile with the latest ngtcp2 2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
3d708f7dc4 Compile with the latest ngtcp2 2021-08-21 18:33:39 +09:00
George Liu
4b5bcb56bc fix quic branch Dockerfile
libjemalloc1 package doesn't exist as it's now libjemalloc2 named

Get:1 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
Get:2 http://deb.debian.org/debian buster InRelease [121 kB]
Get:3 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
Get:4 http://security.debian.org/debian-security buster/updates/main amd64 Packages [213 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 Packages [7905 kB]
Get:6 http://deb.debian.org/debian buster-updates/main amd64 Packages [7868 B]
Fetched 8364 kB in 1s (6499 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
E: Unable to locate package libjemalloc1

fix reference to OpenSSL 1.1.1 branch

Cloning into 'openssl'...
warning: Could not find remote branch OpenSSL_1_1_1d-quic-draft-29 to clone.
fatal: Remote branch OpenSSL_1_1_1d-quic-draft-29 not found in upstream origin
2021-08-21 18:33:39 +09:00
Tatsuhiro Tsujikawa
10ec8c9558 Compile with the latest ngtcp2 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
3900f758ea QUIC needs termination without session 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
a3346fbad8 Compile with latest ngtcp2 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
f73d58d74e quic draft-29 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
813d5e1ddf Compile with latest ngtcp2 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
acb661df72 Fix bug for platform which does not have SOCK_NONBLOCK 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
4bc7710de9 Fix compile error 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
b8c1f4f138 Compile with latest ngtcp2 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
387b67472c Compile latest ngtcp2 crypto lib 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
b2c099bac6 Use ngtcp2_conn_handle_expiry 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
1acebb1cc4 draft-28 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
8d89a8dcb0 Assert ndatalen 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
a60a34331b Revert "Ensure complete packet is written"
This reverts commit c19046b09f8e66713f0e067f986ed92d676eb6b6.
2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
749015eb86 Ensure complete packet is written 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
4b45142e72 Fix compile error with the latest ngtcp2 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
76009ce7b9 draft-27 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
2722119776 Handle stream limit increment 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
c724585bce Update Dockerfile 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
0b61e46f95 draft-25 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
5c0da486b9 Remove unused member function declaration 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
9701e5e6e4 Fix compile error 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
1684091234 Bump base image and use OpenSSL_1_1_1d-quic-draft-24 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
a93eb8b8f5 Optimize QUIC write 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
c591ab5e6f Only count STREAM data as bytes_total 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
b3fbebed55 Use correct type 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
4621f88441 Follow ngtcp2 API update 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
747edb3a99 quic draft-24 2021-08-21 18:33:38 +09:00
Dmitri Tikhonov
558970e281 Update Dockerfile to use I-D 23 branches of ngtcp2 and openssl 2021-08-21 18:33:38 +09:00
Lucas Pardue
73fd20a608 Add SSLKEYLOGFILE support 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
78c2c33b9e Compile with the latest ngtcp2 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
610add1f59 Send SNI 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
655510ce28 h3-23 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
f7414700f4 Small adjustment of successful HTTP/3 error code
Non-zero successful error code is a bit annoying because ngtcp2 does
not know it.  Enforcing successful application error code to 0 is a
lot simpler.
2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
53a860a5bf Simplify write_quic 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
1aae450303 Handle sending just fine 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
b3a2f8837c Avoid setting 0 to repeat field 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
33d2a93294 Add missing acked_stream_data_offset callback 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
2da0db70de Fix return value 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
8b5cbf8066 Update doc 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
9668563801 Update docker build and doc 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
ff7067f3a3 Compile with the latest ngtcp2 and ngtcp2_crypto_openssl 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
6b8b152444 Remove error handling which does not happen 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
3dbe3b3e7f Follow ngtcp2 API changes and use libngtcp2_crypto_openssl 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
7aa4bff97b quic: Support TLS_AES_128_CCM_SHA256 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
6002fac9f1 h2load: Add --tls13-ciphers option 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
231c6ac862 Add Dockerfile 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
c3eb7e1634 Handle preferred address 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
05a6ee2b49 Show ngtcp2 debug log with --verbose 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
94d76c042d h2load: Add --groups option 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
23ccaa6191 Always call write_quic when timer expires 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
476e9d0a48 h3-22 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
7cd5ed6fc6 Handle Retry 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
750c23f319 quic: Configure settings with options 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
bb36df8b2e h2load: Fix possible deadlock 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
470c43a986 Fix link 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
8ea78e8361 Add build instruction 2021-08-21 18:33:38 +09:00
Tatsuhiro Tsujikawa
9c748d20d5 [WIP] Add QUIC to h2load 2021-08-21 18:33:38 +09:00
Amir Livneh
af15b22b03 Fix reference to non-existing nghttp2_option_set_max_send_header_block_size() in comment 2021-08-19 13:14:58 -04:00
Tatsuhiro Tsujikawa
80c9c705b8 Merge pull request #1607 from nghttp2/dnf
Add "dnf" (= "do not forward") parameter to backend option
2021-08-14 17:35:20 +09:00
Tatsuhiro Tsujikawa
138419d232 Add "dnf" (= "do not forward") parameter to backend option 2021-08-14 17:16:21 +09:00
Tatsuhiro Tsujikawa
8cee15bc5a Merge pull request #1603 from JackyYin/improve-doc
update doc for nghttp2_session_mem_recv
2021-08-10 21:25:41 +09:00
Jacky_Yin
8113974b26 doc: update document for nghttp2_session_mem_recv 2021-08-09 23:54:07 +08:00
Tatsuhiro Tsujikawa
2b70cefd48 Merge pull request #1598 from danbev/programmers_guide_typo
Fix typo in programmers-guide.rst
2021-08-08 15:49:43 +09:00
Tatsuhiro Tsujikawa
16054d4bfd Merge pull request #1602 from lhuang04/file_read_callback_prototype_mismatch
Fix prototype mismatch for function 'file_read_callback'
2021-08-08 15:48:55 +09:00
lhuang04
c2d4a53b67 Fix prototype mismatch for function 'file_read_callback'
Summary:
The [data_flags](https://github.com/lhuang04/nghttp2/blob/master/src/HttpServer.cc#L1078) is defined as `uint32_t*` in definition, but delared as [int*](https://github.com/lhuang04/nghttp2/blob/master/src/HttpServer.h#L245) in the prototype.

```
stderr: error: no previous prototype for function 'file_read_callback' [-Werror,-Wmissing-prototypes]
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
        ^
```

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:
2021-08-07 07:24:21 -07:00
Tatsuhiro Tsujikawa
29cbf8b83f clang-format-12 2021-08-04 15:04:58 +09:00
Daniel Bevenius
3448b1c78c Fix typo in programmers-guide.rst 2021-07-26 14:44:15 +02:00
Tatsuhiro Tsujikawa
31253f400d Update manual pages 2021-07-18 14:08:52 +09:00
Tatsuhiro Tsujikawa
1b6f547948 Replace mater remnants with main in nghttpx manual 2021-07-18 14:02:52 +09:00
Tatsuhiro Tsujikawa
deb68b414a Bump up version number to v1.45.0-DEV 2021-07-18 13:16:42 +09:00
Tatsuhiro Tsujikawa
b799b063f8 Update manual pages 2021-07-18 12:45:33 +09:00
Tatsuhiro Tsujikawa
368014b8dd Bump version number to v1.44.0, LT revision to 34:2:20 2021-07-18 12:40:51 +09:00
Tatsuhiro Tsujikawa
fa16e66a6d nghttpx: Fix max distance in weight group/address cycle comparison 2021-07-14 23:26:33 +09:00
Tatsuhiro Tsujikawa
40af31da4c nghttpx: Set connect_blocker and live_check after shuffling addresses 2021-07-14 23:09:28 +09:00
Tatsuhiro Tsujikawa
9e6c0685a2 Fix build failure 2021-05-15 13:51:24 +09:00
Tatsuhiro Tsujikawa
ebad3d4755 Port new ngtcp2 map implementation 2021-05-13 15:01:58 +09:00
Tatsuhiro Tsujikawa
d4fd0681ef Bump llhttp to 6.0.2 2021-05-13 14:06:17 +09:00
Tatsuhiro Tsujikawa
43a47aa08b Do not return HPE_USER from where it is prohibited 2021-05-13 13:59:44 +09:00
Tatsuhiro Tsujikawa
20079b4c2f Update bash_completions 2021-04-02 22:35:37 +09:00
Tatsuhiro Tsujikawa
2aeec7703e Update manual pages 2021-04-02 22:35:37 +09:00
Tatsuhiro Tsujikawa
cef458c31c Replace black-list with block-list
nghttpx --no-http2-cipher-black-list and
--client-no-http2-cipher-black-list are deprecated and replaced with
--no-http2-cipher-block-list and --client-no-http2-cipher-block-list
respectively.
2021-04-02 22:35:37 +09:00
Tatsuhiro Tsujikawa
617a5766a2 Replace master with main 2021-04-02 22:08:19 +09:00
Tatsuhiro Tsujikawa
f1d6733554 Initialize Config rps field 2021-03-10 13:45:20 +09:00
Tatsuhiro Tsujikawa
5f3bcb1f58 Add precious variables for libev and jemalloc and use JEMALLOC_CFLAGS 2021-03-06 22:32:17 +09:00
Tatsuhiro Tsujikawa
b419bfd95f Remove unused field 2021-02-24 20:58:15 +09:00
Tatsuhiro Tsujikawa
e406a2c15e Update doc 2021-02-23 17:41:27 +09:00
Tatsuhiro Tsujikawa
962a75c45e Merge pull request #1559 from nghttp2/h2load-rps
h2load: Add --rps option
2021-02-23 17:08:01 +09:00
Tatsuhiro Tsujikawa
6cdc13d6c6 h2load: Add --rps option 2021-02-23 16:40:17 +09:00
Tatsuhiro Tsujikawa
92944f7847 h2load: Allow unit in -D option 2021-02-23 15:31:54 +09:00
Tatsuhiro Tsujikawa
276792a812 Remove unnecessary function
on_stream_close is called after on_frame_not_send_callback with
success=false without this function.
2021-02-23 14:32:43 +09:00
Tatsuhiro Tsujikawa
579fa6ea93 Add more --with-* configure flags 2021-02-21 21:42:15 +09:00
Tatsuhiro Tsujikawa
2f2b211766 Add LIBTOOL_LDFLAGS configure variable 2021-02-21 21:32:48 +09:00
Tatsuhiro Tsujikawa
88a3cb51af Bump llhttp to 4.0.0 2021-02-18 18:46:23 +09:00
Tatsuhiro Tsujikawa
40679cf638 Merge pull request #1553 from nghttp2/nghttpx-fix-accesslog-method
nghttpx: Remove trailing white space after $method log variable
2021-02-08 23:02:19 +09:00
Tatsuhiro Tsujikawa
5b587e8578 Merge pull request #1550 from jktjkt/docs-asio-fix-typos
docs: asio: fix some typos
2021-02-08 22:29:03 +09:00
Tatsuhiro Tsujikawa
50a1121d81 nghttpx: Remove trailing white space after $method log variable 2021-02-08 22:22:05 +09:00
Tatsuhiro Tsujikawa
3239c5efcc Bump up version number to v1.44.0-DEV 2021-02-02 20:39:12 +09:00
Tatsuhiro Tsujikawa
fb0bd22979 Update manual pages 2021-02-02 19:34:21 +09:00
Tatsuhiro Tsujikawa
3dc6c0afa2 Bump version number to 1.43.0 2021-02-02 19:28:14 +09:00
Tatsuhiro Tsujikawa
e8762781a7 Update AUTHORS 2021-02-02 19:26:08 +09:00
Tatsuhiro Tsujikawa
2bf841e22a workflow: Build with UBSAN enabled 2021-01-17 17:41:01 +09:00
Jan Kundrát
5b9892a902 docs: asio: fix some typos
Really just a s/pusedo/pseudo/g and s/exluced/excluded/g.
2021-01-15 00:39:39 +01:00
Tatsuhiro Tsujikawa
7ebab98e91 Merge pull request #1548 from nghttp2/py3-bindings
Py3 bindings
2020-12-29 19:09:35 +09:00
Tatsuhiro Tsujikawa
23fc6cc900 Bump Linux runner OS to ubuntu 20.04 2020-12-29 18:33:50 +09:00
Tatsuhiro Tsujikawa
2e35cdea6c Update doc 2020-12-29 18:27:07 +09:00
Tatsuhiro Tsujikawa
22af8e782b Require python3 for python bindings 2020-12-29 18:24:41 +09:00
Tatsuhiro Tsujikawa
c88e910009 Update ax_python_devel.m4 2020-12-29 18:24:41 +09:00
Tatsuhiro Tsujikawa
43ba312593 Merge pull request #1547 from nghttp2/sphinx-v3.3
Sphinx v3.3
2020-12-29 18:15:35 +09:00
Tatsuhiro Tsujikawa
3c17299a92 Update enum references 2020-12-29 17:47:57 +09:00
Tatsuhiro Tsujikawa
a7ecff657c Make doc generation work with sphinx v3.3 2020-12-29 17:47:57 +09:00
Tatsuhiro Tsujikawa
79a4f789a1 Merge pull request #1546 from nghttp2/py3-scripts
Python3 development scripts
2020-12-29 17:47:04 +09:00
Tatsuhiro Tsujikawa
28ba0b37e1 Update document reference 2020-12-29 17:35:55 +09:00
Tatsuhiro Tsujikawa
6b7ade9f3f Require python3 for python scripts 2020-12-29 17:35:55 +09:00
Tatsuhiro Tsujikawa
465367294f Bump clang-format to 10 2020-12-28 11:45:44 +09:00
Tatsuhiro Tsujikawa
563c117303 Merge pull request #1544 from nghttp2/nghttpx-clear-mcpool
nghttpx: Make sure that Pool gets cleared when all buffers are returned
2020-12-16 23:50:39 +09:00
Tatsuhiro Tsujikawa
1c04ca8032 Merge pull request #1540 from tavrez/patch-1
Added new nghttp2_ksl.c to Windows makefile
2020-12-16 23:31:33 +09:00
Tatsuhiro Tsujikawa
d32e20bcaa nghttpx: Make sure that Pool gets cleared when all buffers are returned 2020-12-16 23:27:58 +09:00
Tatsuhiro Tsujikawa
8b8ba6b0a6 Merge pull request #1542 from nghttp2/nghttpx-check-sigalg
nghttpx: Choose ECDSA cert if compatible signature algorithm available
2020-12-14 23:00:52 +09:00
Tatsuhiro Tsujikawa
81fb015391 nghttpx: Choose ECDSA cert if compatible signature algorithm available 2020-12-13 23:40:43 +09:00
Reza Tavakoli
d8c71d5fdb Added new nghttp2_ksl.c to Windows makefile 2020-12-02 17:38:03 +03:30
Tatsuhiro Tsujikawa
fb5b5aef0a Merge pull request #1537 from nghttp2/nghttpx-allow-colon-in-pattern
nghttpx: Add workaround to include ':' in backend pattern
2020-11-27 23:35:27 +09:00
Tatsuhiro Tsujikawa
6787423edc nghttpx: Add workaround to include ':' in backend pattern 2020-11-27 22:15:46 +09:00
Tatsuhiro Tsujikawa
ffcdf5dfbc Merge pull request #1533 from LorenzNickel/patch-1
Fix typo in security.rst
2020-11-24 00:51:14 +09:00
Lorenz Nickel
0cdb173846 Fix typo in security.rst 2020-11-23 16:39:49 +01:00
Tatsuhiro Tsujikawa
c9d5472ffb Bump version number to 1.43.0-DEV 2020-11-23 23:54:19 +09:00
Tatsuhiro Tsujikawa
15bd71ed94 Update manual pages 2020-11-23 23:38:21 +09:00
Tatsuhiro Tsujikawa
a76b7a37fd Bump version number to 1.42.0, LT revision to 34:1:20 2020-11-23 23:22:49 +09:00
Tatsuhiro Tsujikawa
5cdf9ce19b Update AUTHORS 2020-11-23 23:19:58 +09:00
Tatsuhiro Tsujikawa
0fba09246b Build with GitHub Actions 2020-11-16 21:22:03 +09:00
164 changed files with 15659 additions and 3538 deletions

View File

@@ -2,16 +2,18 @@
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands: true
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
@@ -21,12 +23,14 @@ AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
@@ -36,11 +40,14 @@ BraceWrapping:
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
@@ -56,27 +63,43 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
StatementAttributeLikeMacros:
- Q_EMIT
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: AfterHash
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
@@ -86,6 +109,7 @@ MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
@@ -96,31 +120,46 @@ PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

View File

@@ -8,9 +8,16 @@ jobs:
strategy:
matrix:
os: [ubuntu-18.04, macos-10.15]
os: [ubuntu-20.04, macos-10.15]
compiler: [gcc, clang]
buildtool: [autotools, cmake]
http3: [http3, no-http3]
openssl: [openssl1, openssl3]
exclude:
- os: macos-10.15
openssl: openssl3
- http3: no-http3
openssl: openssl3
steps:
- uses: actions/checkout@v2
@@ -34,10 +41,11 @@ jobs:
libjansson-dev \
libjemalloc-dev \
libc-ares-dev \
libelf-dev \
cmake \
cmake-data
echo 'CPPFLAGS=-fsanitize=address' >> $GITHUB_ENV
echo 'LDFLAGS=-fsanitize=address' >> $GITHUB_ENV
echo 'CPPFLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -g' >> $GITHUB_ENV
echo 'LDFLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined' >> $GITHUB_ENV
- name: MacOS setup
if: runner.os == 'macOS'
run: |
@@ -52,8 +60,6 @@ jobs:
pkg-config \
libtool
echo 'PKG_CONFIG_PATH=/usr/local/opt/libressl/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig' >> $GITHUB_ENV
# This fixes infamous 'stdio.h not found' error.
echo 'SDKROOT='"$(xcrun --sdk macosx --show-sdk-path)" >> $GITHUB_ENV
- name: Setup clang (Linux)
if: runner.os == 'Linux' && matrix.compiler == 'clang'
run: |
@@ -74,26 +80,93 @@ jobs:
run: |
echo 'CC=gcc' >> $GITHUB_ENV
echo 'CXX=g++' >> $GITHUB_ENV
- name: Build libbpf
if: matrix.http3 == 'http3' && matrix.compiler == 'clang' && runner.os == 'Linux'
run: |
git clone -b v0.4.0 https://github.com/libbpf/libbpf
cd libbpf
PREFIX=$PWD/build make -C src install
EXTRA_AUTOTOOLS_OPTS="--with-libbpf"
echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
- name: Build quictls/openssl v1.1.1
if: matrix.http3 == 'http3' && matrix.openssl == 'openssl1'
run: |
git clone --depth 1 -b OpenSSL_1_1_1l+quic https://github.com/quictls/openssl
cd openssl
./config enable-tls1_3 --prefix=$PWD/build
make -j$(nproc)
make install_sw
- name: Build quictls/openssl v3.0.0
if: matrix.http3 == 'http3' && matrix.openssl == 'openssl3'
run: |
unset CPPFLAGS
unset LDFLAGS
git clone --depth 1 -b openssl-3.0.0+quic https://github.com/quictls/openssl
cd openssl
./config enable-tls1_3 --prefix=$PWD/build --libdir=$PWD/build/lib
make -j$(nproc)
make install_sw
- name: Build nghttp3
if: matrix.http3 == 'http3'
run: |
git clone https://github.com/ngtcp2/nghttp3
cd nghttp3
autoreconf -i
./configure --prefix=$PWD/build --enable-lib-only
make -j$(nproc) check
make install
- name: Build ngtcp2
if: matrix.http3 == 'http3'
run: |
git clone https://github.com/ngtcp2/ngtcp2
cd ngtcp2
autoreconf -i
./configure --prefix=$PWD/build --enable-lib-only PKG_CONFIG_PATH="../openssl/build/lib/pkgconfig"
make -j$(nproc) check
make install
- name: Setup extra environment variables for HTTP/3
if: matrix.http3 == 'http3'
run: |
PKG_CONFIG_PATH="$PWD/openssl/build/lib/pkgconfig:$PWD/nghttp3/build/lib/pkgconfig:$PWD/ngtcp2/build/lib/pkgconfig:$PWD/libbpf/build/lib64/pkgconfig:$PKG_CONFIG_PATH"
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/openssl/build/lib -Wl,-rpath,$PWD/libbpf/build/lib64"
EXTRA_AUTOTOOLS_OPTS="--enable-http3 $EXTRA_AUTOTOOLS_OPTS"
echo 'PKG_CONFIG_PATH='"$PKG_CONFIG_PATH" >> $GITHUB_ENV
echo 'LDFLAGS='"$LDFLAGS" >> $GITHUB_ENV
echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
echo 'EXTRA_CMAKE_OPTS=-DENABLE_HTTP3=ON' >> $GITHUB_ENV
- name: Setup git submodules
run: |
git submodule update --init
- name: Configure autotools
if: matrix.buildtool == 'autotools'
run: |
autoreconf -i
./configure --enable-werror --with-mruby
./configure
- name: Configure cmake
if: matrix.buildtool == 'cmake'
run: |
cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1 -DCPPFLAGS="$CPPFLAGS" -DLDFLAGS="$LDFLAGS" .
make dist
VERSION=$(grep PACKAGE_VERSION config.h | cut -d' ' -f3 | tr -d '"')
tar xf nghttp2-$VERSION.tar.gz
cd nghttp2-$VERSION
echo 'NGHTTP2_CMAKE_DIR='"$PWD" >> $GITHUB_ENV
# This fixes infamous 'stdio.h not found' error.
echo 'SDKROOT='"$(xcrun --sdk macosx --show-sdk-path)" >> $GITHUB_ENV
cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1 -DENABLE_APP=1 $EXTRA_CMAKE_OPTS -DCPPFLAGS="$CPPFLAGS" -DLDFLAGS="$LDFLAGS" .
- name: Build nghttp2 with autotools
if: matrix.buildtool == 'autotools'
run: |
make distcheck \
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --enable-werror CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --with-libev --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
- name: Build nghttp2 with cmake
if: matrix.buildtool == 'cmake'
run: |
cd $NGHTTP2_CMAKE_DIR
make
make check
- name: Integration test
@@ -101,5 +174,5 @@ jobs:
# artifacts.
if: matrix.buildtool == 'cmake'
run: |
cd integration-tests
cd $NGHTTP2_CMAKE_DIR/integration-tests
make itprep it

11
AUTHORS
View File

@@ -19,6 +19,7 @@ Alek Storm
Alex Nalivko
Alexandros Konstantinakis-Karmis
Alexis La Goutte
Amir Livneh
Amir Pakdel
Anders Bakken
Andreas Pohl
@@ -27,17 +28,20 @@ Andy Davies
Angus Gratton
Anna Henningsen
Ant Bryan
Asra Ali
Benedikt Christoph Wolters
Benjamin Peterson
Bernard Spil
Brendan Heinonen
Brian Card
Brian Suh
Daniel Bevenius
Daniel Evers
Daniel Stenberg
Dave Reisner
David Beitey
David Weekly
Dmitri Tikhonov
Dmitriy Vetutnev
Don
Dylan Plecki
@@ -47,9 +51,12 @@ Fabian Wiesel
Gabi Davar
Gaël PORTAY
Geoff Hill
George Liu
Gitai
Google Inc.
Hajime Fujita
Jacky Tian
Jacky_Yin
Jacob Champion
James M Snell
Jan Kundrát
@@ -69,11 +76,13 @@ Kit Chan
Kyle Schomp
LazyHamster
Leo Neat
Lorenz Nickel
Lucas Pardue
MATSUMOTO Ryosuke
Marc Bachmann
Matt Rudary
Matt Way
Michael Kaufmann
Mike Conlen
Mike Frysinger
Mike Lothian
@@ -104,6 +113,7 @@ Tatsuhiko Kubo
Tatsuhiro Tsujikawa
Tobias Geerinckx-Rice
Tom Harwood
Tomas Krizek
Tomasz Buchert
Tomasz Torcz
Vernon Tang
@@ -124,6 +134,7 @@ es
fangdingjun
jwchoi
kumagi
lhuang04
lstefani
makovich
mod-h2-dev

View File

@@ -24,13 +24,13 @@
cmake_minimum_required(VERSION 3.0)
# XXX using 1.8.90 instead of 1.9.0-DEV
project(nghttp2 VERSION 1.41.90)
project(nghttp2 VERSION 1.45.1)
# See versioning rule:
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
set(LT_CURRENT 34)
set(LT_CURRENT 35)
set(LT_REVISION 0)
set(LT_AGE 20)
set(LT_AGE 21)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
include(Version)
@@ -61,6 +61,10 @@ find_package(OpenSSL 1.0.1)
find_package(Libev 4.11)
find_package(Libcares 1.7.5)
find_package(ZLIB 1.2.3)
find_package(Libngtcp2 0.0.0)
find_package(Libngtcp2_crypto_openssl 0.0.0)
find_package(Libnghttp3 0.0.0)
find_package(Libbpf 0.4.0)
if(OPENSSL_FOUND AND LIBEV_FOUND AND ZLIB_FOUND)
set(ENABLE_APP_DEFAULT ON)
else()
@@ -182,9 +186,18 @@ if(HAVE_CUNIT)
endif()
# openssl (for src)
include(CheckSymbolExists)
set(HAVE_OPENSSL ${OPENSSL_FOUND})
if(OPENSSL_FOUND)
set(OPENSSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})
cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}")
check_symbol_exists(SSL_is_quic "openssl/ssl.h" HAVE_SSL_IS_QUIC)
if(NOT HAVE_SSL_IS_QUIC)
message(WARNING "OpenSSL in ${OPENSSL_LIBRARIES} dose not have SSL_is_quic. HTTP/3 support cannot be enabled")
endif()
cmake_pop_check_state()
else()
set(OPENSSL_INCLUDE_DIRS "")
set(OPENSSL_LIBRARIES "")
@@ -223,11 +236,31 @@ if(ENABLE_ASIO_LIB)
find_package(Boost 1.54.0 REQUIRED system thread)
endif()
# libbpf (for bpf)
set(HAVE_LIBBPF ${LIBBPF_FOUND})
if(LIBBPF_FOUND)
set(BPFCFLAGS -Wall -O2 -g)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# For Debian/Ubuntu
set(EXTRABPFCFLAGS -I/usr/include/${CMAKE_SYSTEM_PROCESSOR}-linux-gnu)
endif()
check_c_source_compiles("
#include <linux/bpf.h>
int main() { enum bpf_stats_type foo; (void)foo; }" HAVE_BPF_STATS_TYPE)
endif()
# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL and libev
if(ENABLE_APP AND NOT (ZLIB_FOUND AND OPENSSL_FOUND AND LIBEV_FOUND))
message(FATAL_ERROR "Applications were requested (ENABLE_APP=1) but dependencies are not met.")
endif()
# HTTP/3 requires quictls/openssl, libngtcp2, libngtcp2_crypto_openssl
# and libnghttp3.
if(ENABLE_HTTP3 AND NOT (HAVE_SSL_IS_QUIC AND LIBNGTCP2_FOUND AND LIBNGTCP2_CRYPTO_OPENSSL_FOUND AND LIBNGHTTP3_FOUND))
message(FATAL_ERROR "HTTP/3 was requested (ENABLE_HTTP3=1) but dependencies are not met.")
endif()
# HPACK tools requires jansson
if(ENABLE_HPACK_TOOLS AND NOT HAVE_JANSSON)
message(FATAL_ERROR "HPACK tools were requested (ENABLE_HPACK_TOOLS=1) but dependencies are not met.")
@@ -448,11 +481,16 @@ foreach(name
configure_file("${name}.in" "${name}" @ONLY)
endforeach()
if(APPLE)
add_definitions(-D__APPLE_USE_RFC_3542)
endif()
include_directories(
"${CMAKE_CURRENT_BINARY_DIR}" # for config.h
)
# For use in src/CMakeLists.txt
set(PKGDATADIR "${CMAKE_INSTALL_FULL_DATADIR}/${CMAKE_PROJECT_NAME}")
set(PKGLIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}/${CMAKE_PROJECT_NAME}")
install(FILES README.rst DESTINATION "${CMAKE_INSTALL_DOCDIR}")
@@ -469,6 +507,7 @@ add_subdirectory(integration-tests)
add_subdirectory(doc)
add_subdirectory(contrib)
add_subdirectory(script)
add_subdirectory(bpf)
string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type)
@@ -499,6 +538,10 @@ message(STATUS "summary of build options:
Libxml2: ${HAVE_LIBXML2} (LIBS='${LIBXML2_LIBRARIES}')
Libev: ${HAVE_LIBEV} (LIBS='${LIBEV_LIBRARIES}')
Libc-ares: ${HAVE_LIBCARES} (LIBS='${LIBCARES_LIBRARIES}')
Libngtcp2: ${HAVE_LIBNGTCP2} (LIBS='${LIBNGTCP2_LIBRARIES}')
Libngtcp2_crypto_openssl: ${HAVE_LIBNGTCP2_CRYPTO_OPENSSL} (LIBS='${LIBNGTCP2_CRYPTO_OPENSSL_LIBRARIES}')
Libnghttp3: ${HAVE_LIBNGHTTP3} (LIBS='${LIBNGHTTP3_LIBRARIES}')
Libbpf: ${HAVE_LIBBPF} (LIBS='${LIBBPF_LIBRARIES}')
Libevent(SSL): ${HAVE_LIBEVENT_OPENSSL} (LIBS='${LIBEVENT_OPENSSL_LIBRARIES}')
Jansson: ${HAVE_JANSSON} (LIBS='${JANSSON_LIBRARIES}')
Jemalloc: ${HAVE_JEMALLOC} (LIBS='${JEMALLOC_LIBRARIES}')
@@ -517,6 +560,7 @@ message(STATUS "summary of build options:
Examples: ${ENABLE_EXAMPLES}
Python bindings:${ENABLE_PYTHON_BINDINGS}
Threading: ${ENABLE_THREADS}
HTTP/3(EXPERIMENTAL): ${ENABLE_HTTP3}
")
if(ENABLE_LIB_ONLY_DISABLED_OTHERS)
message("Only the library will be built. To build other components "

View File

@@ -17,6 +17,7 @@ option(ENABLE_LIB_ONLY "Build libnghttp2 only. This is a short hand for -DENAB
option(ENABLE_STATIC_LIB "Build libnghttp2 in static mode also")
option(ENABLE_SHARED_LIB "Build libnghttp2 as a shared library" ON)
option(ENABLE_STATIC_CRT "Build libnghttp2 against the MS LIBCMT[d]")
option(ENABLE_HTTP3 "Enable HTTP/3 support" OFF)
option(WITH_LIBXML2 "Use libxml2"
${WITH_LIBXML2_DEFAULT})

View File

@@ -20,7 +20,7 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = lib third-party src examples python tests integration-tests \
SUBDIRS = lib third-party src bpf examples python tests integration-tests \
doc contrib script
# Now with python setuptools, make uninstall will leave many files we
@@ -46,7 +46,11 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make \
cmake/FindLibevent.cmake \
cmake/FindJansson.cmake \
cmake/FindLibcares.cmake \
cmake/FindSystemd.cmake
cmake/FindSystemd.cmake \
cmake/FindLibbpf.cmake \
cmake/FindLibnghttp3.cmake \
cmake/FindLibngtcp2.cmake \
cmake/FindLibngtcp2_crypto_openssl.cmake
.PHONY: clang-format

View File

@@ -112,7 +112,7 @@ libnghttp2_asio C++ library requires the following packages:
The Python bindings require the following packages:
* cython >= 0.19
* python >= 2.7
* python >= 3.8
* python-setuptools
If you are using Ubuntu 16.04 LTS (Xenial Xerus) or Debian 8 (jessie)
@@ -145,6 +145,31 @@ minimizes the risk of private key leakage when serious bug like
Heartbleed is exploited. The neverbleed is disabled by default. To
enable it, use ``--with-neverbleed`` configure option.
To enable the experimental HTTP/3 support for h2load and nghttpx, the
following libraries are required:
* `OpenSSL with QUIC support
<https://github.com/quictls/openssl/tree/OpenSSL_1_1_1k+quic>`_
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_
Use ``--enable-http3`` configure option to enable HTTP/3 feature for
h2load and nghttpx.
In order to build optional eBPF program to direct an incoming QUIC UDP
datagram to a correct socket for nghttpx, the following libraries are
required:
* libbpf-dev >= 0.4.0
Use ``--with-libbpf`` configure option to build eBPF program.
libelf-dev is needed to build libbpf.
For Ubuntu 20.04, you can build libbpf from `the source code
<https://github.com/libbpf/libbpf/releases/tag/v0.4.0>`_. nghttpx
requires eBPF program for reloading its configuration and hot swapping
its executable.
Compiling libnghttp2 C source code requires a C99 compiler. gcc 4.8
is known to be adequate. In order to compile the C++ source code, gcc
>= 6.0 or clang >= 6.0 is required. C++ source code requires C++14
@@ -307,6 +332,88 @@ The generated documents will not be installed with ``make install``.
The online documentation is available at
https://nghttp2.org/documentation/
Build HTTP/3 enabled h2load and nghttpx
---------------------------------------
To build h2load and nghttpx with HTTP/3 feature enabled, run the
configure script with ``--enable-http3``.
For nghttpx to reload configurations and swapping its executable while
gracefully terminating old worker processes, eBPF is required. Run
the configure script with ``--enable-http3 --with-libbpf`` to build
eBPF program. The Connection ID encryption key must be set with
``--frontend-quic-connection-id-encryption-key`` and must not change
in order to keep the existing connections alive during reload.
The detailed steps to build HTTP/3 enabled h2load and nghttpx follow.
Build custom OpenSSL:
.. code-block:: text
$ git clone --depth 1 -b OpenSSL_1_1_1l+quic https://github.com/quictls/openssl
$ cd openssl
$ ./config --prefix=$PWD/build --openssldir=/etc/ssl
$ make -j$(nproc)
$ make install_sw
$ cd ..
Build nghttp3:
.. code-block:: text
$ git clone --depth 1 https://github.com/ngtcp2/nghttp3
$ cd nghttp3
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
$ make -j$(nproc)
$ make install
$ cd ..
Build ngtcp2:
.. code-block:: text
$ git clone --depth 1 https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only \
PKG_CONFIG_PATH="$PWD/../openssl/build/lib/pkgconfig"
$ make -j$(nproc)
$ make install
$ cd ..
If your Linux distribution does not have libbpf-dev >= 0.4.0, build
from source:
.. code-block:: text
$ git clone --depth 1 -b v0.4.0 https://github.com/libbpf/libbpf
$ cd libbpf
$ PREFIX=$PWD/build make -C src install
$ cd ..
Build nghttp2:
.. code-block:: text
$ git clone https://github.com/nghttp2/nghttp2
$ cd nghttp2
$ git submodule update --init
$ autoreconf -i
$ ./configure --with-mruby --with-neverbleed --enable-http3 --with-libbpf \
--disable-python-bindings \
CC=clang-12 CXX=clang++-12 \
PKG_CONFIG_PATH="$PWD/../openssl/build/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig:$PWD/../ngtcp2/build/lib/pkgconfig:$PWD/../libbpf/build/lib64/pkgconfig" \
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../openssl/build/lib -Wl,-rpath,$PWD/../libbpf/build/lib64"
$ make -j$(nproc)
The eBPF program ``reuseport_kern.o`` should be found under bpf
directory. Pass ``--quic-bpf-program-file=bpf/reuseport_kern.o``
option to nghttpx to load it. See also `HTTP/3 section in nghttpx -
HTTP/2 proxy - HOW-TO
<https://nghttp2.org/documentation/nghttpx-howto.html#http-3>`_.
Unit tests
----------
@@ -734,7 +841,7 @@ information. Here is sample output from ``nghttpd``:
nghttpx - proxy
+++++++++++++++
``nghttpx`` is a multi-threaded reverse proxy for HTTP/2, and
``nghttpx`` is a multi-threaded reverse proxy for HTTP/3, HTTP/2, and
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server
push.
@@ -755,16 +862,16 @@ ticket keys among multiple ``nghttpx`` instances via memcached.
``nghttpx`` has 2 operation modes:
================== ================ ================ =============
Mode option Frontend Backend Note
================== ================ ================ =============
default mode HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Reverse proxy
``--http2-proxy`` HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Forward proxy
================== ================ ================ =============
================== ======================== ================ =============
Mode option Frontend Backend Note
================== ======================== ================ =============
default mode HTTP/3, HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Reverse proxy
``--http2-proxy`` HTTP/3, HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Forward proxy
================== ======================== ================ =============
The interesting mode at the moment is the default mode. It works like
a reverse proxy and listens for HTTP/2, and HTTP/1.1 and can be
deployed as a SSL/TLS terminator for existing web server.
a reverse proxy and listens for HTTP/3, HTTP/2, and HTTP/1.1 and can
be deployed as a SSL/TLS terminator for existing web server.
In all modes, the frontend connections are encrypted by SSL/TLS by
default. To disable encryption, use the ``no-tls`` keyword in
@@ -782,16 +889,16 @@ server:
.. code-block:: text
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Web Server
[reverse proxy]
Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Web Server
[reverse proxy]
With the ``--http2-proxy`` option, it works as forward proxy, and it
is so called secure HTTP/2 proxy:
.. code-block:: text
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
[secure proxy] (e.g., Squid, ATS)
Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
[secure proxy] (e.g., Squid, ATS)
The ``Client`` in the above example needs to be configured to use
``nghttpx`` as secure proxy.
@@ -823,7 +930,7 @@ proxy through an HTTP proxy:
.. code-block:: text
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
--===================---> HTTP/2 Proxy
(HTTP proxy tunnel) (e.g., nghttpx -s)
@@ -831,8 +938,8 @@ proxy through an HTTP proxy:
Benchmarking tool
-----------------
The ``h2load`` program is a benchmarking tool for HTTP/2. The UI of
``h2load`` is heavily inspired by ``weighttp``
The ``h2load`` program is a benchmarking tool for HTTP/3, HTTP/2, and
HTTP/1.1. The UI of ``h2load`` is heavily inspired by ``weighttp``
(https://github.com/lighttpd/weighttp). The typical usage is as
follows:
@@ -875,6 +982,14 @@ threads to avoid saturating a single core on client side.
considered a DOS attack. Please only use it against your private
servers.
If the experimental HTTP/3 is enabled, h2load can send requests to
HTTP/3 server. To do this, specify ``h3`` to ``--npn-list`` option
like so:
.. code-block:: text
$ h2load --npn-list h3 https://127.0.0.1:4433
HPACK tools
-----------
@@ -1422,7 +1537,7 @@ The extension module is called ``nghttp2``.
determined by the ``configure`` script. If the detected Python version is not
what you expect, specify a path to Python executable in a ``PYTHON``
variable as an argument to configure script (e.g., ``./configure
PYTHON=/usr/bin/python3.5``).
PYTHON=/usr/bin/python3.8``).
The following example code illustrates basic usage of the HPACK compressor
and decompressor in Python:
@@ -1494,7 +1609,7 @@ BaseRequestHandler usage:
.. code-block:: python
#!/usr/bin/env python
#!/usr/bin/env python3
import io, ssl
import nghttp2

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# script to extract commit author's name from standard input. The
# input should be <AUTHOR>:<EMAIL>, one per line.
@@ -49,4 +49,4 @@ for name in names:
ndict[lowname] = name
for name in sorted(ndict.values()):
print name
print(name)

13
bpf/CMakeLists.txt Normal file
View File

@@ -0,0 +1,13 @@
if(LIBBPF_FOUND)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/reuseport_kern.o"
COMMAND ${CMAKE_C_COMPILER} ${BPFCFLAGS} ${EXTRABPFCFLAGS} -I${LIBBPF_INCLUDE_DIRS} -target bpf -c reuseport_kern.c -o "${CMAKE_CURRENT_BINARY_DIR}/reuseport_kern.o"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
VERBATIM)
add_custom_target(bpf ALL
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/reuseport_kern.o"
VERBATIM)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/reuseport_kern.o"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/${CMAKE_PROJECT_NAME}")
endif()

40
bpf/Makefile.am Normal file
View File

@@ -0,0 +1,40 @@
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2021 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
EXTRA_DIST = CMakeLists.txt reuseport_kern.c
if HAVE_LIBBPF
bpf_pkglibdir = $(pkglibdir)
bpf_pkglib_DATA = reuseport_kern.o
all: $(builddir)/reuseport_kern.o
$(builddir)/reuseport_kern.o: reuseport_kern.c
$(CC) @LIBBPF_CFLAGS@ @BPFCFLAGS@ @EXTRABPFCFLAGS@ \
-target bpf -c $< -o $@
clean-local:
-rm -f reuseport_kern.o
endif # HAVE_LIBBPF

659
bpf/reuseport_kern.c Normal file
View File

@@ -0,0 +1,659 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2021 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <linux/udp.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
/*
* How to compile:
*
* clang-12 -O2 -Wall -target bpf -g -c reuseport_kern.c -o reuseport_kern.o \
* -I/path/to/kernel/include
*
* See
* https://www.kernel.org/doc/Documentation/kbuild/headers_install.txt
* how to install kernel header files.
*/
/* AES_CBC_decrypt_buffer: https://github.com/kokke/tiny-AES-c
License is Public Domain. Commit hash:
12e7744b4919e9d55de75b7ab566326a1c8e7a67 */
#define AES_BLOCKLEN \
16 /* Block length in bytes - AES is 128b block \
only */
#define AES_KEYLEN 16 /* Key length in bytes */
#define AES_keyExpSize 176
struct AES_ctx {
__u8 RoundKey[AES_keyExpSize];
};
/* The number of columns comprising a state in AES. This is a constant
in AES. Value=4 */
#define Nb 4
#define Nk 4 /* The number of 32 bit words in a key. */
#define Nr 10 /* The number of rounds in AES Cipher. */
/* state - array holding the intermediate results during
decryption. */
typedef __u8 state_t[4][4];
/* The lookup-tables are marked const so they can be placed in
read-only storage instead of RAM The numbers below can be computed
dynamically trading ROM for RAM - This can be useful in (embedded)
bootloader applications, where ROM is often limited. */
static const __u8 sbox[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
0xb0, 0x54, 0xbb, 0x16};
static const __u8 rsbox[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
0x55, 0x21, 0x0c, 0x7d};
/* The round constant word array, Rcon[i], contains the values given
by x to the power (i-1) being powers of x (x is denoted as {02}) in
the field GF(2^8) */
static const __u8 Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
0x20, 0x40, 0x80, 0x1b, 0x36};
#define getSBoxValue(num) (sbox[(num)])
/* This function produces Nb(Nr+1) round keys. The round keys are used
in each round to decrypt the states. */
static void KeyExpansion(__u8 *RoundKey, const __u8 *Key) {
unsigned i, j, k;
__u8 tempa[4]; /* Used for the column/row operations */
/* The first round key is the key itself. */
for (i = 0; i < Nk; ++i) {
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
}
/* All other round keys are found from the previous round keys. */
for (i = Nk; i < Nb * (Nr + 1); ++i) {
{
k = (i - 1) * 4;
tempa[0] = RoundKey[k + 0];
tempa[1] = RoundKey[k + 1];
tempa[2] = RoundKey[k + 2];
tempa[3] = RoundKey[k + 3];
}
if (i % Nk == 0) {
/* This function shifts the 4 bytes in a word to the left once.
[a0,a1,a2,a3] becomes [a1,a2,a3,a0] */
/* Function RotWord() */
{
const __u8 u8tmp = tempa[0];
tempa[0] = tempa[1];
tempa[1] = tempa[2];
tempa[2] = tempa[3];
tempa[3] = u8tmp;
}
/* SubWord() is a function that takes a four-byte input word and
applies the S-box to each of the four bytes to produce an
output word. */
/* Function Subword() */
{
tempa[0] = getSBoxValue(tempa[0]);
tempa[1] = getSBoxValue(tempa[1]);
tempa[2] = getSBoxValue(tempa[2]);
tempa[3] = getSBoxValue(tempa[3]);
}
tempa[0] = tempa[0] ^ Rcon[i / Nk];
}
j = i * 4;
k = (i - Nk) * 4;
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
}
}
static void AES_init_ctx(struct AES_ctx *ctx, const __u8 *key) {
KeyExpansion(ctx->RoundKey, key);
}
/* This function adds the round key to state. The round key is added
to the state by an XOR function. */
static void AddRoundKey(__u8 round, state_t *state, const __u8 *RoundKey) {
__u8 i, j;
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
}
}
}
static __u8 xtime(__u8 x) { return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); }
#define Multiply(x, y) \
(((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ \
((y >> 2 & 1) * xtime(xtime(x))) ^ \
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ \
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))))
#define getSBoxInvert(num) (rsbox[(num)])
/* MixColumns function mixes the columns of the state matrix. The
method used to multiply may be difficult to understand for the
inexperienced. Please use the references to gain more
information. */
static void InvMixColumns(state_t *state) {
int i;
__u8 a, b, c, d;
for (i = 0; i < 4; ++i) {
a = (*state)[i][0];
b = (*state)[i][1];
c = (*state)[i][2];
d = (*state)[i][3];
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^
Multiply(d, 0x09);
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^
Multiply(d, 0x0d);
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^
Multiply(d, 0x0b);
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^
Multiply(d, 0x0e);
}
}
extern __u32 LINUX_KERNEL_VERSION __kconfig;
/* The SubBytes Function Substitutes the values in the state matrix
with values in an S-box. */
static void InvSubBytes(state_t *state) {
__u8 i, j;
if (LINUX_KERNEL_VERSION < KERNEL_VERSION(5, 10, 0)) {
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
/* Ubuntu 20.04 LTS kernel 5.4.0 needs this workaround
otherwise "math between map_value pointer and register with
unbounded min value is not allowed". 5.10.0 is a kernel
version that works but it might not be the minimum
version. */
__u8 k = (*state)[j][i];
(*state)[j][i] = k ? getSBoxInvert(k) : getSBoxInvert(0);
}
}
} else {
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
}
}
}
}
static void InvShiftRows(state_t *state) {
__u8 temp;
/* Rotate first row 1 columns to right */
temp = (*state)[3][1];
(*state)[3][1] = (*state)[2][1];
(*state)[2][1] = (*state)[1][1];
(*state)[1][1] = (*state)[0][1];
(*state)[0][1] = temp;
/* Rotate second row 2 columns to right */
temp = (*state)[0][2];
(*state)[0][2] = (*state)[2][2];
(*state)[2][2] = temp;
temp = (*state)[1][2];
(*state)[1][2] = (*state)[3][2];
(*state)[3][2] = temp;
/* Rotate third row 3 columns to right */
temp = (*state)[0][3];
(*state)[0][3] = (*state)[1][3];
(*state)[1][3] = (*state)[2][3];
(*state)[2][3] = (*state)[3][3];
(*state)[3][3] = temp;
}
static void InvCipher(state_t *state, const __u8 *RoundKey) {
/* Add the First round key to the state before starting the
rounds. */
AddRoundKey(Nr, state, RoundKey);
/* There will be Nr rounds. The first Nr-1 rounds are identical.
These Nr rounds are executed in the loop below. Last one without
InvMixColumn() */
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 1, state, RoundKey);
InvMixColumns(state);
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 2, state, RoundKey);
InvMixColumns(state);
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 3, state, RoundKey);
InvMixColumns(state);
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 4, state, RoundKey);
InvMixColumns(state);
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 5, state, RoundKey);
InvMixColumns(state);
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 6, state, RoundKey);
InvMixColumns(state);
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 7, state, RoundKey);
InvMixColumns(state);
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 8, state, RoundKey);
InvMixColumns(state);
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 9, state, RoundKey);
InvMixColumns(state);
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(Nr - 10, state, RoundKey);
}
static void AES_ECB_decrypt(const struct AES_ctx *ctx, __u8 *buf) {
/* The next function call decrypts the PlainText with the Key using
AES algorithm. */
InvCipher((state_t *)buf, ctx->RoundKey);
}
/* rol32: From linux kernel source code */
/**
* rol32 - rotate a 32-bit value left
* @word: value to rotate
* @shift: bits to roll
*/
static inline __u32 rol32(__u32 word, unsigned int shift) {
return (word << shift) | (word >> ((-shift) & 31));
}
/* jhash.h: Jenkins hash support.
*
* Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
*
* https://burtleburtle.net/bob/hash/
*
* These are the credits from Bob's sources:
*
* lookup3.c, by Bob Jenkins, May 2006, Public Domain.
*
* These are functions for producing 32-bit hashes for hash table lookup.
* hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
* are externally useful functions. Routines to test the hash are included
* if SELF_TEST is defined. You can use this free for any purpose. It's in
* the public domain. It has no warranty.
*
* Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* I've modified Bob's hash to be useful in the Linux kernel, and
* any bugs present are my fault.
* Jozsef
*/
/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
#define __jhash_final(a, b, c) \
{ \
c ^= b; \
c -= rol32(b, 14); \
a ^= c; \
a -= rol32(c, 11); \
b ^= a; \
b -= rol32(a, 25); \
c ^= b; \
c -= rol32(b, 16); \
a ^= c; \
a -= rol32(c, 4); \
b ^= a; \
b -= rol32(a, 14); \
c ^= b; \
c -= rol32(b, 24); \
}
/* __jhash_nwords - hash exactly 3, 2 or 1 word(s) */
static inline __u32 __jhash_nwords(__u32 a, __u32 b, __u32 c, __u32 initval) {
a += initval;
b += initval;
c += initval;
__jhash_final(a, b, c);
return c;
}
/* An arbitrary initial parameter */
#define JHASH_INITVAL 0xdeadbeef
static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval) {
return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2));
}
struct bpf_map_def SEC("maps") cid_prefix_map = {
.type = BPF_MAP_TYPE_HASH,
.max_entries = 255,
.key_size = sizeof(__u64),
.value_size = sizeof(__u32),
};
struct bpf_map_def SEC("maps") reuseport_array = {
.type = BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
.max_entries = 255,
.key_size = sizeof(__u32),
.value_size = sizeof(__u32),
};
struct bpf_map_def SEC("maps") sk_info = {
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 3,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
};
typedef struct quic_hd {
__u8 *dcid;
__u32 dcidlen;
__u32 dcid_offset;
__u8 type;
} quic_hd;
#define SV_DCIDLEN 20
#define MAX_DCIDLEN 20
#define MIN_DCIDLEN 8
#define CID_PREFIXLEN 8
enum {
NGTCP2_PKT_INITIAL = 0x0,
NGTCP2_PKT_0RTT = 0x1,
NGTCP2_PKT_HANDSHAKE = 0x2,
NGTCP2_PKT_SHORT = 0x40,
};
static inline int parse_quic(quic_hd *qhd, __u8 *data, __u8 *data_end) {
__u8 *p;
__u64 dcidlen;
if (*data & 0x80) {
p = data + 1 + 4;
/* Do not check the actual DCID length because we might not buffer
entire DCID here. */
dcidlen = *p;
if (dcidlen > MAX_DCIDLEN || dcidlen < MIN_DCIDLEN) {
return -1;
}
++p;
qhd->type = (*data & 0x30) >> 4;
qhd->dcid = p;
qhd->dcidlen = dcidlen;
qhd->dcid_offset = 6;
} else {
qhd->type = NGTCP2_PKT_SHORT;
qhd->dcid = data + 1;
qhd->dcidlen = SV_DCIDLEN;
qhd->dcid_offset = 1;
}
return 0;
}
static __u32 hash(const __u8 *data, __u32 datalen, __u32 initval) {
__u32 a, b;
a = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
b = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
return jhash_2words(a, b, initval);
}
static __u32 sk_index_from_dcid(const quic_hd *qhd,
const struct sk_reuseport_md *reuse_md,
__u64 num_socks) {
__u32 len = qhd->dcidlen;
__u32 h = reuse_md->hash;
__u8 hbuf[8];
if (len > 16) {
__builtin_memset(hbuf, 0, sizeof(hbuf));
switch (len) {
case 20:
__builtin_memcpy(hbuf, qhd->dcid + 16, 4);
break;
case 19:
__builtin_memcpy(hbuf, qhd->dcid + 16, 3);
break;
case 18:
__builtin_memcpy(hbuf, qhd->dcid + 16, 2);
break;
case 17:
__builtin_memcpy(hbuf, qhd->dcid + 16, 1);
break;
}
h = hash(hbuf, sizeof(hbuf), h);
len = 16;
}
if (len > 8) {
__builtin_memset(hbuf, 0, sizeof(hbuf));
switch (len) {
case 16:
__builtin_memcpy(hbuf, qhd->dcid + 8, 8);
break;
case 15:
__builtin_memcpy(hbuf, qhd->dcid + 8, 7);
break;
case 14:
__builtin_memcpy(hbuf, qhd->dcid + 8, 6);
break;
case 13:
__builtin_memcpy(hbuf, qhd->dcid + 8, 5);
break;
case 12:
__builtin_memcpy(hbuf, qhd->dcid + 8, 4);
break;
case 11:
__builtin_memcpy(hbuf, qhd->dcid + 8, 3);
break;
case 10:
__builtin_memcpy(hbuf, qhd->dcid + 8, 2);
break;
case 9:
__builtin_memcpy(hbuf, qhd->dcid + 8, 1);
break;
}
h = hash(hbuf, sizeof(hbuf), h);
len = 8;
}
return hash(qhd->dcid, len, h) % num_socks;
}
SEC("sk_reuseport")
int select_reuseport(struct sk_reuseport_md *reuse_md) {
__u32 sk_index, *psk_index;
__u64 *pnum_socks, *pkey;
__u32 zero = 0, key_high_idx = 1, key_low_idx = 2;
int rv;
quic_hd qhd;
__u8 qpktbuf[6 + MAX_DCIDLEN];
struct AES_ctx aes_ctx;
__u8 key[AES_KEYLEN];
if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr), qpktbuf,
sizeof(qpktbuf)) != 0) {
return SK_DROP;
}
pnum_socks = bpf_map_lookup_elem(&sk_info, &zero);
if (pnum_socks == NULL) {
return SK_DROP;
}
pkey = bpf_map_lookup_elem(&sk_info, &key_high_idx);
if (pkey == NULL) {
return SK_DROP;
}
__builtin_memcpy(key, pkey, sizeof(*pkey));
pkey = bpf_map_lookup_elem(&sk_info, &key_low_idx);
if (pkey == NULL) {
return SK_DROP;
}
__builtin_memcpy(key + sizeof(*pkey), pkey, sizeof(*pkey));
rv = parse_quic(&qhd, qpktbuf, qpktbuf + sizeof(qpktbuf));
if (rv != 0) {
return SK_DROP;
}
AES_init_ctx(&aes_ctx, key);
switch (qhd.type) {
case NGTCP2_PKT_INITIAL:
case NGTCP2_PKT_0RTT:
if (qhd.dcidlen == SV_DCIDLEN) {
AES_ECB_decrypt(&aes_ctx, qhd.dcid);
psk_index = bpf_map_lookup_elem(&cid_prefix_map, qhd.dcid);
if (psk_index != NULL) {
sk_index = *psk_index;
break;
}
}
sk_index = sk_index_from_dcid(&qhd, reuse_md, *pnum_socks);
break;
case NGTCP2_PKT_HANDSHAKE:
case NGTCP2_PKT_SHORT:
if (qhd.dcidlen != SV_DCIDLEN) {
return SK_DROP;
}
AES_ECB_decrypt(&aes_ctx, qhd.dcid);
psk_index = bpf_map_lookup_elem(&cid_prefix_map, qhd.dcid);
if (psk_index == NULL) {
sk_index = sk_index_from_dcid(&qhd, reuse_md, *pnum_socks);
break;
}
sk_index = *psk_index;
break;
default:
return SK_DROP;
}
rv = bpf_sk_select_reuseport(reuse_md, &reuseport_array, &sk_index, 0);
if (rv != 0) {
return SK_DROP;
}
return SK_PASS;
}

32
cmake/FindLibbpf.cmake Normal file
View File

@@ -0,0 +1,32 @@
# - Try to find libbpf
# Once done this will define
# LIBBPF_FOUND - System has libbpf
# LIBBPF_INCLUDE_DIRS - The libbpf include directories
# LIBBPF_LIBRARIES - The libraries needed to use libbpf
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBBPF QUIET libbpf)
find_path(LIBBPF_INCLUDE_DIR
NAMES bpf/bpf.h
HINTS ${PC_LIBBPF_INCLUDE_DIRS}
)
find_library(LIBBPF_LIBRARY
NAMES bpf
HINTS ${PC_LIBBPF_LIBRARY_DIRS}
)
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBBPF_FOUND
# to TRUE if all listed variables are TRUE and the requested version
# matches.
find_package_handle_standard_args(Libbpf REQUIRED_VARS
LIBBPF_LIBRARY LIBBPF_INCLUDE_DIR
VERSION_VAR LIBBPF_VERSION)
if(LIBBPF_FOUND)
set(LIBBPF_LIBRARIES ${LIBBPF_LIBRARY})
set(LIBBPF_INCLUDE_DIRS ${LIBBPF_INCLUDE_DIR})
endif()
mark_as_advanced(LIBBPF_INCLUDE_DIR LIBBPF_LIBRARY)

View File

@@ -0,0 +1,41 @@
# - Try to find libnghttp3
# Once done this will define
# LIBNGHTTP3_FOUND - System has libnghttp3
# LIBNGHTTP3_INCLUDE_DIRS - The libnghttp3 include directories
# LIBNGHTTP3_LIBRARIES - The libraries needed to use libnghttp3
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBNGHTTP3 QUIET libnghttp3)
find_path(LIBNGHTTP3_INCLUDE_DIR
NAMES nghttp3/nghttp3.h
HINTS ${PC_LIBNGHTTP3_INCLUDE_DIRS}
)
find_library(LIBNGHTTP3_LIBRARY
NAMES nghttp3
HINTS ${PC_LIBNGHTTP3_LIBRARY_DIRS}
)
if(LIBNGHTTP3_INCLUDE_DIR)
set(_version_regex "^#define[ \t]+NGHTTP3_VERSION[ \t]+\"([^\"]+)\".*")
file(STRINGS "${LIBNGHTTP3_INCLUDE_DIR}/nghttp3/version.h"
LIBNGHTTP3_VERSION REGEX "${_version_regex}")
string(REGEX REPLACE "${_version_regex}" "\\1"
LIBNGHTTP3_VERSION "${LIBNGHTTP3_VERSION}")
unset(_version_regex)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBNGHTTP3_FOUND
# to TRUE if all listed variables are TRUE and the requested version
# matches.
find_package_handle_standard_args(Libnghttp3 REQUIRED_VARS
LIBNGHTTP3_LIBRARY LIBNGHTTP3_INCLUDE_DIR
VERSION_VAR LIBNGHTTP3_VERSION)
if(LIBNGHTTP3_FOUND)
set(LIBNGHTTP3_LIBRARIES ${LIBNGHTTP3_LIBRARY})
set(LIBNGHTTP3_INCLUDE_DIRS ${LIBNGHTTP3_INCLUDE_DIR})
endif()
mark_as_advanced(LIBNGHTTP3_INCLUDE_DIR LIBNGHTTP3_LIBRARY)

41
cmake/FindLibngtcp2.cmake Normal file
View File

@@ -0,0 +1,41 @@
# - Try to find libngtcp2
# Once done this will define
# LIBNGTCP2_FOUND - System has libngtcp2
# LIBNGTCP2_INCLUDE_DIRS - The libngtcp2 include directories
# LIBNGTCP2_LIBRARIES - The libraries needed to use libngtcp2
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBNGTCP2 QUIET libngtcp2)
find_path(LIBNGTCP2_INCLUDE_DIR
NAMES ngtcp2/ngtcp2.h
HINTS ${PC_LIBNGTCP2_INCLUDE_DIRS}
)
find_library(LIBNGTCP2_LIBRARY
NAMES ngtcp2
HINTS ${PC_LIBNGTCP2_LIBRARY_DIRS}
)
if(LIBNGTCP2_INCLUDE_DIR)
set(_version_regex "^#define[ \t]+NGTCP2_VERSION[ \t]+\"([^\"]+)\".*")
file(STRINGS "${LIBNGTCP2_INCLUDE_DIR}/ngtcp2/version.h"
LIBNGTCP2_VERSION REGEX "${_version_regex}")
string(REGEX REPLACE "${_version_regex}" "\\1"
LIBNGTCP2_VERSION "${LIBNGTCP2_VERSION}")
unset(_version_regex)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBNGTCP2_FOUND
# to TRUE if all listed variables are TRUE and the requested version
# matches.
find_package_handle_standard_args(Libngtcp2 REQUIRED_VARS
LIBNGTCP2_LIBRARY LIBNGTCP2_INCLUDE_DIR
VERSION_VAR LIBNGTCP2_VERSION)
if(LIBNGTCP2_FOUND)
set(LIBNGTCP2_LIBRARIES ${LIBNGTCP2_LIBRARY})
set(LIBNGTCP2_INCLUDE_DIRS ${LIBNGTCP2_INCLUDE_DIR})
endif()
mark_as_advanced(LIBNGTCP2_INCLUDE_DIR LIBNGTCP2_LIBRARY)

View File

@@ -0,0 +1,43 @@
# - Try to find libngtcp2_crypto_openssl
# Once done this will define
# LIBNGTCP2_CRYPTO_OPENSSL_FOUND - System has libngtcp2_crypto_openssl
# LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIRS - The libngtcp2_crypto_openssl include directories
# LIBNGTCP2_CRYPTO_OPENSSL_LIBRARIES - The libraries needed to use libngtcp2_crypto_openssl
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBNGTCP2_CRYPTO_OPENSSL QUIET libngtcp2_crypto_openssl)
find_path(LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR
NAMES ngtcp2/ngtcp2_crypto_openssl.h
HINTS ${PC_LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIRS}
)
find_library(LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY
NAMES ngtcp2_crypto_openssl
HINTS ${PC_LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY_DIRS}
)
if(LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR)
set(_version_regex "^#define[ \t]+NGTCP2_VERSION[ \t]+\"([^\"]+)\".*")
file(STRINGS "${LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR}/ngtcp2/version.h"
LIBNGTCP2_CRYPTO_OPENSSL_VERSION REGEX "${_version_regex}")
string(REGEX REPLACE "${_version_regex}" "\\1"
LIBNGTCP2_CRYPTO_OPENSSL_VERSION "${LIBNGTCP2_CRYPTO_OPENSSL_VERSION}")
unset(_version_regex)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set
# LIBNGTCP2_CRYPTO_OPENSSL_FOUND to TRUE if all listed variables are
# TRUE and the requested version matches.
find_package_handle_standard_args(Libngtcp2_crypto_openssl REQUIRED_VARS
LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY
LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR
VERSION_VAR LIBNGTCP2_CRYPTO_OPENSSL_VERSION)
if(LIBNGTCP2_CRYPTO_OPENSSL_FOUND)
set(LIBNGTCP2_CRYPTO_OPENSSL_LIBRARIES ${LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY})
set(LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIRS ${LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR})
endif()
mark_as_advanced(LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR
LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY)

View File

@@ -15,5 +15,5 @@ find_library(SYSTEMD_LIBRARIES NAMES systemd ${PC_SYSTEMD_LIBRARY_DIRS})
find_path(SYSTEMD_INCLUDE_DIRS systemd/sd-login.h HINTS ${PC_SYSTEMD_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SYSTEMD DEFAULT_MSG SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES)
find_package_handle_standard_args(Systemd DEFAULT_MSG SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES)
mark_as_advanced(SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES)

View File

@@ -78,3 +78,12 @@
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1
/* Define to 1 if HTTP/3 is enabled. */
#cmakedefine ENABLE_HTTP3 1
/* Define to 1 if you have `libbpf` library. */
#cmakedefine HAVE_LIBBPF 1
/* Define to 1 if you have enum bpf_stats_type in linux/bpf.h. */
#cmakedefine HAVE_BPF_STATS_TYPE 1

View File

@@ -25,7 +25,7 @@ dnl Do not change user variables!
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
AC_PREREQ(2.61)
AC_INIT([nghttp2], [1.42.0-DEV], [t-tujikawa@users.sourceforge.net])
AC_INIT([nghttp2], [1.45.1], [t-tujikawa@users.sourceforge.net])
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
@@ -43,10 +43,10 @@ AM_INIT_AUTOMAKE([subdir-objects])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl See versioning rule:
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 34)
dnl https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 35)
AC_SUBST(LT_REVISION, 0)
AC_SUBST(LT_AGE, 20)
AC_SUBST(LT_AGE, 21)
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
@@ -107,11 +107,51 @@ AC_ARG_ENABLE([lib-only],
[Build libnghttp2 only. This is a short hand for --disable-app --disable-examples --disable-hpack-tools --disable-python-bindings])],
[request_lib_only=$enableval], [request_lib_only=no])
AC_ARG_ENABLE([http3],
[AS_HELP_STRING([--enable-http3],
[(EXPERIMENTAL) Enable HTTP/3. This requires ngtcp2, nghttp3, and a custom OpenSSL.])],
[request_http3=$enableval], [request_http3=no])
AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2],
[Use libxml2 [default=check]])],
[request_libxml2=$withval], [request_libxml2=check])
AC_ARG_WITH([jansson],
[AS_HELP_STRING([--with-jansson],
[Use jansson [default=check]])],
[request_jansson=$withval], [request_jansson=check])
AC_ARG_WITH([zlib],
[AS_HELP_STRING([--with-zlib],
[Use zlib [default=check]])],
[request_zlib=$withval], [request_zlib=check])
AC_ARG_WITH([libevent-openssl],
[AS_HELP_STRING([--with-libevent-openssl],
[Use libevent_openssl [default=check]])],
[request_libevent_openssl=$withval], [request_libevent_openssl=check])
AC_ARG_WITH([libcares],
[AS_HELP_STRING([--with-libcares],
[Use libc-ares [default=check]])],
[request_libcares=$withval], [request_libcares=check])
AC_ARG_WITH([openssl],
[AS_HELP_STRING([--with-openssl],
[Use openssl [default=check]])],
[request_openssl=$withval], [request_openssl=check])
AC_ARG_WITH([libev],
[AS_HELP_STRING([--with-libev],
[Use libev [default=check]])],
[request_libev=$withval], [request_libev=check])
AC_ARG_WITH([cunit],
[AS_HELP_STRING([--with-cunit],
[Use cunit [default=check]])],
[request_cunit=$withval], [request_cunit=check])
AC_ARG_WITH([jemalloc],
[AS_HELP_STRING([--with-jemalloc],
[Use jemalloc [default=check]])],
@@ -137,9 +177,36 @@ AC_ARG_WITH([cython],
[Use cython in given PATH])],
[cython_path=$withval], [])
AC_ARG_WITH([libngtcp2],
[AS_HELP_STRING([--with-libngtcp2],
[Use libngtcp2 [default=check]])],
[request_libngtcp2=$withval], [request_libngtcp2=check])
AC_ARG_WITH([libnghttp3],
[AS_HELP_STRING([--with-libnghttp3],
[Use libnghttp3 [default=check]])],
[request_libnghttp3=$withval], [request_libnghttp3=check])
AC_ARG_WITH([libbpf],
[AS_HELP_STRING([--with-libbpf],
[Use libbpf [default=no]])],
[request_libbpf=$withval], [request_libbpf=no])
dnl Define variables
AC_ARG_VAR([CYTHON], [the Cython executable])
AC_ARG_VAR([LIBEV_CFLAGS], [C compiler flags for libev, skipping any checks])
AC_ARG_VAR([LIBEV_LIBS], [linker flags for libev, skipping any checks])
AC_ARG_VAR([JEMALLOC_CFLAGS],
[C compiler flags for jemalloc, skipping any checks])
AC_ARG_VAR([JEMALLOC_LIBS], [linker flags for jemalloc, skipping any checks])
AC_ARG_VAR([LIBTOOL_LDFLAGS],
[libtool specific flags (e.g., -static-libtool-libs)])
AC_ARG_VAR([BPFCFLAGS], [C compiler flags for bpf program])
dnl Checks for programs
AC_PROG_CC
AC_PROG_CXX
@@ -151,7 +218,7 @@ AC_PROG_MKDIR_P
PKG_PROG_PKG_CONFIG([0.20])
AM_PATH_PYTHON([2.7],, [:])
AM_PATH_PYTHON([3.8],, [:])
if [test "x$request_lib_only" = "xyes"]; then
request_app=no
@@ -161,7 +228,7 @@ if [test "x$request_lib_only" = "xyes"]; then
fi
if [test "x$request_python_bindings" != "xno"]; then
AX_PYTHON_DEVEL([>= '2.7'])
AX_PYTHON_DEVEL([>= '3.8'])
fi
if test "x${cython_path}" = "x"; then
@@ -200,6 +267,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
]],
[[
std::vector<std::future<int>> v;
(void)v;
]])],
[AC_DEFINE([HAVE_STD_FUTURE], [1],
[Define to 1 if you have the `std::future`.])
@@ -289,11 +357,26 @@ case "$host_os" in
;;
esac
# zlib
PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.3], [have_zlib=yes], [have_zlib=no])
case "${build}" in
*-apple-darwin*)
EXTRA_DEFS="-D__APPLE_USE_RFC_3542"
AC_SUBST([EXTRA_DEFS])
;;
esac
if test "x${have_zlib}" = "xno"; then
AC_MSG_NOTICE($ZLIB_PKG_ERRORS)
# zlib
have_zlib=no
if test "x${request_zlib}" != "xno"; then
PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.3], [have_zlib=yes], [have_zlib=no])
if test "x${have_zlib}" = "xno"; then
AC_MSG_NOTICE($ZLIB_PKG_ERRORS)
fi
fi
if test "x${request_zlib}" = "xyes" &&
test "x${have_zlib}" != "xyes"; then
AC_MSG_ERROR([zlib was requested (--with-zlib) but not found])
fi
# dl: openssl requires libdl when it is statically linked.
@@ -309,82 +392,242 @@ case "${host_os}" in
esac
# cunit
PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes], [have_cunit=no])
# If pkg-config does not find cunit, check it using AC_CHECK_LIB. We
# do this because Debian (Ubuntu) lacks pkg-config file for cunit.
if test "x${have_cunit}" = "xno"; then
AC_MSG_WARN([${CUNIT_PKG_ERRORS}])
AC_CHECK_LIB([cunit], [CU_initialize_registry],
[have_cunit=yes], [have_cunit=no])
have_cunit=no
if test "x${request_cunit}" != "xno"; then
PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes], [have_cunit=no])
# If pkg-config does not find cunit, check it using AC_CHECK_LIB. We
# do this because Debian (Ubuntu) lacks pkg-config file for cunit.
if test "x${have_cunit}" = "xno"; then
AC_MSG_WARN([${CUNIT_PKG_ERRORS}])
AC_CHECK_LIB([cunit], [CU_initialize_registry],
[have_cunit=yes], [have_cunit=no])
if test "x${have_cunit}" = "xyes"; then
CUNIT_LIBS="-lcunit"
CUNIT_CFLAGS=""
AC_SUBST([CUNIT_LIBS])
AC_SUBST([CUNIT_CFLAGS])
fi
fi
if test "x${have_cunit}" = "xyes"; then
CUNIT_LIBS="-lcunit"
CUNIT_CFLAGS=""
AC_SUBST([CUNIT_LIBS])
AC_SUBST([CUNIT_CFLAGS])
# cunit in Mac OS X requires ncurses. Note that in Mac OS X, test
# program can be built without -lncurses, but it emits runtime
# error.
case "${build}" in
*-apple-darwin*)
CUNIT_LIBS="$CUNIT_LIBS -lncurses"
AC_SUBST([CUNIT_LIBS])
;;
esac
fi
fi
if test "x${have_cunit}" = "xyes"; then
# cunit in Mac OS X requires ncurses. Note that in Mac OS X, test
# program can be built without -lncurses, but it emits runtime
# error.
case "${build}" in
*-apple-darwin*)
CUNIT_LIBS="$CUNIT_LIBS -lncurses"
AC_SUBST([CUNIT_LIBS])
;;
esac
if test "x${request_cunit}" = "xyes" &&
test "x${have_cunit}" != "xyes"; then
AC_MSG_ERROR([cunit was requested (--with-cunit) but not found])
fi
AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ])
# libev (for src)
# libev does not have pkg-config file. Check it in an old way.
save_LIBS=$LIBS
# android requires -lm for floor
AC_CHECK_LIB([ev], [ev_time], [have_libev=yes], [have_libev=no], [-lm])
if test "x${have_libev}" = "xyes"; then
AC_CHECK_HEADER([ev.h], [have_libev=yes], [have_libev=no])
if test "x${have_libev}" = "xyes"; then
LIBEV_LIBS=-lev
LIBEV_CFLAGS=
AC_SUBST([LIBEV_LIBS])
AC_SUBST([LIBEV_CFLAGS])
have_libev=no
if test "x${request_libev}" != "xno"; then
if test "x${LIBEV_LIBS}" = "x" && test "x${LIBEV_CFLAGS}" = "x"; then
# libev does not have pkg-config file. Check it in an old way.
save_LIBS=$LIBS
# android requires -lm for floor
AC_CHECK_LIB([ev], [ev_time], [have_libev=yes], [have_libev=no], [-lm])
if test "x${have_libev}" = "xyes"; then
AC_CHECK_HEADER([ev.h], [have_libev=yes], [have_libev=no])
if test "x${have_libev}" = "xyes"; then
LIBEV_LIBS=-lev
LIBEV_CFLAGS=
fi
fi
LIBS=$save_LIBS
else
have_libev=yes
fi
fi
LIBS=$save_LIBS
if test "x${request_libev}" = "xyes" &&
test "x${have_libev}" != "xyes"; then
AC_MSG_ERROR([libev was requested (--with-libev) but not found])
fi
# openssl (for src)
PKG_CHECK_MODULES([OPENSSL], [openssl >= 1.0.1],
[have_openssl=yes], [have_openssl=no])
if test "x${have_openssl}" = "xno"; then
AC_MSG_NOTICE($OPENSSL_PKG_ERRORS)
have_openssl=no
if test "x${request_openssl}" != "xno"; then
PKG_CHECK_MODULES([OPENSSL], [openssl >= 1.0.1],
[have_openssl=yes], [have_openssl=no])
if test "x${have_openssl}" = "xno"; then
AC_MSG_NOTICE($OPENSSL_PKG_ERRORS)
else
save_CFLAGS="$CFLAGS"
save_LIBS="$LIBS"
CFLAGS="$OPENSSL_CFLAGS $CFLAGS"
LIBS="$OPENSSL_LIBS $LIBS"
have_ssl_is_quic=no
AC_MSG_CHECKING([for SSL_is_quic])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <openssl/ssl.h>
]], [[
SSL *ssl = NULL;
SSL_is_quic(ssl);
]])],
[AC_MSG_RESULT([yes]); have_ssl_is_quic=yes],
[AC_MSG_RESULT([no]); have_ssl_is_quic=no])
CFLAGS="$save_CFLAGS"
LIBS="$save_LIBS"
fi
fi
if test "x${request_openssl}" = "xyes" &&
test "x${have_openssl}" != "xyes"; then
AC_MSG_ERROR([openssl was requested (--with-openssl) but not found])
fi
# c-ares (for src)
PKG_CHECK_MODULES([LIBCARES], [libcares >= 1.7.5], [have_libcares=yes],
[have_libcares=no])
if test "x${have_libcares}" = "xno"; then
AC_MSG_NOTICE($LIBCARES_PKG_ERRORS)
have_libcares=no
if test "x${request_libcares}" != "xno"; then
PKG_CHECK_MODULES([LIBCARES], [libcares >= 1.7.5], [have_libcares=yes],
[have_libcares=no])
if test "x${have_libcares}" = "xno"; then
AC_MSG_NOTICE($LIBCARES_PKG_ERRORS)
fi
fi
if test "x${request_libcares}" = "xyes" &&
test "x${have_libcares}" != "xyes"; then
AC_MSG_ERROR([libcares was requested (--with-libcares) but not found])
fi
# ngtcp2 (for src)
have_libngtcp2=no
if test "x${request_libngtcp2}" != "xno"; then
PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.0.0], [have_libngtcp2=yes],
[have_libngtcp2=no])
if test "x${have_libngtcp2}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS)
fi
fi
if test "x${request_libngtcp2}" = "xyes" &&
test "x${have_libngtcp2}" != "xyes"; then
AC_MSG_ERROR([libngtcp2 was requested (--with-libngtcp2) but not found])
fi
# ngtcp2_crypto_openssl (for src)
have_libngtcp2_crypto_openssl=no
if test "x${request_libngtcp2}" != "xno"; then
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL],
[libngtcp2_crypto_openssl >= 0.0.0],
[have_libngtcp2_crypto_openssl=yes],
[have_libngtcp2_crypto_openssl=no])
if test "x${have_libngtcp2_crypto_openssl}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_OPENSSL_PKG_ERRORS)
fi
fi
if test "x${request_libngtcp2}" = "xyes" &&
test "x${have_libngtcp2_crypto_openssl}" != "xyes"; then
AC_MSG_ERROR([libngtcp2_crypto_openssl was requested (--with-libngtcp2) but not found])
fi
# nghttp3 (for src)
have_libnghttp3=no
if test "x${request_libnghttp3}" != "xno"; then
PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.0.0], [have_libnghttp3=yes],
[have_libnghttp3=no])
if test "x${have_libnghttp3}" = "xno"; then
AC_MSG_NOTICE($LIBNGHTTP3_PKG_ERRORS)
fi
fi
if test "x${request_libnghttp3}" = "xyes" &&
test "x${have_libnghttp3}" != "xyes"; then
AC_MSG_ERROR([libnghttp3 was requested (--with-libnghttp3) but not found])
fi
# libbpf (for src)
have_libbpf=no
if test "x${request_libbpf}" != "xno"; then
PKG_CHECK_MODULES([LIBBPF], [libbpf >= 0.4.0], [have_libbpf=yes],
[have_libbpf=no])
if test "x${have_libbpf}" = "xyes"; then
AC_DEFINE([HAVE_LIBBPF], [1], [Define to 1 if you have `libbpf` library.])
if test "x${BPFCFLAGS}" = "x"; then
BPFCFLAGS="-Wall -O2 -g"
fi
# Add the include path for Debian
EXTRABPFCFLAGS="-I/usr/include/$host_cpu-$host_os"
AC_SUBST([EXTRABPFCFLAGS])
AC_MSG_CHECKING([whether enum bpf_stats_type is defined in linux/bpf.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[
#include <linux/bpf.h>
]],
[[
enum bpf_stats_type foo;
(void)foo;
]])],
[have_bpf_stats_type=yes],
[have_bpf_stats_type=no])
if test "x${have_bpf_stats_type}" = "xyes"; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_BPF_STATS_TYPE], [1],
[Define to 1 if you have enum bpf_stats_type in linux/bpf.h.])
else
AC_MSG_RESULT([no])
fi
else
AC_MSG_NOTICE($LIBBPF_PKG_ERRORS)
fi
fi
if test "x${request_libbpf}" = "xyes" &&
test "x${have_libbpf}" != "xyes"; then
AC_MSG_ERROR([libbpf was requested (--with-libbpf) but not found])
fi
AM_CONDITIONAL([HAVE_LIBBPF], [ test "x${have_libbpf}" = "xyes" ])
# libevent_openssl (for examples)
# 2.0.8 is required because we use evconnlistener_set_error_cb()
PKG_CHECK_MODULES([LIBEVENT_OPENSSL], [libevent_openssl >= 2.0.8],
[have_libevent_openssl=yes], [have_libevent_openssl=no])
if test "x${have_libevent_openssl}" = "xno"; then
AC_MSG_NOTICE($LIBEVENT_OPENSSL_PKG_ERRORS)
have_libevent_openssl=no
if test "x${request_libevent_openssl}" != "xno"; then
PKG_CHECK_MODULES([LIBEVENT_OPENSSL], [libevent_openssl >= 2.0.8],
[have_libevent_openssl=yes], [have_libevent_openssl=no])
if test "x${have_libevent_openssl}" = "xno"; then
AC_MSG_NOTICE($LIBEVENT_OPENSSL_PKG_ERRORS)
fi
fi
if test "x${request_libevent_openssl}" = "xyes" &&
test "x${have_libevent_openssl}" != "xyes"; then
AC_MSG_ERROR([libevent_openssl was requested (--with-libevent) but not found])
fi
# jansson (for src/nghttp, src/deflatehd and src/inflatehd)
PKG_CHECK_MODULES([JANSSON], [jansson >= 2.5],
[have_jansson=yes], [have_jansson=no])
if test "x${have_jansson}" = "xyes"; then
AC_DEFINE([HAVE_JANSSON], [1],
[Define to 1 if you have `libjansson` library.])
else
AC_MSG_NOTICE($JANSSON_PKG_ERRORS)
have_jansson=no
if test "x${request_jansson}" != "xno"; then
PKG_CHECK_MODULES([JANSSON], [jansson >= 2.5],
[have_jansson=yes], [have_jansson=no])
if test "x${have_jansson}" = "xyes"; then
AC_DEFINE([HAVE_JANSSON], [1],
[Define to 1 if you have `libjansson` library.])
else
AC_MSG_NOTICE($JANSSON_PKG_ERRORS)
fi
fi
if test "x${request_jansson}" = "xyes" &&
test "x${have_jansson}" != "xyes"; then
AC_MSG_ERROR([jansson was requested (--with-jansson) but not found])
fi
# libsystemd (for src/nghttpx)
have_libsystemd=no
@@ -405,12 +648,15 @@ if test "x${request_systemd}" = "xyes" &&
fi
# libxml2 (for src/nghttp)
PKG_CHECK_MODULES([LIBXML2], [libxml-2.0 >= 2.6.26],
[have_libxml2=yes], [have_libxml2=no])
if test "x${have_libxml2}" = "xyes"; then
AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have `libxml2` library.])
else
AC_MSG_NOTICE($LIBXML2_PKG_ERRORS)
have_libxml2=no
if test "x${request_libxml2}" != "xno"; then
PKG_CHECK_MODULES([LIBXML2], [libxml-2.0 >= 2.6.26],
[have_libxml2=yes], [have_libxml2=no])
if test "x${have_libxml2}" = "xyes"; then
AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have `libxml2` library.])
else
AC_MSG_NOTICE($LIBXML2_PKG_ERRORS)
fi
fi
if test "x${request_libxml2}" = "xyes" &&
@@ -423,28 +669,31 @@ AM_CONDITIONAL([HAVE_LIBXML2], [ test "x${have_libxml2}" = "xyes" ])
# jemalloc
have_jemalloc=no
if test "x${request_jemalloc}" != "xno"; then
save_LIBS=$LIBS
AC_SEARCH_LIBS([malloc_stats_print], [jemalloc], [have_jemalloc=yes], [],
[$PTHREAD_LDFLAGS])
if test "x${have_jemalloc}" = "xyes"; then
jemalloc_libs=${ac_cv_search_malloc_stats_print}
else
# On Darwin, malloc_stats_print is je_malloc_stats_print
AC_SEARCH_LIBS([je_malloc_stats_print], [jemalloc], [have_jemalloc=yes], [],
if test "x${JEMALLOC_LIBS}" = "x" && test "x${JEMALLOC_CFLAGS}" = "x"; then
save_LIBS=$LIBS
AC_SEARCH_LIBS([malloc_stats_print], [jemalloc], [have_jemalloc=yes], [],
[$PTHREAD_LDFLAGS])
if test "x${have_jemalloc}" = "xyes"; then
jemalloc_libs=${ac_cv_search_je_malloc_stats_print}
jemalloc_libs=${ac_cv_search_malloc_stats_print}
else
# On Darwin, malloc_stats_print is je_malloc_stats_print
AC_SEARCH_LIBS([je_malloc_stats_print], [jemalloc], [have_jemalloc=yes], [],
[$PTHREAD_LDFLAGS])
if test "x${have_jemalloc}" = "xyes"; then
jemalloc_libs=${ac_cv_search_je_malloc_stats_print}
fi
fi
fi
LIBS=$save_LIBS
LIBS=$save_LIBS
if test "x${have_jemalloc}" = "xyes" &&
test "x${jemalloc_libs}" != "xnone required"; then
JEMALLOC_LIBS=${jemalloc_libs}
AC_SUBST([JEMALLOC_LIBS])
if test "x${have_jemalloc}" = "xyes" &&
test "x${jemalloc_libs}" != "xnone required"; then
JEMALLOC_LIBS=${jemalloc_libs}
fi
else
have_jemalloc=yes
fi
fi
@@ -490,6 +739,24 @@ fi
AM_CONDITIONAL([ENABLE_APP], [ test "x${enable_app}" = "xyes" ])
# Check HTTP/3 support
enable_http3=no
if test "x${request_http3}" != "xno" &&
test "x${have_ssl_is_quic}" = "xyes" &&
test "x${have_libngtcp2}" = "xyes" &&
test "x${have_libngtcp2_crypto_openssl}" = "xyes" &&
test "x${have_libnghttp3}" = "xyes"; then
enable_http3=yes
AC_DEFINE([ENABLE_HTTP3], [1], [Define to 1 if HTTP/3 is enabled.])
fi
if test "x${request_http3}" = "xyes" &&
test "x${enable_http3}" != "xyes"; then
AC_MSG_ERROR([HTTP/3 was requested (--enable-http3) but dependencies are not met.])
fi
AM_CONDITIONAL([ENABLE_HTTP3], [ test "x${enable_http3}" = "xyes" ])
enable_hpack_tools=no
# HPACK tools requires jansson
if test "x${request_hpack_tools}" != "xno" &&
@@ -567,7 +834,7 @@ enable_python_bindings=no
if test "x${request_python_bindings}" != "xno" &&
test "x${CYTHON}" != "x" &&
test "x${PYTHON}" != "x:" &&
test "x${have_python_dev}" = "xyes"; then
test "x${PYTHON_VERSION}" != "x"; then
enable_python_bindings=yes
fi
@@ -716,6 +983,34 @@ AC_CHECK_DECLS([initgroups], [], [], [[
#include <grp.h>
]])
have_netinet_udp_h_udp_segment=no
AC_CHECK_DECL([UDP_SEGMENT], [have_netinet_udp_h_udp_segment=yes],
[have_netinet_udp_h_udp_segment=no], [[
#include <netinet/udp.h>
]])
if test "x$have_netinet_udp_h_udp_segment" = "xno"; then
have_linux_udp_h_udp_segment=no
AC_MSG_CHECKING([whether UDP_SEGMENT is defined as 103 in linux/udp.h])
AC_RUN_IFELSE([AC_LANG_PROGRAM(
[[
#include <linux/udp.h>
]],
[[
#if UDP_SEGMENT != 103
exit(1)
#endif
]])],
[have_linux_udp_h_udp_segment=yes
AC_MSG_RESULT([yes])],
[have_linux_udp_h_udp_segment=no
AC_MSG_RESULT([no])])
if test "x$have_linux_udp_h_udp_segment" = "xyes"; then
EXTRA_DEFS="$EXTRA_DEFS -DUDP_SEGMENT=103"
fi
fi
save_CFLAGS=$CFLAGS
save_CXXFLAGS=$CXXFLAGS
@@ -831,6 +1126,7 @@ AC_CONFIG_FILES([
src/Makefile
src/includes/Makefile
src/libnghttp2_asio.pc
bpf/Makefile
examples/Makefile
python/Makefile
python/setup.py
@@ -882,17 +1178,22 @@ AC_MSG_NOTICE([summary of build options:
WARNCXXFLAGS: ${WARNCXXFLAGS}
CXX1XCXXFLAGS: ${CXX1XCXXFLAGS}
EXTRACFLAG: ${EXTRACFLAG}
BPFCFLAGS: ${BPFCFLAGS}
EXTRABPFCFLAGS: ${EXTRABPFCFLAGS}
LIBS: ${LIBS}
DEFS: ${DEFS}
EXTRA_DEFS: ${EXTRA_DEFS}
Library:
Shared: ${enable_shared}
Static: ${enable_static}
Libtool:
LIBTOOL_LDFLAGS: ${LIBTOOL_LDFLAGS}
Python:
Python: ${PYTHON}
PYTHON_VERSION: ${PYTHON_VERSION}
pyexecdir: ${pyexecdir}
Python-dev: ${have_python_dev}
PYTHON_CPPFLAGS:${PYTHON_CPPFLAGS}
PYTHON_LDFLAGS: ${PYTHON_LDFLAGS}
PYTHON_LIBS: ${PYTHON_LIBS}
Cython: ${CYTHON}
Test:
CUnit: ${have_cunit} (CFLAGS='${CUNIT_CFLAGS}' LIBS='${CUNIT_LIBS}')
@@ -902,9 +1203,13 @@ AC_MSG_NOTICE([summary of build options:
Libxml2: ${have_libxml2} (CFLAGS='${LIBXML2_CFLAGS}' LIBS='${LIBXML2_LIBS}')
Libev: ${have_libev} (CFLAGS='${LIBEV_CFLAGS}' LIBS='${LIBEV_LIBS}')
Libc-ares: ${have_libcares} (CFLAGS='${LIBCARES_CFLAGS}' LIBS='${LIBCARES_LIBS}')
libngtcp2: ${have_libngtcp2} (CFLAGS='${LIBNGTCP2_CFLAGS}' LIBS='${LIBNGTCP2_LIBS}')
libngtcp2_crypto_openssl: ${have_libngtcp2_crypto_openssl} (CFLAGS='${LIBNGTCP2_CRYPTO_OPENSSL_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_OPENSSL_LIBS}')
libnghttp3: ${have_libnghttp3} (CFLAGS='${LIBNGHTTP3_CFLAGS}' LIBS='${LIBNGHTTP3_LIBS}')
libbpf: ${have_libbpf} (CFLAGS='${LIBBPF_CFLAGS}' LIBS='${LIBBPF_LIBS}')
Libevent(SSL): ${have_libevent_openssl} (CFLAGS='${LIBEVENT_OPENSSL_CFLAGS}' LIBS='${LIBEVENT_OPENSSL_LIBS}')
Jansson: ${have_jansson} (CFLAGS='${JANSSON_CFLAGS}' LIBS='${JANSSON_LIBS}')
Jemalloc: ${have_jemalloc} (LIBS='${JEMALLOC_LIBS}')
Jemalloc: ${have_jemalloc} (CFLAGS='${JEMALLOC_CFLAGS}' LIBS='${JEMALLOC_LIBS}')
Zlib: ${have_zlib} (CFLAGS='${ZLIB_CFLAGS}' LIBS='${ZLIB_LIBS}')
Systemd: ${have_libsystemd} (CFLAGS='${SYSTEMD_CFLAGS}' LIBS='${SYSTEMD_LIBS}')
Boost CPPFLAGS: ${BOOST_CPPFLAGS}
@@ -923,4 +1228,5 @@ AC_MSG_NOTICE([summary of build options:
Examples: ${enable_examples}
Python bindings:${enable_python_bindings}
Threading: ${enable_threads}
HTTP/3 (EXPERIMENTAL): ${enable_http3}
])

View File

@@ -184,9 +184,9 @@ set(EXTRA_DIST
sources/python-apiref.rst
sources/building-android-binary.rst
sources/contribute.rst
_exts/sphinxcontrib/LICENSE.rubydomain
_exts/sphinxcontrib/__init__.py
_exts/sphinxcontrib/rubydomain.py
_exts/rubydomain/LICENSE.rubydomain
_exts/rubydomain/__init__.py
_exts/rubydomain/rubydomain.py
_themes/sphinx_rtd_theme/__init__.py
_themes/sphinx_rtd_theme/breadcrumbs.html
_themes/sphinx_rtd_theme/footer.html

View File

@@ -30,6 +30,8 @@ APIDOCS= \
nghttp2_check_authority.rst \
nghttp2_check_header_name.rst \
nghttp2_check_header_value.rst \
nghttp2_check_method.rst \
nghttp2_check_path.rst \
nghttp2_hd_deflate_bound.rst \
nghttp2_hd_deflate_change_table_size.rst \
nghttp2_hd_deflate_del.rst \
@@ -204,9 +206,9 @@ EXTRA_DIST = \
sources/building-android-binary.rst \
sources/contribute.rst \
sources/security.rst \
_exts/sphinxcontrib/LICENSE.rubydomain \
_exts/sphinxcontrib/__init__.py \
_exts/sphinxcontrib/rubydomain.py \
_exts/rubydomain/LICENSE.rubydomain \
_exts/rubydomain/__init__.py \
_exts/rubydomain/rubydomain.py \
_themes/sphinx_rtd_theme/__init__.py \
_themes/sphinx_rtd_theme/breadcrumbs.html \
_themes/sphinx_rtd_theme/footer.html \
@@ -270,7 +272,7 @@ EXTRA_DIST = \
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXBUILD ?= sphinx-build
PAPER =
BUILDDIR = manual

View File

@@ -18,7 +18,7 @@ from docutils.parsers.rst import Directive
from sphinx import addnodes
from sphinx import version_info
from sphinx.roles import XRefRole
from sphinx.locale import l_, _
from sphinx.locale import _
from sphinx.domains import Domain, ObjType, Index
from sphinx.directives import ObjectDescription
from sphinx.util.nodes import make_refnode

View File

@@ -8,7 +8,7 @@ _h2load()
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--connection-window-bits --clients --verbose --ciphers --rate --no-tls-proto --connect-to --header-table-size --requests --log-file --base-uri --h1 --threads --npn-list --rate-period --data --version --connection-inactivity-timeout --timing-script-file --encoder-header-table-size --max-concurrent-streams --connection-active-timeout --input-file --help --window-bits --warm-up-time --duration --header ' -- "$cur" ) )
COMPREPLY=( $( compgen -W '--requests --clients --threads --input-file --max-concurrent-streams --window-bits --connection-window-bits --header --ciphers --tls13-ciphers --no-tls-proto --data --rate --rate-period --duration --warm-up-time --connection-active-timeout --connection-inactivity-timeout --timing-script-file --base-uri --npn-list --h1 --header-table-size --encoder-header-table-size --log-file --qlog-file-base --connect-to --rps --groups --no-udp-gso --max-udp-payload-size --verbose --version --help ' -- "$cur" ) )
;;
*)
_filedir

View File

@@ -1,8 +1,6 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import print_function
import subprocess
import io
import re

View File

@@ -8,7 +8,7 @@ _nghttp()
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --encoder-header-table-size --padding --hexdump --max-concurrent-streams --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --trailer --weight --help --key --null-out --window-bits --expect-continue --stat --no-verify-peer --header ' -- "$cur" ) )
COMPREPLY=( $( compgen -W '--verbose --null-out --remote-name --timeout --window-bits --connection-window-bits --get-assets --stat --header --trailer --cert --key --data --multiply --upgrade --weight --peer-max-concurrent-streams --header-table-size --encoder-header-table-size --padding --har --color --continuation --no-content-length --no-dep --hexdump --no-push --max-concurrent-streams --expect-continue --no-verify-peer --version --help ' -- "$cur" ) )
;;
*)
_filedir

View File

@@ -8,7 +8,7 @@ _nghttpd()
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--htdocs --verbose --daemon --echo-upload --error-gzip --push --header-table-size --encoder-header-table-size --padding --hexdump --max-concurrent-streams --no-tls --connection-window-bits --mime-types-file --no-content-length --workers --version --color --early-response --dh-param-file --trailer --address --window-bits --verify-client --help ' -- "$cur" ) )
COMPREPLY=( $( compgen -W '--address --daemon --verify-client --htdocs --verbose --no-tls --header-table-size --encoder-header-table-size --color --push --padding --max-concurrent-streams --workers --error-gzip --window-bits --connection-window-bits --dh-param-file --early-response --trailer --hexdump --echo-upload --mime-types-file --no-content-length --version --help ' -- "$cur" ) )
;;
*)
_filedir

View File

@@ -8,7 +8,7 @@ _nghttpx()
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--worker-read-rate --include --frontend-http2-dump-response-header --tls-ticket-key-file --verify-client-cacert --max-response-header-fields --backend-http2-window-size --tls13-client-ciphers --frontend-keep-alive-timeout --backend-request-buffer --max-request-header-fields --backend-connect-timeout --tls-max-proto-version --conf --dns-lookup-timeout --backend-http2-max-concurrent-streams --worker-write-burst --npn-list --dns-max-try --fetch-ocsp-response-file --no-via --tls-session-cache-memcached-cert-file --no-http2-cipher-black-list --mruby-file --add-forwarded --client-no-http2-cipher-black-list --stream-read-timeout --client-ciphers --ocsp-update-interval --forwarded-for --accesslog-syslog --dns-cache-timeout --frontend-http2-read-timeout --listener-disable-timeout --ciphers --client-psk-secrets --strip-incoming-x-forwarded-for --no-server-rewrite --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --frontend-max-requests --tls-no-postpone-early-data --rlimit-nofile --no-strip-incoming-x-forwarded-proto --tls-ticket-key-memcached-cert-file --no-verify-ocsp --forwarded-by --tls-session-cache-memcached-private-key-file --error-page --ocsp-startup --backend-write-timeout --tls-dyn-rec-warmup-threshold --tls-ticket-key-memcached-max-retry --frontend-http2-window-size --http2-no-cookie-crumbling --worker-read-burst --dh-param-file --accesslog-format --errorlog-syslog --redirect-https-port --request-header-field-buffer --api-max-request-body --frontend-http2-decoder-dynamic-table-size --errorlog-file --frontend-http2-max-concurrent-streams --psk-secrets --frontend-write-timeout --tls-ticket-key-cipher --read-burst --no-add-x-forwarded-proto --backend --server-name --insecure --backend-max-backoff --log-level --host-rewrite --tls-ticket-key-memcached-interval --frontend-http2-setting-timeout --frontend-http2-connection-window-size --worker-frontend-connections --syslog-facility --fastopen --no-location-rewrite --single-thread --tls-session-cache-memcached --no-ocsp --backend-response-buffer --tls-min-proto-version --workers --add-x-forwarded-for --no-server-push --worker-write-rate --add-request-header --backend-http2-settings-timeout --subcert --ignore-per-pattern-mruby-error --ecdh-curves --no-kqueue --help --frontend-frame-debug --tls-sct-dir --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --backend-http2-decoder-dynamic-table-size --no-strip-incoming-early-data --user --verify-client-tolerate-expired --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --backend-connections-per-host --tls-max-early-data --response-header-field-buffer --tls-ticket-key-memcached-address-family --padding --tls-session-cache-memcached-address-family --stream-write-timeout --cacert --tls-ticket-key-memcached-private-key-file --accesslog-write-early --backend-address-family --backend-http2-connection-window-size --tls13-ciphers --version --add-response-header --backend-read-timeout --frontend-http2-optimize-window-size --frontend --accesslog-file --http2-proxy --backend-http2-encoder-dynamic-table-size --client-private-key-file --single-process --client-cert-file --tls-ticket-key-memcached --tls-dyn-rec-idle-timeout --frontend-http2-optimize-write-buffer-size --verify-client --frontend-http2-encoder-dynamic-table-size --read-rate --backend-connections-per-frontend --strip-incoming-forwarded ' -- "$cur" ) )
COMPREPLY=( $( compgen -W '--backend --frontend --backlog --backend-address-family --backend-http-proxy-uri --workers --single-thread --read-rate --read-burst --write-rate --write-burst --worker-read-rate --worker-read-burst --worker-write-rate --worker-write-burst --worker-frontend-connections --backend-connections-per-host --backend-connections-per-frontend --rlimit-nofile --backend-request-buffer --backend-response-buffer --fastopen --no-kqueue --frontend-http2-read-timeout --frontend-http3-read-timeout --frontend-read-timeout --frontend-write-timeout --frontend-keep-alive-timeout --stream-read-timeout --stream-write-timeout --backend-read-timeout --backend-write-timeout --backend-connect-timeout --backend-keep-alive-timeout --listener-disable-timeout --frontend-http2-setting-timeout --backend-http2-settings-timeout --backend-max-backoff --ciphers --tls13-ciphers --client-ciphers --tls13-client-ciphers --ecdh-curves --insecure --cacert --private-key-passwd-file --subcert --dh-param-file --npn-list --verify-client --verify-client-cacert --verify-client-tolerate-expired --client-private-key-file --client-cert-file --tls-min-proto-version --tls-max-proto-version --tls-ticket-key-file --tls-ticket-key-memcached --tls-ticket-key-memcached-address-family --tls-ticket-key-memcached-interval --tls-ticket-key-memcached-max-retry --tls-ticket-key-memcached-max-fail --tls-ticket-key-cipher --tls-ticket-key-memcached-cert-file --tls-ticket-key-memcached-private-key-file --fetch-ocsp-response-file --ocsp-update-interval --ocsp-startup --no-verify-ocsp --no-ocsp --tls-session-cache-memcached --tls-session-cache-memcached-address-family --tls-session-cache-memcached-cert-file --tls-session-cache-memcached-private-key-file --tls-dyn-rec-warmup-threshold --tls-dyn-rec-idle-timeout --no-http2-cipher-block-list --client-no-http2-cipher-block-list --tls-sct-dir --psk-secrets --client-psk-secrets --tls-no-postpone-early-data --tls-max-early-data --frontend-http2-max-concurrent-streams --backend-http2-max-concurrent-streams --frontend-http2-window-size --frontend-http2-connection-window-size --backend-http2-window-size --backend-http2-connection-window-size --http2-no-cookie-crumbling --padding --no-server-push --frontend-http2-optimize-write-buffer-size --frontend-http2-optimize-window-size --frontend-http2-encoder-dynamic-table-size --frontend-http2-decoder-dynamic-table-size --backend-http2-encoder-dynamic-table-size --backend-http2-decoder-dynamic-table-size --http2-proxy --log-level --accesslog-file --accesslog-syslog --accesslog-format --accesslog-write-early --errorlog-file --errorlog-syslog --syslog-facility --add-x-forwarded-for --strip-incoming-x-forwarded-for --no-add-x-forwarded-proto --no-strip-incoming-x-forwarded-proto --add-forwarded --strip-incoming-forwarded --forwarded-by --forwarded-for --no-via --no-strip-incoming-early-data --no-location-rewrite --host-rewrite --altsvc --http2-altsvc --add-request-header --add-response-header --request-header-field-buffer --max-request-header-fields --response-header-field-buffer --max-response-header-fields --error-page --server-name --no-server-rewrite --redirect-https-port --api-max-request-body --dns-cache-timeout --dns-lookup-timeout --dns-max-try --frontend-max-requests --frontend-http2-dump-request-header --frontend-http2-dump-response-header --frontend-frame-debug --daemon --pid-file --user --single-process --mruby-file --ignore-per-pattern-mruby-error --frontend-quic-idle-timeout --frontend-quic-debug-log --quic-bpf-program-file --frontend-quic-early-data --frontend-quic-qlog-dir --frontend-quic-require-token --frontend-quic-congestion-controller --frontend-quic-connection-id-encryption-key --no-quic-bpf --frontend-http3-window-size --frontend-http3-connection-window-size --frontend-http3-max-window-size --frontend-http3-max-connection-window-size --frontend-http3-max-concurrent-streams --conf --include --version --help ' -- "$cur" ) )
;;
*)
_filedir

View File

@@ -41,7 +41,7 @@ import sys, os
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
sys.path.append(os.path.abspath('@top_srcdir@/doc/_exts'))
sys.path.insert(0, os.path.abspath('@top_srcdir@/doc/_exts'))
# -- General configuration -----------------------------------------------------
@@ -50,7 +50,7 @@ sys.path.append(os.path.abspath('@top_srcdir@/doc/_exts'))
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinxcontrib.rubydomain']
extensions = ['rubydomain.rubydomain']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['@top_srcdir@/_templates']

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "H2LOAD" "1" "Jun 02, 2020" "1.41.0" "nghttp2"
.TH "H2LOAD" "1" "Sep 21, 2021" "1.45.1" "nghttp2"
.SH NAME
h2load \- HTTP/2 benchmarking tool
.
@@ -101,6 +101,7 @@ Default: \fB1\fP
.TP
.B \-w, \-\-window\-bits=<N>
Sets the stream level initial window size to (2**<N>)\-1.
For QUIC, <N> is capped to 26 (roughly 64MiB).
.sp
Default: \fB30\fP
.UNINDENT
@@ -120,13 +121,21 @@ Add/Override a header to the requests.
.INDENT 0.0
.TP
.B \-\-ciphers=<SUITE>
Set allowed cipher list. The format of the string is
described in OpenSSL ciphers(1).
Set allowed cipher list for TLSv1.2 or ealier. The
format of the string is described in OpenSSL ciphers(1).
.sp
Default: \fBECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-SHA384:ECDHE\-RSA\-AES256\-SHA384:ECDHE\-ECDSA\-AES128\-SHA256:ECDHE\-RSA\-AES128\-SHA256\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls13\-ciphers=<SUITE>
Set allowed cipher list for TLSv1.3. The format of the
string is described in OpenSSL ciphers(1).
.sp
Default: \fBTLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-p, \-\-no\-tls\-proto=<PROTOID>
Specify ALPN identifier of the protocol to be used when
accessing http URI without SSL/TLS.
@@ -168,7 +177,7 @@ option is 1s.
.UNINDENT
.INDENT 0.0
.TP
.B \-D, \-\-duration=<N>
.B \-D, \-\-duration=<DURATION>
Specifies the main duration for the measurements in case
of timing\-based benchmarking. \fI\%\-D\fP and \fI\%\-r\fP are mutually
exclusive.
@@ -220,7 +229,8 @@ to the number of script lines. The scheme, host and
port defined in the first URI are used solely. Values
contained in other URIs, if present, are ignored.
Definition of a base URI overrides all scheme, host or
port values.
port values. \fI\%\-\-timing\-script\-file\fP and \fI\%\-\-rps\fP are
mutually exclusive.
.UNINDENT
.INDENT 0.0
.TP
@@ -284,12 +294,45 @@ to buffering. Status code is \-1 for failed streams.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-qlog\-file\-base=<PATH>
Enable qlog output and specify base file name for qlogs.
Qlog is emitted for each connection.
For a given base name "base", each output file name
becomes "base.M.N.qlog" where M is worker ID and N is
client ID (e.g. "base.0.3.qlog").
Only effective in QUIC runs.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-connect\-to=<HOST>[:<PORT>]
Host and port to connect instead of using the authority
in <URI>.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-rps=<N>
Specify request per second for each client. \fI\%\-\-rps\fP and
\fI\%\-\-timing\-script\-file\fP are mutually exclusive.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-groups=<GROUPS>
Specify the supported groups.
.sp
Default: \fBX25519:P\-256:P\-384:P\-521\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-no\-udp\-gso
Disable UDP GSO.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-max\-udp\-payload\-size=<SIZE>
Specify the maximum outgoing UDP datagram payload size.
.UNINDENT
.INDENT 0.0
.TP
.B \-v, \-\-verbose
Output debug information.
.UNINDENT

View File

@@ -76,6 +76,7 @@ OPTIONS
.. option:: -w, --window-bits=<N>
Sets the stream level initial window size to (2\*\*<N>)-1.
For QUIC, <N> is capped to 26 (roughly 64MiB).
Default: ``30``
@@ -92,11 +93,18 @@ OPTIONS
.. option:: --ciphers=<SUITE>
Set allowed cipher list. The format of the string is
described in OpenSSL ciphers(1).
Set allowed cipher list for TLSv1.2 or ealier. The
format of the string is described in OpenSSL ciphers(1).
Default: ``ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256``
.. option:: --tls13-ciphers=<SUITE>
Set allowed cipher list for TLSv1.3. The format of the
string is described in OpenSSL ciphers(1).
Default: ``TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256``
.. option:: -p, --no-tls-proto=<PROTOID>
Specify ALPN identifier of the protocol to be used when
@@ -134,7 +142,7 @@ OPTIONS
the rate option is not used. The default value for this
option is 1s.
.. option:: -D, --duration=<N>
.. option:: -D, --duration=<DURATION>
Specifies the main duration for the measurements in case
of timing-based benchmarking. :option:`-D` and :option:`\-r` are mutually
@@ -183,7 +191,8 @@ OPTIONS
port defined in the first URI are used solely. Values
contained in other URIs, if present, are ignored.
Definition of a base URI overrides all scheme, host or
port values.
port values. :option:`--timing-script-file` and :option:`\--rps` are
mutually exclusive.
.. option:: -B, --base-uri=(<URI>|unix:<PATH>)
@@ -239,11 +248,39 @@ OPTIONS
appear slightly out of order with multiple threads due
to buffering. Status code is -1 for failed streams.
.. option:: --qlog-file-base=<PATH>
Enable qlog output and specify base file name for qlogs.
Qlog is emitted for each connection.
For a given base name "base", each output file name
becomes "base.M.N.qlog" where M is worker ID and N is
client ID (e.g. "base.0.3.qlog").
Only effective in QUIC runs.
.. option:: --connect-to=<HOST>[:<PORT>]
Host and port to connect instead of using the authority
in <URI>.
.. option:: --rps=<N>
Specify request per second for each client. :option:`--rps` and
:option:`--timing-script-file` are mutually exclusive.
.. option:: --groups=<GROUPS>
Specify the supported groups.
Default: ``X25519:P-256:P-384:P-521``
.. option:: --no-udp-gso
Disable UDP GSO.
.. option:: --max-udp-payload-size=<SIZE>
Specify the maximum outgoing UDP datagram payload size.
.. option:: -v, --verbose
Output debug information.

View File

@@ -1,9 +1,11 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# nghttp2 - HTTP/2 C Library
#
# Copyright (c) 2020 nghttp2 contributors
# Copyright (c) 2020 ngtcp2 contributors
# Copyright (c) 2012 Tatsuhiro Tsujikawa
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
@@ -25,17 +27,16 @@
# Generates API reference from C source code.
from __future__ import unicode_literals
from __future__ import print_function # At least python 2.6 is required
import re, sys, argparse, os.path
class FunctionDoc:
def __init__(self, name, content, domain):
def __init__(self, name, content, domain, filename):
self.name = name
self.content = content
self.domain = domain
if self.domain == 'function':
self.funcname = re.search(r'(nghttp2_[^ )]+)\(', self.name).group(1)
self.filename = filename
def write(self, out):
out.write('.. {}:: {}\n'.format(self.domain, self.name))
@@ -64,6 +65,26 @@ class StructDoc:
out.write(' {}\n'.format(line))
out.write('\n')
class EnumDoc:
def __init__(self, name, content, members):
self.name = name
self.content = content
self.members = members
def write(self, out):
if self.name:
out.write('.. type:: {}\n'.format(self.name))
out.write('\n')
for line in self.content:
out.write(' {}\n'.format(line))
out.write('\n')
for name, content in self.members:
out.write(' .. enum:: {}\n'.format(name))
out.write('\n')
for line in content:
out.write(' {}\n'.format(line))
out.write('\n')
class MacroDoc:
def __init__(self, name, content):
self.name = name
@@ -75,50 +96,76 @@ class MacroDoc:
for line in self.content:
out.write(' {}\n'.format(line))
def make_api_ref(infiles):
class MacroSectionDoc:
def __init__(self, content):
self.content = content
def write(self, out):
out.write('\n')
c = ' '.join(self.content).strip()
out.write(c)
out.write('\n')
out.write('-' * len(c))
out.write('\n\n')
class TypedefDoc:
def __init__(self, name, content):
self.name = name
self.content = content
def write(self, out):
out.write('''.. type:: {}\n'''.format(self.name))
out.write('\n')
for line in self.content:
out.write(' {}\n'.format(line))
def make_api_ref(infile):
macros = []
enums = []
types = []
functions = []
for infile in infiles:
while True:
while True:
line = infile.readline()
if not line:
break
elif line == '/**\n':
line = infile.readline()
if not line:
break
elif line == '/**\n':
line = infile.readline()
doctype = line.split()[1]
if doctype == '@function':
functions.append(process_function('function', infile))
elif doctype == '@functypedef':
types.append(process_function('type', infile))
elif doctype == '@struct' or doctype == '@union':
types.append(process_struct(infile))
elif doctype == '@enum':
enums.append(process_enum(infile))
elif doctype == '@macro':
macros.append(process_macro(infile))
doctype = line.split()[1]
if doctype == '@function':
functions.append(process_function('function', infile))
elif doctype == '@functypedef':
types.append(process_function('type', infile))
elif doctype == '@struct' or doctype == '@union':
types.append(process_struct(infile))
elif doctype == '@enum':
enums.append(process_enum(infile))
elif doctype == '@macro':
macros.append(process_macro(infile))
elif doctype == '@macrosection':
macros.append(process_macrosection(infile))
elif doctype == '@typedef':
types.append(process_typedef(infile))
return macros, enums, types, functions
alldocs = [('Macros', macros),
('Enums', enums),
('Types (structs, unions and typedefs)', types),
('Functions', functions)]
def output(
indexfile, macrosfile, enumsfile, typesfile, funcsdir,
title, indexfile, macrosfile, enumsfile, typesfile, funcsdir,
macros, enums, types, functions):
indexfile.write('''
API Reference
=============
{title}
{titledecoration}
.. toctree::
:maxdepth: 1
macros
enums
types
''')
{macros}
{enums}
{types}
'''.format(
title=title, titledecoration='='*len(title),
macros=os.path.splitext(os.path.basename(macrosfile.name))[0],
enums=os.path.splitext(os.path.basename(enumsfile.name))[0],
types=os.path.splitext(os.path.basename(typesfile.name))[0],
))
for doc in functions:
indexfile.write(' {}\n'.format(doc.funcname))
@@ -153,9 +200,10 @@ Types (structs, unions and typedefs)
Synopsis
--------
*#include <nghttp2/nghttp2.h>*
*#include <nghttp2/{filename}>*
'''.format(funcname=doc.funcname, secul='='*len(doc.funcname)))
'''.format(funcname=doc.funcname, secul='='*len(doc.funcname),
filename=doc.filename))
doc.write(f)
def process_macro(infile):
@@ -164,6 +212,17 @@ def process_macro(infile):
macro_name = line.split()[1]
return MacroDoc(macro_name, content)
def process_macrosection(infile):
content = read_content(infile)
return MacroSectionDoc(content)
def process_typedef(infile):
content = read_content(infile)
typedef = infile.readline()
typedef = re.sub(r';\n$', '', typedef)
typedef = re.sub(r'typedef ', '', typedef)
return TypedefDoc(typedef, content)
def process_enum(infile):
members = []
enum_name = None
@@ -176,7 +235,7 @@ def process_enum(infile):
member_content = read_content(infile)
line = infile.readline()
items = line.split()
member_name = items[0]
member_name = items[0].rstrip(',')
if len(items) >= 3:
member_content.insert(0, '(``{}``) '\
.format(' '.join(items[2:]).rstrip(',')))
@@ -185,7 +244,7 @@ def process_enum(infile):
enum_name = line.rstrip().split()[1]
enum_name = re.sub(r';$', '', enum_name)
break
return StructDoc(enum_name, content, members, 'macro')
return EnumDoc(enum_name, content, members)
def process_struct(infile):
members = []
@@ -226,7 +285,9 @@ def process_function(domain, infile):
func_proto = re.sub(r';\n$', '', func_proto)
func_proto = re.sub(r'\s+', ' ', func_proto)
func_proto = re.sub(r'NGHTTP2_EXTERN ', '', func_proto)
return FunctionDoc(func_proto, content, domain)
func_proto = re.sub(r'typedef ', '', func_proto)
filename = os.path.basename(infile.name)
return FunctionDoc(func_proto, content, domain, filename)
def read_content(infile):
content = []
@@ -251,6 +312,8 @@ def transform_content(content):
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Generate API reference")
parser.add_argument('--title', default='API Reference',
help='title of index page')
parser.add_argument('index', type=argparse.FileType('w'),
help='index output file')
parser.add_argument('macros', type=argparse.FileType('w'),
@@ -269,12 +332,13 @@ if __name__ == '__main__':
types = []
funcs = []
for infile in args.files:
m, e, t, f = make_api_ref(args.files)
m, e, t, f = make_api_ref(infile)
macros.extend(m)
enums.extend(e)
types.extend(t)
funcs.extend(f)
funcs.sort(key=lambda x: x.funcname)
output(
args.title,
args.index, args.macros, args.enums, args.types, args.funcsdir,
macros, enums, types, funcs)

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTP" "1" "Jun 02, 2020" "1.41.0" "nghttp2"
.TH "NGHTTP" "1" "Sep 21, 2021" "1.45.1" "nghttp2"
.SH NAME
nghttp \- HTTP/2 client
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPD" "1" "Jun 02, 2020" "1.41.0" "nghttp2"
.TH "NGHTTPD" "1" "Sep 21, 2021" "1.45.1" "nghttp2"
.SH NAME
nghttpd \- HTTP/2 server
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPX" "1" "Jun 02, 2020" "1.41.0" "nghttp2"
.TH "NGHTTPX" "1" "Sep 21, 2021" "1.45.1" "nghttp2"
.SH NAME
nghttpx \- HTTP/2 proxy
.
@@ -35,7 +35,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
\fBnghttpx\fP [OPTIONS]... [<PRIVATE_KEY> <CERT>]
.SH DESCRIPTION
.sp
A reverse proxy for HTTP/2, and HTTP/1.
A reverse proxy for HTTP/3, HTTP/2, and HTTP/1.
.INDENT 0.0
.TP
.B <PRIVATE_KEY>
@@ -140,12 +140,13 @@ parameters are: "proto=<PROTO>", "tls",
"affinity=<METHOD>", "dns", "redirect\-if\-not\-tls",
"upgrade\-scheme", "mruby=<PATH>",
"read\-timeout=<DURATION>", "write\-timeout=<DURATION>",
"group=<GROUP>", "group\-weight=<N>", and "weight=<N>".
The parameter consists of keyword, and optionally
followed by "=" and value. For example, the parameter
"proto=h2" consists of the keyword "proto" and value
"h2". The parameter "tls" consists of the keyword "tls"
without value. Each parameter is described as follows.
"group=<GROUP>", "group\-weight=<N>", "weight=<N>", and
"dnf". The parameter consists of keyword, and
optionally followed by "=" and value. For example, the
parameter "proto=h2" consists of the keyword "proto" and
value "h2". The parameter "tls" consists of the keyword
"tls" without value. Each parameter is described as
follows.
.sp
The backend application protocol can be specified using
optional "proto" parameter, and in the form of
@@ -276,9 +277,19 @@ weight than weight 2. If this parameter is omitted,
weight becomes 1. "weight" is ignored if session
affinity is enabled.
.sp
If "dnf" parameter is specified, an incoming request is
not forwarded to a backend and just consumed along with
the request body (actually a backend server never be
contacted). It is expected that the HTTP response is
generated by mruby script (see "mruby=<PATH>" parameter
above). "dnf" is an abbreviation of "do not forward".
.sp
Since ";" and ":" are used as delimiter, <PATTERN> must
not contain these characters. Since ";" has special
meaning in shell, the option value must be quoted.
not contain these characters. In order to include ":"
in <PATTERN>, one has to specify "%3A" (which is
percent\-encoded from of ":") instead. Since ";" has
special meaning in shell, the option value must be
quoted.
.sp
Default: \fB127.0.0.1,80\fP
.UNINDENT
@@ -320,6 +331,12 @@ To accept PROXY protocol version 1 and 2 on frontend
connection, specify "proxyproto" parameter. This is
disabled by default.
.sp
To receive HTTP/3 (QUIC) traffic, specify "quic"
parameter. It makes nghttpx listen on UDP port rather
than TCP port. UNIX domain socket, "api", and
"healthmon" parameters cannot be used with "quic"
parameter.
.sp
Default: \fB*,3000\fP
.UNINDENT
.INDENT 0.0
@@ -525,6 +542,13 @@ Default: \fB3m\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-http3\-read\-timeout=<DURATION>
Specify read timeout for HTTP/3 frontend connection.
.sp
Default: \fB3m\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-read\-timeout=<DURATION>
Specify read timeout for HTTP/1.1 frontend connection.
.sp
@@ -1003,19 +1027,19 @@ Default: \fB1s\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-no\-http2\-cipher\-black\-list
Allow black listed cipher suite on frontend HTTP/2
.B \-\-no\-http2\-cipher\-block\-list
Allow block listed cipher suite on frontend HTTP/2
connection. See
\fI\%https://tools.ietf.org/html/rfc7540#appendix\-A\fP for the
complete HTTP/2 cipher suites black list.
complete HTTP/2 cipher suites block list.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-client\-no\-http2\-cipher\-black\-list
Allow black listed cipher suite on backend HTTP/2
.B \-\-client\-no\-http2\-cipher\-block\-list
Allow block listed cipher suite on backend HTTP/2
connection. See
\fI\%https://tools.ietf.org/html/rfc7540#appendix\-A\fP for the
complete HTTP/2 cipher suites black list.
complete HTTP/2 cipher suites block list.
.UNINDENT
.INDENT 0.0
.TP
@@ -1040,9 +1064,9 @@ in hex. An empty line, and line which starts with \(aq#\(aq
are skipped. The default enabled cipher list might not
contain any PSK cipher suite. In that case, desired PSK
cipher suites must be enabled using \fI\%\-\-ciphers\fP option.
The desired PSK cipher suite may be black listed by
The desired PSK cipher suite may be block listed by
HTTP/2. To use those cipher suites with HTTP/2,
consider to use \fI\%\-\-no\-http2\-cipher\-black\-list\fP option.
consider to use \fI\%\-\-no\-http2\-cipher\-block\-list\fP option.
But be aware its implications.
.UNINDENT
.INDENT 0.0
@@ -1057,20 +1081,21 @@ The first identity and secret pair encountered is used.
The default enabled cipher list might not contain any
PSK cipher suite. In that case, desired PSK cipher
suites must be enabled using \fI\%\-\-client\-ciphers\fP option.
The desired PSK cipher suite may be black listed by
The desired PSK cipher suite may be block listed by
HTTP/2. To use those cipher suites with HTTP/2,
consider to use \fI\%\-\-client\-no\-http2\-cipher\-black\-list\fP
consider to use \fI\%\-\-client\-no\-http2\-cipher\-block\-list\fP
option. But be aware its implications.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-no\-postpone\-early\-data
By default, nghttpx postpones forwarding HTTP requests
sent in early data, including those sent in partially in
it, until TLS handshake finishes. If all backend server
recognizes "Early\-Data" header field, using this option
makes nghttpx not postpone forwarding request and get
full potential of 0\-RTT data.
By default, except for QUIC connections, nghttpx
postpones forwarding HTTP requests sent in early data,
including those sent in partially in it, until TLS
handshake finishes. If all backend server recognizes
"Early\-Data" header field, using this option makes
nghttpx not postpone forwarding request and get full
potential of 0\-RTT data.
.UNINDENT
.INDENT 0.0
.TP
@@ -1324,6 +1349,18 @@ request. "\-" if backend host is not available.
.IP \(bu 2
$backend_port: backend port used to fulfill the
request. "\-" if backend host is not available.
.IP \(bu 2
$method: HTTP method
.IP \(bu 2
$path: Request path including query. For CONNECT
request, authority is recorded.
.IP \(bu 2
$path_without_query: $path up to the first \(aq?\(aq
character. For CONNECT request, authority is
recorded.
.IP \(bu 2
$protocol_version: HTTP version (e.g., HTTP/1.1,
HTTP/2)
.UNINDENT
.sp
The variable can be enclosed by "{" and "}" for
@@ -1463,13 +1500,21 @@ not be altered regardless of this option.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
.B \-\-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
Specify protocol ID, port, host and origin of
alternative service. <HOST> and <ORIGIN> are optional.
They are advertised in alt\-svc header field only in
HTTP/1.1 frontend. This option can be used multiple
times to specify multiple alternative services.
Example: \fI\%\-\-altsvc\fP=h2,443
alternative service. <HOST>, <ORIGIN> and <PARAMS> are
optional. Empty <HOST> and <ORIGIN> are allowed and
they are treated as nothing is specified. They are
advertised in alt\-svc header field only in HTTP/1.1
frontend. This option can be used multiple times to
specify multiple alternative services.
Example: \fI\%\-\-altsvc\fP="h2,443,,,ma=3600; persist=1\(aq
.UNINDENT
.INDENT 0.0
.TP
.B \-\-http2\-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
Just like \fI\%\-\-altsvc\fP option, but this altsvc is only sent
in HTTP/2 frontend.
.UNINDENT
.INDENT 0.0
.TP
@@ -1654,10 +1699,10 @@ be used to drop root privileges.
.B \-\-single\-process
Run this program in a single process mode for debugging
purpose. Without this option, nghttpx creates at least
2 processes: master and worker processes. If this
option is used, master and worker are unified into a
single process. nghttpx still spawns additional process
if neverbleed is used. In the single process mode, the
2 processes: main and worker processes. If this option
is used, main and worker are unified into a single
process. nghttpx still spawns additional process if
neverbleed is used. In the single process mode, the
signal handling feature is disabled.
.UNINDENT
.SS Scripting
@@ -1673,6 +1718,125 @@ Ignore mruby compile error for per\-pattern mruby script
file. If error occurred, it is treated as if no mruby
file were specified for the pattern.
.UNINDENT
.SS HTTP/3 and QUIC
.INDENT 0.0
.TP
.B \-\-frontend\-quic\-idle\-timeout=<DURATION>
Specify an idle timeout for QUIC connection.
.sp
Default: \fB30s\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-quic\-debug\-log
Output QUIC debug log to \fI/dev/stderr.\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-quic\-bpf\-program\-file=<PATH>
Specify a path to eBPF program file reuseport_kern.o to
direct an incoming QUIC UDP datagram to a correct
socket.
.sp
Default: \fB/usr/local/lib/nghttp2/reuseport_kern.o\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-quic\-early\-data
Enable early data on frontend QUIC connections. nghttpx
sends "Early\-Data" header field to a backend server if a
request is received in early data and handshake has not
finished. All backend servers should deal with possibly
replayed requests.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-quic\-qlog\-dir=<DIR>
Specify a directory where a qlog file is written for
frontend QUIC connections. A qlog file is created per
each QUIC connection. The file name is ISO8601 basic
format, followed by "\-", server Source Connection ID and
".qlog".
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-quic\-require\-token
Require an address validation token for a frontend QUIC
connection. Server sends a token in Retry packet or
NEW_TOKEN frame in the previous connection.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-quic\-congestion\-controller=<CC>
Specify a congestion controller algorithm for a frontend
QUIC connection. <CC> should be either "cubic" or
"bbr".
.sp
Default: \fBcubic\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-quic\-connection\-id\-encryption\-key=<HEXSTRING>
Specify Connection ID encryption key. The encryption
key must be 16 bytes, and it must be encoded in hex
string (which is 32 bytes long). If this option is
omitted, new key is generated. In order to survive QUIC
connection in a configuration reload event, old and new
configuration must have this option and share the same
key.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-no\-quic\-bpf
Disable eBPF.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-http3\-window\-size=<SIZE>
Sets the per\-stream initial window size of HTTP/3
frontend connection.
.sp
Default: \fB256K\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-http3\-connection\-window\-size=<SIZE>
Sets the per\-connection window size of HTTP/3 frontend
connection.
.sp
Default: \fB1M\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-http3\-max\-window\-size=<SIZE>
Sets the maximum per\-stream window size of HTTP/3
frontend connection. The window size is adjusted based
on the receiving rate of stream data. The initial value
is the value specified by \fI\%\-\-frontend\-http3\-window\-size\fP
and the window size grows up to <SIZE> bytes.
.sp
Default: \fB6M\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-http3\-max\-connection\-window\-size=<SIZE>
Sets the maximum per\-connection window size of HTTP/3
frontend connection. The window size is adjusted based
on the receiving rate of stream data. The initial value
is the value specified by
\fI\%\-\-frontend\-http3\-connection\-window\-size\fP and the window
size grows up to <SIZE> bytes.
.sp
Default: \fB8M\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-http3\-max\-concurrent\-streams=<N>
Set the maximum number of the concurrent streams in one
frontend HTTP/3 connection.
.sp
Default: \fB100\fP
.UNINDENT
.SS Misc
.INDENT 0.0
.TP
@@ -1769,15 +1933,15 @@ Error log is written to stderr by default. It can be configured
using \fI\%\-\-errorlog\-file\fP\&. The format of log message is as
follows:
.sp
<datetime> <master\-pid> <current\-pid> <thread\-id> <level> (<filename>:<line>) <msg>
<datetime> <main\-pid> <current\-pid> <thread\-id> <level> (<filename>:<line>) <msg>
.INDENT 7.0
.TP
.B <datetime>
It is a combination of date and time when the log is written. It
is in ISO 8601 format.
.TP
.B <master\-pid>
It is a master process ID.
.B <main\-pid>
It is a main process ID.
.TP
.B <current\-pid>
It is a process ID which writes this log.
@@ -1813,15 +1977,15 @@ SIGUSR2
.INDENT 3.5
Fork and execute nghttpx. It will execute the binary in the same
path with same command\-line arguments and environment variables. As
of nghttpx version 1.20.0, the new master process sends SIGQUIT to
the original master process when it is ready to serve requests. For
the earlier versions of nghttpx, user has to send SIGQUIT to the
original master process.
of nghttpx version 1.20.0, the new main process sends SIGQUIT to the
original main process when it is ready to serve requests. For the
earlier versions of nghttpx, user has to send SIGQUIT to the
original main process.
.sp
The difference between SIGUSR2 (+ SIGQUIT) and SIGHUP is that former
is usually used to execute new binary, and the master process is
newly spawned. On the other hand, the latter just reloads
configuration file, and the same master process continues to exist.
is usually used to execute new binary, and the main process is newly
spawned. On the other hand, the latter just reloads configuration
file, and the same main process continues to exist.
.UNINDENT
.UNINDENT
.sp
@@ -1830,16 +1994,16 @@ configuration file, and the same master process continues to exist.
.INDENT 3.5
nghttpx consists of multiple processes: one process for processing
these signals, and another one for processing requests. The former
spawns the latter. The former is called master process, and the
spawns the latter. The former is called main process, and the
latter is called worker process. If neverbleed is enabled, the
worker process spawns neverbleed daemon process which does RSA key
processing. The above signal must be sent to the master process.
If the other processes received one of them, it is ignored. This
processing. The above signal must be sent to the main process. If
the other processes received one of them, it is ignored. This
behaviour of these processes may change in the future release. In
other words, in the future release, the processes other than master
other words, in the future release, the processes other than main
process may terminate upon the reception of these signals.
Therefore these signals should not be sent to the processes other
than master process.
than main process.
.UNINDENT
.UNINDENT
.SH SERVER PUSH

View File

@@ -14,7 +14,7 @@ SYNOPSIS
DESCRIPTION
-----------
A reverse proxy for HTTP/2, and HTTP/1.
A reverse proxy for HTTP/3, HTTP/2, and HTTP/1.
.. describe:: <PRIVATE_KEY>
@@ -124,12 +124,13 @@ Connections
"affinity=<METHOD>", "dns", "redirect-if-not-tls",
"upgrade-scheme", "mruby=<PATH>",
"read-timeout=<DURATION>", "write-timeout=<DURATION>",
"group=<GROUP>", "group-weight=<N>", and "weight=<N>".
The parameter consists of keyword, and optionally
followed by "=" and value. For example, the parameter
"proto=h2" consists of the keyword "proto" and value
"h2". The parameter "tls" consists of the keyword "tls"
without value. Each parameter is described as follows.
"group=<GROUP>", "group-weight=<N>", "weight=<N>", and
"dnf". The parameter consists of keyword, and
optionally followed by "=" and value. For example, the
parameter "proto=h2" consists of the keyword "proto" and
value "h2". The parameter "tls" consists of the keyword
"tls" without value. Each parameter is described as
follows.
The backend application protocol can be specified using
optional "proto" parameter, and in the form of
@@ -260,9 +261,19 @@ Connections
weight becomes 1. "weight" is ignored if session
affinity is enabled.
If "dnf" parameter is specified, an incoming request is
not forwarded to a backend and just consumed along with
the request body (actually a backend server never be
contacted). It is expected that the HTTP response is
generated by mruby script (see "mruby=<PATH>" parameter
above). "dnf" is an abbreviation of "do not forward".
Since ";" and ":" are used as delimiter, <PATTERN> must
not contain these characters. Since ";" has special
meaning in shell, the option value must be quoted.
not contain these characters. In order to include ":"
in <PATTERN>, one has to specify "%3A" (which is
percent-encoded from of ":") instead. Since ";" has
special meaning in shell, the option value must be
quoted.
Default: ``127.0.0.1,80``
@@ -304,6 +315,12 @@ Connections
connection, specify "proxyproto" parameter. This is
disabled by default.
To receive HTTP/3 (QUIC) traffic, specify "quic"
parameter. It makes nghttpx listen on UDP port rather
than TCP port. UNIX domain socket, "api", and
"healthmon" parameters cannot be used with "quic"
parameter.
Default: ``*,3000``
@@ -492,6 +509,12 @@ Timeout
Default: ``3m``
.. option:: --frontend-http3-read-timeout=<DURATION>
Specify read timeout for HTTP/3 frontend connection.
Default: ``3m``
.. option:: --frontend-read-timeout=<DURATION>
Specify read timeout for HTTP/1.1 frontend connection.
@@ -922,19 +945,19 @@ SSL/TLS
Default: ``1s``
.. option:: --no-http2-cipher-black-list
.. option:: --no-http2-cipher-block-list
Allow black listed cipher suite on frontend HTTP/2
Allow block listed cipher suite on frontend HTTP/2
connection. See
https://tools.ietf.org/html/rfc7540#appendix-A for the
complete HTTP/2 cipher suites black list.
complete HTTP/2 cipher suites block list.
.. option:: --client-no-http2-cipher-black-list
.. option:: --client-no-http2-cipher-block-list
Allow black listed cipher suite on backend HTTP/2
Allow block listed cipher suite on backend HTTP/2
connection. See
https://tools.ietf.org/html/rfc7540#appendix-A for the
complete HTTP/2 cipher suites black list.
complete HTTP/2 cipher suites block list.
.. option:: --tls-sct-dir=<DIR>
@@ -957,9 +980,9 @@ SSL/TLS
are skipped. The default enabled cipher list might not
contain any PSK cipher suite. In that case, desired PSK
cipher suites must be enabled using :option:`--ciphers` option.
The desired PSK cipher suite may be black listed by
The desired PSK cipher suite may be block listed by
HTTP/2. To use those cipher suites with HTTP/2,
consider to use :option:`--no-http2-cipher-black-list` option.
consider to use :option:`--no-http2-cipher-block-list` option.
But be aware its implications.
.. option:: --client-psk-secrets=<PATH>
@@ -973,19 +996,20 @@ SSL/TLS
The default enabled cipher list might not contain any
PSK cipher suite. In that case, desired PSK cipher
suites must be enabled using :option:`--client-ciphers` option.
The desired PSK cipher suite may be black listed by
The desired PSK cipher suite may be block listed by
HTTP/2. To use those cipher suites with HTTP/2,
consider to use :option:`--client-no-http2-cipher-black-list`
consider to use :option:`--client-no-http2-cipher-block-list`
option. But be aware its implications.
.. option:: --tls-no-postpone-early-data
By default, nghttpx postpones forwarding HTTP requests
sent in early data, including those sent in partially in
it, until TLS handshake finishes. If all backend server
recognizes "Early-Data" header field, using this option
makes nghttpx not postpone forwarding request and get
full potential of 0-RTT data.
By default, except for QUIC connections, nghttpx
postpones forwarding HTTP requests sent in early data,
including those sent in partially in it, until TLS
handshake finishes. If all backend server recognizes
"Early-Data" header field, using this option makes
nghttpx not postpone forwarding request and get full
potential of 0-RTT data.
.. option:: --tls-max-early-data=<SIZE>
@@ -1203,6 +1227,14 @@ Logging
request. "-" if backend host is not available.
* $backend_port: backend port used to fulfill the
request. "-" if backend host is not available.
* $method: HTTP method
* $path: Request path including query. For CONNECT
request, authority is recorded.
* $path_without_query: $path up to the first '?'
character. For CONNECT request, authority is
recorded.
* $protocol_version: HTTP version (e.g., HTTP/1.1,
HTTP/2)
The variable can be enclosed by "{" and "}" for
disambiguation (e.g., ${remote_addr}).
@@ -1327,14 +1359,21 @@ HTTP
mode. When :option:`--http2-proxy` is used, these headers will
not be altered regardless of this option.
.. option:: --altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
.. option:: --altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
Specify protocol ID, port, host and origin of
alternative service. <HOST> and <ORIGIN> are optional.
They are advertised in alt-svc header field only in
HTTP/1.1 frontend. This option can be used multiple
times to specify multiple alternative services.
Example: :option:`--altsvc`\=h2,443
alternative service. <HOST>, <ORIGIN> and <PARAMS> are
optional. Empty <HOST> and <ORIGIN> are allowed and
they are treated as nothing is specified. They are
advertised in alt-svc header field only in HTTP/1.1
frontend. This option can be used multiple times to
specify multiple alternative services.
Example: :option:`--altsvc`\="h2,443,,,ma=3600; persist=1'
.. option:: --http2-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
Just like :option:`--altsvc` option, but this altsvc is only sent
in HTTP/2 frontend.
.. option:: --add-request-header=<HEADER>
@@ -1509,10 +1548,10 @@ Process
Run this program in a single process mode for debugging
purpose. Without this option, nghttpx creates at least
2 processes: master and worker processes. If this
option is used, master and worker are unified into a
single process. nghttpx still spawns additional process
if neverbleed is used. In the single process mode, the
2 processes: main and worker processes. If this option
is used, main and worker are unified into a single
process. nghttpx still spawns additional process if
neverbleed is used. In the single process mode, the
signal handling feature is disabled.
@@ -1530,6 +1569,114 @@ Scripting
file were specified for the pattern.
HTTP/3 and QUIC
~~~~~~~~~~~~~~~
.. option:: --frontend-quic-idle-timeout=<DURATION>
Specify an idle timeout for QUIC connection.
Default: ``30s``
.. option:: --frontend-quic-debug-log
Output QUIC debug log to */dev/stderr.*
.. option:: --quic-bpf-program-file=<PATH>
Specify a path to eBPF program file reuseport_kern.o to
direct an incoming QUIC UDP datagram to a correct
socket.
Default: ``/usr/local/lib/nghttp2/reuseport_kern.o``
.. option:: --frontend-quic-early-data
Enable early data on frontend QUIC connections. nghttpx
sends "Early-Data" header field to a backend server if a
request is received in early data and handshake has not
finished. All backend servers should deal with possibly
replayed requests.
.. option:: --frontend-quic-qlog-dir=<DIR>
Specify a directory where a qlog file is written for
frontend QUIC connections. A qlog file is created per
each QUIC connection. The file name is ISO8601 basic
format, followed by "-", server Source Connection ID and
".qlog".
.. option:: --frontend-quic-require-token
Require an address validation token for a frontend QUIC
connection. Server sends a token in Retry packet or
NEW_TOKEN frame in the previous connection.
.. option:: --frontend-quic-congestion-controller=<CC>
Specify a congestion controller algorithm for a frontend
QUIC connection. <CC> should be either "cubic" or
"bbr".
Default: ``cubic``
.. option:: --frontend-quic-connection-id-encryption-key=<HEXSTRING>
Specify Connection ID encryption key. The encryption
key must be 16 bytes, and it must be encoded in hex
string (which is 32 bytes long). If this option is
omitted, new key is generated. In order to survive QUIC
connection in a configuration reload event, old and new
configuration must have this option and share the same
key.
.. option:: --no-quic-bpf
Disable eBPF.
.. option:: --frontend-http3-window-size=<SIZE>
Sets the per-stream initial window size of HTTP/3
frontend connection.
Default: ``256K``
.. option:: --frontend-http3-connection-window-size=<SIZE>
Sets the per-connection window size of HTTP/3 frontend
connection.
Default: ``1M``
.. option:: --frontend-http3-max-window-size=<SIZE>
Sets the maximum per-stream window size of HTTP/3
frontend connection. The window size is adjusted based
on the receiving rate of stream data. The initial value
is the value specified by :option:`--frontend-http3-window-size`
and the window size grows up to <SIZE> bytes.
Default: ``6M``
.. option:: --frontend-http3-max-connection-window-size=<SIZE>
Sets the maximum per-connection window size of HTTP/3
frontend connection. The window size is adjusted based
on the receiving rate of stream data. The initial value
is the value specified by
:option:`--frontend-http3-connection-window-size` and the window
size grows up to <SIZE> bytes.
Default: ``8M``
.. option:: --frontend-http3-max-concurrent-streams=<N>
Set the maximum number of the concurrent streams in one
frontend HTTP/3 connection.
Default: ``100``
Misc
~~~~
@@ -1614,14 +1761,14 @@ Error log
using :option:`--errorlog-file`. The format of log message is as
follows:
<datetime> <master-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
<datetime> <main-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
<datetime>
It is a combination of date and time when the log is written. It
is in ISO 8601 format.
<master-pid>
It is a master process ID.
<main-pid>
It is a main process ID.
<current-pid>
It is a process ID which writes this log.
@@ -1654,30 +1801,30 @@ SIGUSR2
Fork and execute nghttpx. It will execute the binary in the same
path with same command-line arguments and environment variables. As
of nghttpx version 1.20.0, the new master process sends SIGQUIT to
the original master process when it is ready to serve requests. For
the earlier versions of nghttpx, user has to send SIGQUIT to the
original master process.
of nghttpx version 1.20.0, the new main process sends SIGQUIT to the
original main process when it is ready to serve requests. For the
earlier versions of nghttpx, user has to send SIGQUIT to the
original main process.
The difference between SIGUSR2 (+ SIGQUIT) and SIGHUP is that former
is usually used to execute new binary, and the master process is
newly spawned. On the other hand, the latter just reloads
configuration file, and the same master process continues to exist.
is usually used to execute new binary, and the main process is newly
spawned. On the other hand, the latter just reloads configuration
file, and the same main process continues to exist.
.. note::
nghttpx consists of multiple processes: one process for processing
these signals, and another one for processing requests. The former
spawns the latter. The former is called master process, and the
spawns the latter. The former is called main process, and the
latter is called worker process. If neverbleed is enabled, the
worker process spawns neverbleed daemon process which does RSA key
processing. The above signal must be sent to the master process.
If the other processes received one of them, it is ignored. This
processing. The above signal must be sent to the main process. If
the other processes received one of them, it is ignored. This
behaviour of these processes may change in the future release. In
other words, in the future release, the processes other than master
other words, in the future release, the processes other than main
process may terminate upon the reception of these signals.
Therefore these signals should not be sent to the processes other
than master process.
than main process.
SERVER PUSH
-----------

View File

@@ -46,14 +46,14 @@ Error log
using :option:`--errorlog-file`. The format of log message is as
follows:
<datetime> <master-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
<datetime> <main-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
<datetime>
It is a combination of date and time when the log is written. It
is in ISO 8601 format.
<master-pid>
It is a master process ID.
<main-pid>
It is a main process ID.
<current-pid>
It is a process ID which writes this log.
@@ -86,30 +86,30 @@ SIGUSR2
Fork and execute nghttpx. It will execute the binary in the same
path with same command-line arguments and environment variables. As
of nghttpx version 1.20.0, the new master process sends SIGQUIT to
the original master process when it is ready to serve requests. For
the earlier versions of nghttpx, user has to send SIGQUIT to the
original master process.
of nghttpx version 1.20.0, the new main process sends SIGQUIT to the
original main process when it is ready to serve requests. For the
earlier versions of nghttpx, user has to send SIGQUIT to the
original main process.
The difference between SIGUSR2 (+ SIGQUIT) and SIGHUP is that former
is usually used to execute new binary, and the master process is
newly spawned. On the other hand, the latter just reloads
configuration file, and the same master process continues to exist.
is usually used to execute new binary, and the main process is newly
spawned. On the other hand, the latter just reloads configuration
file, and the same main process continues to exist.
.. note::
nghttpx consists of multiple processes: one process for processing
these signals, and another one for processing requests. The former
spawns the latter. The former is called master process, and the
spawns the latter. The former is called main process, and the
latter is called worker process. If neverbleed is enabled, the
worker process spawns neverbleed daemon process which does RSA key
processing. The above signal must be sent to the master process.
If the other processes received one of them, it is ignored. This
processing. The above signal must be sent to the main process. If
the other processes received one of them, it is ignored. This
behaviour of these processes may change in the future release. In
other words, in the future release, the processes other than master
other words, in the future release, the processes other than main
process may terminate upon the reception of these signals.
Therefore these signals should not be sent to the processes other
than master process.
than main process.
SERVER PUSH
-----------

View File

@@ -6,7 +6,7 @@ Architecture
The most notable point in nghttp2 library architecture is it does not
perform any I/O. nghttp2 only performs HTTP/2 protocol stuff based on
input byte strings. It will calls callback functions set by
input byte strings. It will call callback functions set by
applications while processing input. The output of nghttp2 is just
byte string. An application is responsible to send these output to
the remote peer. The callback functions may be called while producing

View File

@@ -26,16 +26,16 @@ Coding style
We use clang-format to format source code consistently. The
clang-format configuration file .clang-format is located at the root
directory. Since clang-format produces slightly different results
between versions, we currently use clang-format-9.
between versions, we currently use clang-format-12.
To detect any violation to the coding style, we recommend to setup git
pre-commit hook to check coding style of the changes you introduced.
The pre-commit file is located at the root directory. Copy it under
.git/hooks and make sure that it is executable. The pre-commit script
uses clang-format-diff.py to detect any style errors. If it is not in
your PATH or it exists under different name (e.g., clang-format-diff-9
in debian), either add it to PATH variable or add git option
``clangformatdiff.binary`` to point to the script.
your PATH or it exists under different name (e.g.,
clang-format-diff-12 in debian), either add it to PATH variable or add
git option ``clangformatdiff.binary`` to point to the script.
For emacs users, integrating clang-format to emacs is very easy.
clang-format.el should come with clang distribution. If it is not

View File

@@ -131,3 +131,12 @@ specify ``unix:`` followed by the path to UNIX domain socket. For
example, if UNIX domain socket is ``/tmp/nghttpx.sock``, use
``--base-uri=unix:/tmp/nghttpx.sock``. h2load uses scheme, host and
port in the first URI in command-line or input file.
HTTP/3
------
h2load supports HTTP/3 if it is built with HTTP/3 enabled. HTTP/3
support is experimental.
In order to send HTTP/3 request, specify ``h3`` to
:option:`--npn-list`.

View File

@@ -1,4 +1,4 @@
.. nghttp2 documentation master file, created by
.. nghttp2 documentation main file, created by
sphinx-quickstart on Sun Mar 11 22:57:49 2012.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.

View File

@@ -14,8 +14,8 @@ Default mode
If nghttpx is invoked without :option:`--http2-proxy`, it operates in
default mode. In this mode, it works as reverse proxy (gateway) for
both HTTP/2 and HTTP/1 clients to backend servers. This is also known
as "HTTP/2 router".
HTTP/3, HTTP/2 and HTTP/1 clients to backend servers. This is also
known as "HTTP/2 router".
By default, frontend connection is encrypted using SSL/TLS. So
server's private key and certificate must be supplied to the command
@@ -28,6 +28,9 @@ the frontend, and an HTTP/1 connection can be upgraded to HTTP/2 using
HTTP Upgrade. Starting HTTP/2 connection by sending HTTP/2 connection
preface is also supported.
In order to receive HTTP/3 traffic, use ``quic`` parameter in
:option:`--frontend` option (.e.g, ``--frontend='*,443;quic'``)
nghttpx can listen on multiple frontend addresses. This is achieved
by using multiple :option:`--frontend` options. For each frontend
address, TLS can be enabled or disabled.
@@ -228,7 +231,7 @@ process. It will do fork and execute new executable, using same
command-line arguments and environment variables.
As of nghttpx version 1.20.0, that is all you have to do. The new
master process sends QUIT signal to the original process, when it is
main process sends QUIT signal to the original process, when it is
ready to serve requests, to shut it down gracefully.
For earlier versions of nghttpx, you have to do one more thing. At
@@ -239,7 +242,7 @@ current process will exit. At this point, only new nghttpx process
exists and serves incoming requests.
If you want to just reload configuration file without executing new
binary, send SIGHUP to nghttpx master process.
binary, send SIGHUP to nghttpx main process.
Re-opening log files
--------------------
@@ -445,10 +448,10 @@ nghttpx server accepts any of the identity and secret pairs in the
file. The default cipher suite list does not contain PSK cipher
suites. In order to use PSK, PSK cipher suite must be enabled by
using :option:`--ciphers` option. The desired PSK cipher suite may be
listed in `HTTP/2 cipher black list
listed in `HTTP/2 cipher block list
<https://tools.ietf.org/html/rfc7540#appendix-A>`_. In order to use
such PSK cipher suite with HTTP/2, disable HTTP/2 cipher black list by
using :option:`--no-http2-cipher-black-list` option. But you should
such PSK cipher suite with HTTP/2, disable HTTP/2 cipher block list by
using :option:`--no-http2-cipher-block-list` option. But you should
understand its implications.
At the time of writing, even if only PSK cipher suites are specified
@@ -468,10 +471,10 @@ used, like so:
The default cipher suite list does not contain PSK cipher suites. In
order to use PSK, PSK cipher suite must be enabled by using
:option:`--client-ciphers` option. The desired PSK cipher suite may
be listed in `HTTP/2 cipher black list
be listed in `HTTP/2 cipher block list
<https://tools.ietf.org/html/rfc7540#appendix-A>`_. In order to use
such PSK cipher suite with HTTP/2, disable HTTP/2 cipher black list by
using :option:`--client-no-http2-cipher-black-list` option. But you
such PSK cipher suite with HTTP/2, disable HTTP/2 cipher block list by
using :option:`--client-no-http2-cipher-block-list` option. But you
should understand its implications.
TLSv1.3
@@ -509,6 +512,42 @@ Bootstrapping WebSockets with HTTP/2 for both frontend and backend
connections. This feature is enabled by default and no configuration
is required.
WebSockets over HTTP/3 is also supported.
HTTP/3
------
nghttpx supports HTTP/3 if it is built with HTTP/3 support enabled.
HTTP/3 support is experimental.
In order to listen UDP port to receive HTTP/3 traffic,
:option:`--frontend` option must have ``quic`` parameter:
.. code-block:: text
frontend=*,443;quic
The above example makes nghttpx receive HTTP/3 traffic on UDP
port 443.
nghttpx does not support HTTP/3 on backend connection.
Hot swapping (SIGUSR2) or configuration reload (SIGHUP) require eBPF
program. Without eBPF, old worker processes keep getting HTTP/3
traffic and do not work as intended. Connection ID encryption key
must be set with
:option:`--frontend-quic-connection-id-encryption-key` and must not
change in order to keep the existing connections alive during reload.
In order announce that HTTP/3 endpoint is available, you should
specify alt-svc header field. For example, the following options send
alt-svc header field in HTTP/1.1 and HTTP/2 response:
.. code-block:: text
altsvc=h3,443,,,ma=3600
http2-altsvc=h3,443,,,ma=3600
Migration from nghttpx v1.18.x or earlier
-----------------------------------------
@@ -516,10 +555,10 @@ As of nghttpx v1.19.0, :option:`--ciphers` option only changes cipher
list for frontend TLS connection. In order to change cipher list for
backend connection, use :option:`--client-ciphers` option.
Similarly, :option:`--no-http2-cipher-black-list` option only disables
HTTP/2 cipher black list for frontend connection. In order to disable
HTTP/2 cipher black list for backend connection, use
:option:`--client-no-http2-cipher-black-list` option.
Similarly, :option:`--no-http2-cipher-block-list` option only disables
HTTP/2 cipher block list for frontend connection. In order to disable
HTTP/2 cipher block list for backend connection, use
:option:`--client-no-http2-cipher-block-list` option.
``--accept-proxy-protocol`` option was deprecated. Instead, use
``proxyproto`` parameter in :option:`--frontend` option to enable

View File

@@ -13,7 +13,7 @@ The extension module is called ``nghttp2``.
determined by configure script. If the detected Python version is not
what you expect, specify a path to Python executable in ``PYTHON``
variable as an argument to configure script (e.g., ``./configure
PYTHON=/usr/bin/python3.5``).
PYTHON=/usr/bin/python3.8``).
HPACK API
---------
@@ -137,14 +137,14 @@ HTTP/2 servers
.. note::
We use :py:mod:`asyncio` for HTTP/2 server classes, and ALPN.
Therefore, Python 3.5 or later is required to use these objects.
To explicitly configure nghttp2 build to use Python 3.5, specify
the ``PYTHON`` variable to the path to Python 3.5 executable when
Therefore, Python 3.8 or later is required to use these objects.
To explicitly configure nghttp2 build to use Python 3.8, specify
the ``PYTHON`` variable to the path to Python 3.8 executable when
invoking configure script like this:
.. code-block:: text
$ ./configure PYTHON=/usr/bin/python3.5
$ ./configure PYTHON=/usr/bin/python3.8
.. py:class:: HTTP2Server(address, RequestHandlerClass, ssl=None)
@@ -336,7 +336,7 @@ The following example illustrates :py:class:`HTTP2Server` and
.. code-block:: python
#!/usr/bin/env python
#!/usr/bin/env python3
import io, ssl
@@ -367,7 +367,7 @@ response body generation. This is simplified reverse proxy:
.. code-block:: python
#!/usr/bin/env python
#!/usr/bin/env python3
import ssl
import os

View File

@@ -33,6 +33,6 @@ attached to this kind of issue.
Before few hours of new release, we merge the fixes to the master
branch (and/or a release branch if necessary) and make a new release.
Security advisory is disclosed on GitHub. We also post the
vulnerability information to `oss-secirty
vulnerability information to `oss-security
<https://oss-security.openwall.org/wiki/mailing-lists/oss-security>`_
mailing list.

75
docker/Dockerfile Normal file
View File

@@ -0,0 +1,75 @@
FROM debian:11 as build
RUN apt-get update && \
apt-get install -y --no-install-recommends \
git clang make binutils autoconf automake autotools-dev libtool \
pkg-config \
zlib1g-dev libev-dev libjemalloc-dev ruby-dev libc-ares-dev bison \
libelf-dev
RUN git clone --depth 1 -b openssl-3.0.0+quic https://github.com/quictls/openssl && \
cd openssl && \
./config --openssldir=/etc/ssl && \
make -j$(nproc) && \
make install_sw && \
cd .. && \
rm -rf openssl
RUN git clone --depth 1 https://github.com/ngtcp2/nghttp3 && \
cd nghttp3 && \
autoreconf -i && \
./configure --enable-lib-only && \
make -j$(nproc) && \
make install-strip && \
cd .. && \
rm -rf nghttp3
RUN git clone --depth 1 https://github.com/ngtcp2/ngtcp2 && \
cd ngtcp2 && \
autoreconf -i && \
./configure --enable-lib-only \
LIBTOOL_LDFLAGS="-static-libtool-libs" \
OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a -ldl -lpthread" \
PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \
make -j$(nproc) && \
make install-strip && \
cd .. && \
rm -rf ngtcp2
RUN git clone --depth 1 -b v0.4.0 https://github.com/libbpf/libbpf && \
cd libbpf && \
PREFIX=/usr/local make -C src install && \
cd .. && \
rm -rf libbpf
RUN git clone --depth 1 https://github.com/nghttp2/nghttp2.git && \
cd nghttp2 && \
git submodule update --init && \
autoreconf -i && \
./configure --disable-examples --disable-hpack-tools \
--disable-python-bindings --with-mruby --with-neverbleed \
--enable-http3 --with-libbpf \
CC=clang CXX=clang++ \
LIBTOOL_LDFLAGS="-static-libtool-libs" \
OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a -ldl -pthread" \
LIBEV_LIBS="-l:libev.a" \
JEMALLOC_LIBS="-l:libjemalloc.a" \
LIBCARES_LIBS="-l:libcares.a" \
ZLIB_LIBS="-l:libz.a" \
LIBBPF_LIBS="-L/usr/local/lib64 -l:libbpf.a -l:libelf.a" \
LDFLAGS="-static-libgcc -static-libstdc++" \
PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \
make -j$(nproc) install-strip && \
cd .. && \
rm -rf nghttp2
FROM gcr.io/distroless/base-debian11
COPY --from=build \
/usr/local/bin/h2load \
/usr/local/bin/nghttpx \
/usr/local/bin/nghttp \
/usr/local/bin/nghttpd \
/usr/local/bin/
COPY --from=build /usr/local/lib/nghttp2/reuseport_kern.o \
/usr/local/lib/nghttp2/

25
docker/README.rst Normal file
View File

@@ -0,0 +1,25 @@
Dockerfile
==========
Dockerfile creates the applications bundled with nghttp2.
These applications are:
- nghttp
- nghttpd
- nghttpx
- h2load
HTTP/3 and eBPF features are enabled.
In order to run nghttpx with HTTP/3 endpoint, you need to run the
image with the escalated privilege and higher memlock value. Here is
the example command-line to run nghttpx to listen to HTTP/3 on port
443, assuming that the current directory contains a private key and a
certificate in server.key and server.crt respectively :
.. code-block:: text
$ docker run --rm -it -v $PWD:/shared --net=host --privileged \
--ulimit memlock=2048000 nghttp2 nghttpx \
/shared/server.key /shared/server.crt \
-f'*,443;quic'

View File

@@ -35,6 +35,7 @@ AM_CPPFLAGS = \
@LIBEVENT_OPENSSL_CFLAGS@ \
@OPENSSL_CFLAGS@ \
@DEFS@
AM_LDFLAGS = @LIBTOOL_LDFLAGS@
LDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/liburl-parser.la \
@LIBEVENT_OPENSSL_LIBS@ \

View File

@@ -142,7 +142,6 @@ static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
/* Create SSL_CTX. */
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
SSL_CTX *ssl_ctx;
EC_KEY *ecdh;
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if (!ssl_ctx) {
@@ -153,14 +152,28 @@ static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (!ecdh) {
errx(1, "EC_KEY_new_by_curv_name failed: %s",
ERR_error_string(ERR_get_error(), NULL));
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
{
EVP_PKEY *ecdh;
ecdh = EVP_EC_gen("P-256");
if (!ecdh) {
errx(1, "EVP_EC_gen failed: %s", ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
EVP_PKEY_free(ecdh);
}
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
EC_KEY_free(ecdh);
#else /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */
{
EC_KEY *ecdh;
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (!ecdh) {
errx(1, "EC_KEY_new_by_curv_name failed: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
EC_KEY_free(ecdh);
}
#endif /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
errx(1, "Could not read private key file %s", key_file);

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
def name(i):

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
def name(i):

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from gentokenlookup import gentokenlookup

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
HEADERS = [
(':authority', 0),
@@ -96,47 +96,47 @@ def build_header(headers):
def gen_enum():
name = ''
print 'typedef enum {'
print('typedef enum {')
for k, token in HEADERS:
if token is None:
print ' {},'.format(to_enum_hd(k))
print(' {},'.format(to_enum_hd(k)))
else:
if name != k:
name = k
print ' {} = {},'.format(to_enum_hd(k), token)
print '} nghttp2_token;'
print(' {} = {},'.format(to_enum_hd(k), token))
print('} nghttp2_token;')
def gen_index_header():
print '''\
print('''\
static int32_t lookup_token(const uint8_t *name, size_t namelen) {
switch (namelen) {'''
switch (namelen) {''')
b = build_header(HEADERS)
for size in sorted(b.keys()):
ents = b[size]
print '''\
case {}:'''.format(size)
print '''\
switch (name[{}]) {{'''.format(size - 1)
print('''\
case {}:'''.format(size))
print('''\
switch (name[{}]) {{'''.format(size - 1))
for c in sorted(ents.keys()):
headers = sorted(ents[c])
print '''\
case '{}':'''.format(c)
print('''\
case '{}':'''.format(c))
for k in headers:
print '''\
print('''\
if (memeq("{}", name, {})) {{
return {};
}}'''.format(k[:-1], size - 1, to_enum_hd(k))
print '''\
break;'''
print '''\
}}'''.format(k[:-1], size - 1, to_enum_hd(k)))
print('''\
break;''')
print('''\
}
break;'''
print '''\
break;''')
print('''\
}
return -1;
}'''
}''')
if __name__ == '__main__':
gen_enum()
print ''
print()
gen_index_header()

29
genmethodchartbl.py Executable file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env python3
import sys
def name(i):
if i < 0x21:
return \
['NUL ', 'SOH ', 'STX ', 'ETX ', 'EOT ', 'ENQ ', 'ACK ', 'BEL ',
'BS ', 'HT ', 'LF ', 'VT ', 'FF ', 'CR ', 'SO ', 'SI ',
'DLE ', 'DC1 ', 'DC2 ', 'DC3 ', 'DC4 ', 'NAK ', 'SYN ', 'ETB ',
'CAN ', 'EM ', 'SUB ', 'ESC ', 'FS ', 'GS ', 'RS ', 'US ',
'SPC '][i]
elif i == 0x7f:
return 'DEL '
for i in range(256):
if chr(i) in ["!" , "#" , "$" , "%" , "&" , "'" , "*",
"+" , "-" , "." , "^" , "_" , "`" , "|" , "~"] or\
('0' <= chr(i) and chr(i) <= '9') or \
('A' <= chr(i) and chr(i) <= 'Z') or \
('a' <= chr(i) and chr(i) <= 'z'):
sys.stdout.write('1 /* {} */, '.format(chr(i)))
elif (0x21 <= i and i < 0x7f):
sys.stdout.write('0 /* {} */, '.format(chr(i)))
elif 0x80 <= i:
sys.stdout.write('0 /* {} */, '.format(hex(i)))
else:
sys.stdout.write('0 /* {} */, '.format(name(i)))
if (i + 1)%4 == 0:
sys.stdout.write('\n')

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env python
from __future__ import unicode_literals
#!/usr/bin/env python3
from io import StringIO
from gentokenlookup import gentokenlookup

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from gentokenlookup import gentokenlookup
@@ -113,6 +113,7 @@ OPTIONS = [
"max-request-header-fields",
"header-field-buffer",
"max-header-fields",
"no-http2-cipher-block-list",
"no-http2-cipher-black-list",
"backend-http1-tls",
"tls-session-cache-memcached-cert-file",
@@ -155,6 +156,7 @@ OPTIONS = [
"frontend-keep-alive-timeout",
"psk-secrets",
"client-psk-secrets",
"client-no-http2-cipher-block-list",
"client-no-http2-cipher-black-list",
"client-ciphers",
"accesslog-write-early",
@@ -175,6 +177,22 @@ OPTIONS = [
"tls13-ciphers",
"tls13-client-ciphers",
"no-strip-incoming-early-data",
"quic-bpf-program-file",
"no-quic-bpf",
"http2-altsvc",
"frontend-http3-read-timeout",
"frontend-quic-idle-timeout",
"frontend-quic-debug-log",
"frontend-http3-window-size",
"frontend-http3-connection-window-size",
"frontend-http3-max-window-size",
"frontend-http3-max-connection-window-size",
"frontend-http3-max-concurrent-streams",
"frontend-quic-early-data",
"frontend-quic-qlog-dir",
"frontend-quic-require-token",
"frontend-quic-congestion-controller",
"frontend-quic-connection-id-encryption-key",
]
LOGVARS = [

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
def name(i):

23
genpathchartbl.py Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env python3
import sys
def name(i):
if i < 0x21:
return \
['NUL ', 'SOH ', 'STX ', 'ETX ', 'EOT ', 'ENQ ', 'ACK ', 'BEL ',
'BS ', 'HT ', 'LF ', 'VT ', 'FF ', 'CR ', 'SO ', 'SI ',
'DLE ', 'DC1 ', 'DC2 ', 'DC3 ', 'DC4 ', 'NAK ', 'SYN ', 'ETB ',
'CAN ', 'EM ', 'SUB ', 'ESC ', 'FS ', 'GS ', 'RS ', 'US ',
'SPC '][i]
elif i == 0x7f:
return 'DEL '
for i in range(256):
if (0x21 <= i and i < 0x7f):
sys.stdout.write('1 /* {} */, '.format(chr(i)))
elif 0x80 <= i:
sys.stdout.write('1 /* {} */, '.format(hex(i)))
else:
sys.stdout.write('0 /* {} */, '.format(name(i)))
if (i + 1)%4 == 0:
sys.stdout.write('\n')

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
def to_enum_hd(k, prefix):
res = prefix
@@ -24,46 +24,46 @@ def build_header(headers):
return res
def gen_enum(tokens, prefix):
print '''\
enum {'''
print('''\
enum {''')
for k in sorted(tokens):
print '''\
{},'''.format(to_enum_hd(k, prefix))
print '''\
print('''\
{},'''.format(to_enum_hd(k, prefix)))
print('''\
{}MAXIDX,
}};'''.format(prefix)
}};'''.format(prefix))
def gen_index_header(tokens, prefix, value_type, comp_fun, return_type, fail_value):
print '''\
print('''\
{} lookup_token(const {} *name, size_t namelen) {{
switch (namelen) {{'''.format(return_type, value_type)
switch (namelen) {{'''.format(return_type, value_type))
b = build_header(tokens)
for size in sorted(b.keys()):
ents = b[size]
print '''\
case {}:'''.format(size)
print '''\
switch (name[{}]) {{'''.format(size - 1)
print('''\
case {}:'''.format(size))
print('''\
switch (name[{}]) {{'''.format(size - 1))
for c in sorted(ents.keys()):
headers = sorted(ents[c])
print '''\
case '{}':'''.format(c)
print('''\
case '{}':'''.format(c))
for k in headers:
print '''\
print('''\
if ({}("{}", name, {})) {{
return {};
}}'''.format(comp_fun, k[:-1], size - 1, to_enum_hd(k, prefix))
print '''\
break;'''
print '''\
}}'''.format(comp_fun, k[:-1], size - 1, to_enum_hd(k, prefix)))
print('''\
break;''')
print('''\
}
break;'''
print '''\
break;''')
print('''\
}}
return {};
}}'''.format(fail_value)
}}'''.format(fail_value))
def gentokenlookup(tokens, prefix, value_type='uint8_t', comp_fun='util::streq_l', return_type='int', fail_value='-1'):
gen_enum(tokens, prefix)
print ''
print()
gen_index_header(tokens, prefix, value_type, comp_fun, return_type, fail_value)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
def name(i):
@@ -20,8 +20,6 @@ for i in range(256):
sys.stdout.write('1 /* {} */, '.format(chr(i)))
elif 0x80 <= i:
sys.stdout.write('1 /* {} */, '.format(hex(i)))
elif 0 == i:
sys.stdout.write('1 /* NUL */, ')
else:
sys.stdout.write('0 /* {} */, '.format(name(i)))
if (i + 1)%4 == 0:

View File

@@ -1,10 +1,8 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# script to produce rst file from program's help output.
from __future__ import unicode_literals
from __future__ import print_function
import sys
import re
import argparse

View File

@@ -1171,3 +1171,31 @@ Content-Length: 1000000
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1ChunkedEndsPrematurely tests that an HTTP/1.1 request fails
// if the backend chunked encoded response ends prematurely.
func TestH1H1ChunkedEndsPrematurely(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
return
}
conn, bufrw, err := hj.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer conn.Close()
bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n")
bufrw.Flush()
})
defer st.Close()
_, err := st.http1(requestParam{
name: "TestH1H1ChunkedEndsPrematurely",
})
if err == nil {
t.Fatal("st.http1() should fail")
}
}

View File

@@ -565,7 +565,7 @@ func TestH2H1BadResponseCL(t *testing.T) {
t.Fatalf("Error st.http2() = %v", err)
}
want := http2.ErrCodeProtocol
want := http2.ErrCodeInternal
if res.errCode != want {
t.Errorf("res.errCode = %v; want %v", res.errCode, want)
}
@@ -2838,3 +2838,35 @@ func TestH2ResponseBeforeRequestEnd(t *testing.T) {
t.Errorf("res.status: %v; want %v", got, want)
}
}
// TestH2H1ChunkedEndsPrematurely tests that a stream is reset if the
// backend chunked encoded response ends prematurely.
func TestH2H1ChunkedEndsPrematurely(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
return
}
conn, bufrw, err := hj.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer conn.Close()
bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n")
bufrw.Flush()
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1ChunkedEndsPrematurely",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.errCode, http2.ErrCodeInternal; got != want {
t.Errorf("res.errCode = %v; want %v", got, want)
}
}

View File

@@ -24,7 +24,6 @@ set(NGHTTP2_SOURCES
nghttp2_http.c
nghttp2_rcbuf.c
nghttp2_debug.c
nghttp2_ksl.c
)
set(NGHTTP2_RES "")

View File

@@ -27,6 +27,7 @@ EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in
AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG)
AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \
@DEFS@
AM_LDFLAGS = @LIBTOOL_LDFLAGS@
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libnghttp2.pc
@@ -49,8 +50,7 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_mem.c \
nghttp2_http.c \
nghttp2_rcbuf.c \
nghttp2_debug.c \
nghttp2_ksl.c
nghttp2_debug.c
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_frame.h \
@@ -66,9 +66,8 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_mem.h \
nghttp2_http.h \
nghttp2_rcbuf.h \
nghttp2_debug.h \
nghttp2_ksl.h
nghttp2_debug.h
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
libnghttp2_la_LDFLAGS = -no-undefined \
libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)

File diff suppressed because it is too large Load Diff

View File

@@ -57,7 +57,7 @@
/* Maximum headers block size to send, calculated using
nghttp2_hd_deflate_bound(). This is the default value, and can be
overridden by nghttp2_option_set_max_send_header_block_size(). */
overridden by nghttp2_option_set_max_send_header_block_length(). */
#define NGHTTP2_MAX_HEADERSLEN 65536
/* The number of bytes for each SETTINGS entry */

View File

@@ -507,7 +507,166 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len) {
return 1;
}
/* Generated by genauthroitychartbl.py */
/* Generated by genmethodchartbl.py */
static char VALID_METHOD_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 0 /* [ */,
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
};
int nghttp2_check_method(const uint8_t *value, size_t len) {
const uint8_t *last;
if (len == 0) {
return 0;
}
for (last = value + len; value != last; ++value) {
if (!VALID_METHOD_CHARS[*value]) {
return 0;
}
}
return 1;
}
/* Generated by genpathchartbl.py */
static char VALID_PATH_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
};
int nghttp2_check_path(const uint8_t *value, size_t len) {
const uint8_t *last;
for (last = value + len; value != last; ++value) {
if (!VALID_PATH_CHARS[*value]) {
return 0;
}
}
return 1;
}
/* Generated by genauthoritychartbl.py */
static char VALID_AUTHORITY_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,

View File

@@ -360,12 +360,21 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
return NGHTTP2_ERR_IGN_HTTP_HEADER;
}
if (nv->token == NGHTTP2_TOKEN__AUTHORITY ||
nv->token == NGHTTP2_TOKEN_HOST) {
switch (nv->token) {
case NGHTTP2_TOKEN__METHOD:
rv = nghttp2_check_method(nv->value->base, nv->value->len);
break;
case NGHTTP2_TOKEN__PATH:
rv = nghttp2_check_path(nv->value->base, nv->value->len);
break;
case NGHTTP2_TOKEN__AUTHORITY:
case NGHTTP2_TOKEN_HOST:
rv = nghttp2_check_authority(nv->value->base, nv->value->len);
} else if (nv->token == NGHTTP2_TOKEN__SCHEME) {
break;
case NGHTTP2_TOKEN__SCHEME:
rv = check_scheme(nv->value->base, nv->value->len);
} else {
break;
default:
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
}

View File

@@ -1,707 +0,0 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2020 nghttp2 contributors
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp2_ksl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "nghttp2_mem.h"
static size_t ksl_nodelen(size_t keylen) {
return (sizeof(nghttp2_ksl_node) + keylen - sizeof(uint64_t) + 0xf) &
(size_t)~0xf;
}
static size_t ksl_blklen(size_t nodelen) {
return sizeof(nghttp2_ksl_blk) + nodelen * NGHTTP2_KSL_MAX_NBLK -
sizeof(uint64_t);
}
/*
* ksl_node_set_key sets |key| to |node|.
*/
static void ksl_node_set_key(nghttp2_ksl *ksl, nghttp2_ksl_node *node,
const void *key) {
memcpy(node->key, key, ksl->keylen);
}
int nghttp2_ksl_init(nghttp2_ksl *ksl, nghttp2_ksl_compar compar, size_t keylen,
nghttp2_mem *mem) {
size_t nodelen = ksl_nodelen(keylen);
size_t blklen = ksl_blklen(nodelen);
nghttp2_ksl_blk *head;
ksl->head = nghttp2_mem_malloc(mem, blklen);
if (!ksl->head) {
return NGHTTP2_ERR_NOMEM;
}
ksl->front = ksl->back = ksl->head;
ksl->compar = compar;
ksl->keylen = keylen;
ksl->nodelen = nodelen;
ksl->n = 0;
ksl->mem = mem;
head = ksl->head;
head->next = head->prev = NULL;
head->n = 0;
head->leaf = 1;
return 0;
}
/*
* ksl_free_blk frees |blk| recursively.
*/
static void ksl_free_blk(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk) {
size_t i;
if (!blk->leaf) {
for (i = 0; i < blk->n; ++i) {
ksl_free_blk(ksl, nghttp2_ksl_nth_node(ksl, blk, i)->blk);
}
}
nghttp2_mem_free(ksl->mem, blk);
}
void nghttp2_ksl_free(nghttp2_ksl *ksl) {
if (!ksl) {
return;
}
ksl_free_blk(ksl, ksl->head);
}
/*
* ksl_split_blk splits |blk| into 2 nghttp2_ksl_blk objects. The new
* nghttp2_ksl_blk is always the "right" block.
*
* It returns the pointer to the nghttp2_ksl_blk created which is the
* located at the right of |blk|, or NULL which indicates out of
* memory error.
*/
static nghttp2_ksl_blk *ksl_split_blk(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk) {
nghttp2_ksl_blk *rblk;
rblk = nghttp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
if (rblk == NULL) {
return NULL;
}
rblk->next = blk->next;
blk->next = rblk;
if (rblk->next) {
rblk->next->prev = rblk;
} else if (ksl->back == blk) {
ksl->back = rblk;
}
rblk->prev = blk;
rblk->leaf = blk->leaf;
rblk->n = blk->n / 2;
memcpy(rblk->nodes, blk->nodes + ksl->nodelen * (blk->n - rblk->n),
ksl->nodelen * rblk->n);
blk->n -= rblk->n;
assert(blk->n >= NGHTTP2_KSL_MIN_NBLK);
assert(rblk->n >= NGHTTP2_KSL_MIN_NBLK);
return rblk;
}
/*
* ksl_split_node splits a node included in |blk| at the position |i|
* into 2 adjacent nodes. The new node is always inserted at the
* position |i+1|.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
static int ksl_split_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
nghttp2_ksl_node *node;
nghttp2_ksl_blk *lblk = nghttp2_ksl_nth_node(ksl, blk, i)->blk, *rblk;
rblk = ksl_split_blk(ksl, lblk);
if (rblk == NULL) {
return NGHTTP2_ERR_NOMEM;
}
memmove(blk->nodes + (i + 2) * ksl->nodelen,
blk->nodes + (i + 1) * ksl->nodelen,
ksl->nodelen * (blk->n - (i + 1)));
node = nghttp2_ksl_nth_node(ksl, blk, i + 1);
node->blk = rblk;
++blk->n;
ksl_node_set_key(ksl, node,
nghttp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
node = nghttp2_ksl_nth_node(ksl, blk, i);
ksl_node_set_key(ksl, node,
nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
return 0;
}
/*
* ksl_split_head splits a head (root) block. It increases the height
* of skip list by 1.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
static int ksl_split_head(nghttp2_ksl *ksl) {
nghttp2_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
nghttp2_ksl_node *node;
rblk = ksl_split_blk(ksl, ksl->head);
if (rblk == NULL) {
return NGHTTP2_ERR_NOMEM;
}
lblk = ksl->head;
nhead = nghttp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
if (nhead == NULL) {
nghttp2_mem_free(ksl->mem, rblk);
return NGHTTP2_ERR_NOMEM;
}
nhead->next = nhead->prev = NULL;
nhead->n = 2;
nhead->leaf = 0;
node = nghttp2_ksl_nth_node(ksl, nhead, 0);
ksl_node_set_key(ksl, node,
nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
node->blk = lblk;
node = nghttp2_ksl_nth_node(ksl, nhead, 1);
ksl_node_set_key(ksl, node,
nghttp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
node->blk = rblk;
ksl->head = nhead;
return 0;
}
/*
* insert_node inserts a node whose key is |key| with the associated
* |data| at the index of |i|. This function assumes that the number
* of nodes contained by |blk| is strictly less than
* NGHTTP2_KSL_MAX_NBLK.
*/
static void ksl_insert_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i,
const nghttp2_ksl_key *key, void *data) {
nghttp2_ksl_node *node;
assert(blk->n < NGHTTP2_KSL_MAX_NBLK);
memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
ksl->nodelen * (blk->n - i));
node = nghttp2_ksl_nth_node(ksl, blk, i);
ksl_node_set_key(ksl, node, key);
node->data = data;
++blk->n;
}
static size_t ksl_bsearch(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk,
const nghttp2_ksl_key *key,
nghttp2_ksl_compar compar) {
ssize_t left = -1, right = (ssize_t)blk->n, mid;
nghttp2_ksl_node *node;
while (right - left > 1) {
mid = (left + right) / 2;
node = nghttp2_ksl_nth_node(ksl, blk, (size_t)mid);
if (compar((nghttp2_ksl_key *)node->key, key)) {
left = mid;
} else {
right = mid;
}
}
return (size_t)right;
}
int nghttp2_ksl_insert(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
const nghttp2_ksl_key *key, void *data) {
nghttp2_ksl_blk *blk = ksl->head;
nghttp2_ksl_node *node;
size_t i;
int rv;
if (blk->n == NGHTTP2_KSL_MAX_NBLK) {
rv = ksl_split_head(ksl);
if (rv != 0) {
return rv;
}
blk = ksl->head;
}
for (;;) {
i = ksl_bsearch(ksl, blk, key, ksl->compar);
if (blk->leaf) {
if (i < blk->n &&
!ksl->compar(key, nghttp2_ksl_nth_node(ksl, blk, i)->key)) {
if (it) {
*it = nghttp2_ksl_end(ksl);
}
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
ksl_insert_node(ksl, blk, i, key, data);
++ksl->n;
if (it) {
nghttp2_ksl_it_init(it, ksl, blk, i);
}
return 0;
}
if (i == blk->n) {
/* This insertion extends the largest key in this subtree. */
for (; !blk->leaf;) {
node = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1);
if (node->blk->n == NGHTTP2_KSL_MAX_NBLK) {
rv = ksl_split_node(ksl, blk, blk->n - 1);
if (rv != 0) {
return rv;
}
node = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1);
}
ksl_node_set_key(ksl, node, key);
blk = node->blk;
}
ksl_insert_node(ksl, blk, blk->n, key, data);
++ksl->n;
if (it) {
nghttp2_ksl_it_init(it, ksl, blk, blk->n - 1);
}
return 0;
}
node = nghttp2_ksl_nth_node(ksl, blk, i);
if (node->blk->n == NGHTTP2_KSL_MAX_NBLK) {
rv = ksl_split_node(ksl, blk, i);
if (rv != 0) {
return rv;
}
if (ksl->compar((nghttp2_ksl_key *)node->key, key)) {
node = nghttp2_ksl_nth_node(ksl, blk, i + 1);
if (ksl->compar((nghttp2_ksl_key *)node->key, key)) {
ksl_node_set_key(ksl, node, key);
}
}
}
blk = node->blk;
}
}
/*
* ksl_remove_node removes the node included in |blk| at the index of
* |i|.
*/
static void ksl_remove_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen,
ksl->nodelen * (blk->n - (i + 1)));
--blk->n;
}
/*
* ksl_merge_node merges 2 nodes which are the nodes at the index of
* |i| and |i + 1|.
*
* If |blk| is the direct descendant of head (root) block and the head
* block contains just 2 nodes, the merged block becomes head block,
* which decreases the height of |ksl| by 1.
*
* This function returns the pointer to the merged block.
*/
static nghttp2_ksl_blk *ksl_merge_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk,
size_t i) {
nghttp2_ksl_blk *lblk, *rblk;
assert(i + 1 < blk->n);
lblk = nghttp2_ksl_nth_node(ksl, blk, i)->blk;
rblk = nghttp2_ksl_nth_node(ksl, blk, i + 1)->blk;
assert(lblk->n + rblk->n < NGHTTP2_KSL_MAX_NBLK);
memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes,
ksl->nodelen * rblk->n);
lblk->n += rblk->n;
lblk->next = rblk->next;
if (lblk->next) {
lblk->next->prev = lblk;
} else if (ksl->back == rblk) {
ksl->back = lblk;
}
nghttp2_mem_free(ksl->mem, rblk);
if (ksl->head == blk && blk->n == 2) {
nghttp2_mem_free(ksl->mem, ksl->head);
ksl->head = lblk;
} else {
ksl_remove_node(ksl, blk, i + 1);
ksl_node_set_key(ksl, nghttp2_ksl_nth_node(ksl, blk, i),
nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
}
return lblk;
}
/*
* ksl_shift_left moves the first node in blk->nodes[i]->blk->nodes to
* blk->nodes[i - 1]->blk->nodes.
*/
static void ksl_shift_left(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
nghttp2_ksl_node *lnode, *rnode, *dest, *src;
assert(i > 0);
lnode = nghttp2_ksl_nth_node(ksl, blk, i - 1);
rnode = nghttp2_ksl_nth_node(ksl, blk, i);
assert(lnode->blk->n < NGHTTP2_KSL_MAX_NBLK);
assert(rnode->blk->n > NGHTTP2_KSL_MIN_NBLK);
dest = nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n);
src = nghttp2_ksl_nth_node(ksl, rnode->blk, 0);
memcpy(dest, src, ksl->nodelen);
ksl_node_set_key(ksl, lnode, dest->key);
++lnode->blk->n;
--rnode->blk->n;
memmove(rnode->blk->nodes, rnode->blk->nodes + ksl->nodelen,
ksl->nodelen * rnode->blk->n);
}
/*
* ksl_shift_right moves the last node in blk->nodes[i]->blk->nodes to
* blk->nodes[i + 1]->blk->nodes.
*/
static void ksl_shift_right(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
nghttp2_ksl_node *lnode, *rnode, *dest, *src;
assert(i < blk->n - 1);
lnode = nghttp2_ksl_nth_node(ksl, blk, i);
rnode = nghttp2_ksl_nth_node(ksl, blk, i + 1);
assert(lnode->blk->n > NGHTTP2_KSL_MIN_NBLK);
assert(rnode->blk->n < NGHTTP2_KSL_MAX_NBLK);
memmove(rnode->blk->nodes + ksl->nodelen, rnode->blk->nodes,
ksl->nodelen * rnode->blk->n);
++rnode->blk->n;
dest = nghttp2_ksl_nth_node(ksl, rnode->blk, 0);
src = nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1);
memcpy(dest, src, ksl->nodelen);
--lnode->blk->n;
ksl_node_set_key(
ksl, lnode,
nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key);
}
/*
* key_equal returns nonzero if |lhs| and |rhs| are equal using the
* function |compar|.
*/
static int key_equal(nghttp2_ksl_compar compar, const nghttp2_ksl_key *lhs,
const nghttp2_ksl_key *rhs) {
return !compar(lhs, rhs) && !compar(rhs, lhs);
}
int nghttp2_ksl_remove(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
const nghttp2_ksl_key *key) {
nghttp2_ksl_blk *blk = ksl->head;
nghttp2_ksl_node *node;
size_t i;
if (!blk->leaf && blk->n == 2 &&
nghttp2_ksl_nth_node(ksl, blk, 0)->blk->n == NGHTTP2_KSL_MIN_NBLK &&
nghttp2_ksl_nth_node(ksl, blk, 1)->blk->n == NGHTTP2_KSL_MIN_NBLK) {
blk = ksl_merge_node(ksl, ksl->head, 0);
}
for (;;) {
i = ksl_bsearch(ksl, blk, key, ksl->compar);
if (i == blk->n) {
if (it) {
*it = nghttp2_ksl_end(ksl);
}
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
if (blk->leaf) {
if (ksl->compar(key, nghttp2_ksl_nth_node(ksl, blk, i)->key)) {
if (it) {
*it = nghttp2_ksl_end(ksl);
}
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
ksl_remove_node(ksl, blk, i);
--ksl->n;
if (it) {
if (blk->n == i && blk->next) {
nghttp2_ksl_it_init(it, ksl, blk->next, 0);
} else {
nghttp2_ksl_it_init(it, ksl, blk, i);
}
}
return 0;
}
node = nghttp2_ksl_nth_node(ksl, blk, i);
if (node->blk->n == NGHTTP2_KSL_MIN_NBLK) {
if (i > 0 && nghttp2_ksl_nth_node(ksl, blk, i - 1)->blk->n >
NGHTTP2_KSL_MIN_NBLK) {
ksl_shift_right(ksl, blk, i - 1);
blk = node->blk;
} else if (i + 1 < blk->n &&
nghttp2_ksl_nth_node(ksl, blk, i + 1)->blk->n >
NGHTTP2_KSL_MIN_NBLK) {
ksl_shift_left(ksl, blk, i + 1);
blk = node->blk;
} else if (i > 0) {
blk = ksl_merge_node(ksl, blk, i - 1);
} else {
assert(i + 1 < blk->n);
blk = ksl_merge_node(ksl, blk, i);
}
} else {
blk = node->blk;
}
}
}
nghttp2_ksl_it nghttp2_ksl_lower_bound(nghttp2_ksl *ksl,
const nghttp2_ksl_key *key) {
nghttp2_ksl_blk *blk = ksl->head;
nghttp2_ksl_it it;
size_t i;
for (;;) {
i = ksl_bsearch(ksl, blk, key, ksl->compar);
if (blk->leaf) {
if (i == blk->n && blk->next) {
blk = blk->next;
i = 0;
}
nghttp2_ksl_it_init(&it, ksl, blk, i);
return it;
}
if (i == blk->n) {
/* This happens if descendant has smaller key. Fast forward to
find last node in this subtree. */
for (; !blk->leaf; blk = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
;
if (blk->next) {
blk = blk->next;
i = 0;
} else {
i = blk->n;
}
nghttp2_ksl_it_init(&it, ksl, blk, i);
return it;
}
blk = nghttp2_ksl_nth_node(ksl, blk, i)->blk;
}
}
nghttp2_ksl_it nghttp2_ksl_lower_bound_compar(nghttp2_ksl *ksl,
const nghttp2_ksl_key *key,
nghttp2_ksl_compar compar) {
nghttp2_ksl_blk *blk = ksl->head;
nghttp2_ksl_it it;
size_t i;
for (;;) {
i = ksl_bsearch(ksl, blk, key, compar);
if (blk->leaf) {
if (i == blk->n && blk->next) {
blk = blk->next;
i = 0;
}
nghttp2_ksl_it_init(&it, ksl, blk, i);
return it;
}
if (i == blk->n) {
/* This happens if descendant has smaller key. Fast forward to
find last node in this subtree. */
for (; !blk->leaf; blk = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
;
if (blk->next) {
blk = blk->next;
i = 0;
} else {
i = blk->n;
}
nghttp2_ksl_it_init(&it, ksl, blk, i);
return it;
}
blk = nghttp2_ksl_nth_node(ksl, blk, i)->blk;
}
}
void nghttp2_ksl_update_key(nghttp2_ksl *ksl, const nghttp2_ksl_key *old_key,
const nghttp2_ksl_key *new_key) {
nghttp2_ksl_blk *blk = ksl->head;
nghttp2_ksl_node *node;
size_t i;
for (;;) {
i = ksl_bsearch(ksl, blk, old_key, ksl->compar);
assert(i < blk->n);
node = nghttp2_ksl_nth_node(ksl, blk, i);
if (blk->leaf) {
assert(key_equal(ksl->compar, (nghttp2_ksl_key *)node->key, old_key));
ksl_node_set_key(ksl, node, new_key);
return;
}
if (key_equal(ksl->compar, (nghttp2_ksl_key *)node->key, old_key) ||
ksl->compar((nghttp2_ksl_key *)node->key, new_key)) {
ksl_node_set_key(ksl, node, new_key);
}
blk = node->blk;
}
}
static void ksl_print(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t level) {
size_t i;
nghttp2_ksl_node *node;
fprintf(stderr, "LV=%zu n=%zu\n", level, blk->n);
if (blk->leaf) {
for (i = 0; i < blk->n; ++i) {
node = nghttp2_ksl_nth_node(ksl, blk, i);
fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key);
}
fprintf(stderr, "\n");
return;
}
for (i = 0; i < blk->n; ++i) {
ksl_print(ksl, nghttp2_ksl_nth_node(ksl, blk, i)->blk, level + 1);
}
}
size_t nghttp2_ksl_len(nghttp2_ksl *ksl) { return ksl->n; }
void nghttp2_ksl_clear(nghttp2_ksl *ksl) {
size_t i;
nghttp2_ksl_blk *head;
if (!ksl->head->leaf) {
for (i = 0; i < ksl->head->n; ++i) {
ksl_free_blk(ksl, nghttp2_ksl_nth_node(ksl, ksl->head, i)->blk);
}
}
ksl->front = ksl->back = ksl->head;
ksl->n = 0;
head = ksl->head;
head->next = head->prev = NULL;
head->n = 0;
head->leaf = 1;
}
void nghttp2_ksl_print(nghttp2_ksl *ksl) { ksl_print(ksl, ksl->head, 0); }
nghttp2_ksl_it nghttp2_ksl_begin(const nghttp2_ksl *ksl) {
nghttp2_ksl_it it;
nghttp2_ksl_it_init(&it, ksl, ksl->front, 0);
return it;
}
nghttp2_ksl_it nghttp2_ksl_end(const nghttp2_ksl *ksl) {
nghttp2_ksl_it it;
nghttp2_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
return it;
}
void nghttp2_ksl_it_init(nghttp2_ksl_it *it, const nghttp2_ksl *ksl,
nghttp2_ksl_blk *blk, size_t i) {
it->ksl = ksl;
it->blk = blk;
it->i = i;
}
void *nghttp2_ksl_it_get(const nghttp2_ksl_it *it) {
assert(it->i < it->blk->n);
return nghttp2_ksl_nth_node(it->ksl, it->blk, it->i)->data;
}
void nghttp2_ksl_it_prev(nghttp2_ksl_it *it) {
assert(!nghttp2_ksl_it_begin(it));
if (it->i == 0) {
it->blk = it->blk->prev;
it->i = it->blk->n - 1;
} else {
--it->i;
}
}
int nghttp2_ksl_it_begin(const nghttp2_ksl_it *it) {
return it->i == 0 && it->blk->prev == NULL;
}

View File

@@ -1,315 +0,0 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2020 nghttp2 contributors
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_KSL_H
#define NGHTTP2_KSL_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <stdlib.h>
#include <nghttp2/nghttp2.h>
/*
* Skip List using single key instead of range.
*/
#define NGHTTP2_KSL_DEGR 16
/* NGHTTP2_KSL_MAX_NBLK is the maximum number of nodes which a single
block can contain. */
#define NGHTTP2_KSL_MAX_NBLK (2 * NGHTTP2_KSL_DEGR - 1)
/* NGHTTP2_KSL_MIN_NBLK is the minimum number of nodes which a single
block other than root must contains. */
#define NGHTTP2_KSL_MIN_NBLK (NGHTTP2_KSL_DEGR - 1)
/*
* nghttp2_ksl_key represents key in nghttp2_ksl.
*/
typedef void nghttp2_ksl_key;
struct nghttp2_ksl_node;
typedef struct nghttp2_ksl_node nghttp2_ksl_node;
struct nghttp2_ksl_blk;
typedef struct nghttp2_ksl_blk nghttp2_ksl_blk;
/*
* nghttp2_ksl_node is a node which contains either nghttp2_ksl_blk or
* opaque data. If a node is an internal node, it contains
* nghttp2_ksl_blk. Otherwise, it has data. The key is stored at the
* location starting at key.
*/
struct nghttp2_ksl_node {
union {
nghttp2_ksl_blk *blk;
void *data;
};
union {
uint64_t align;
/* key is a buffer to include key associated to this node.
Because the length of key is unknown until nghttp2_ksl_init is
called, the actual buffer will be allocated after this
field. */
uint8_t key[1];
};
};
/*
* nghttp2_ksl_blk contains nghttp2_ksl_node objects.
*/
struct nghttp2_ksl_blk {
/* next points to the next block if leaf field is nonzero. */
nghttp2_ksl_blk *next;
/* prev points to the previous block if leaf field is nonzero. */
nghttp2_ksl_blk *prev;
/* n is the number of nodes this object contains in nodes. */
size_t n;
/* leaf is nonzero if this block contains leaf nodes. */
int leaf;
union {
uint64_t align;
/* nodes is a buffer to contain NGHTTP2_KSL_MAX_NBLK
nghttp2_ksl_node objects. Because nghttp2_ksl_node object is
allocated along with the additional variable length key
storage, the size of buffer is unknown until nghttp2_ksl_init is
called. */
uint8_t nodes[1];
};
};
/*
* nghttp2_ksl_compar is a function type which returns nonzero if key
* |lhs| should be placed before |rhs|. It returns 0 otherwise.
*/
typedef int (*nghttp2_ksl_compar)(const nghttp2_ksl_key *lhs,
const nghttp2_ksl_key *rhs);
struct nghttp2_ksl;
typedef struct nghttp2_ksl nghttp2_ksl;
struct nghttp2_ksl_it;
typedef struct nghttp2_ksl_it nghttp2_ksl_it;
/*
* nghttp2_ksl_it is a forward iterator to iterate nodes.
*/
struct nghttp2_ksl_it {
const nghttp2_ksl *ksl;
nghttp2_ksl_blk *blk;
size_t i;
};
/*
* nghttp2_ksl is a deterministic paged skip list.
*/
struct nghttp2_ksl {
/* head points to the root block. */
nghttp2_ksl_blk *head;
/* front points to the first leaf block. */
nghttp2_ksl_blk *front;
/* back points to the last leaf block. */
nghttp2_ksl_blk *back;
nghttp2_ksl_compar compar;
size_t n;
/* keylen is the size of key */
size_t keylen;
/* nodelen is the actual size of nghttp2_ksl_node including key
storage. */
size_t nodelen;
nghttp2_mem *mem;
};
/*
* nghttp2_ksl_init initializes |ksl|. |compar| specifies compare
* function. |keylen| is the length of key.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_ksl_init(nghttp2_ksl *ksl, nghttp2_ksl_compar compar, size_t keylen,
nghttp2_mem *mem);
/*
* nghttp2_ksl_free frees resources allocated for |ksl|. If |ksl| is
* NULL, this function does nothing. It does not free the memory
* region pointed by |ksl| itself.
*/
void nghttp2_ksl_free(nghttp2_ksl *ksl);
/*
* nghttp2_ksl_insert inserts |key| with its associated |data|. On
* successful insertion, the iterator points to the inserted node is
* stored in |*it|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_INVALID_ARGUMENT
* |key| already exists.
*/
int nghttp2_ksl_insert(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
const nghttp2_ksl_key *key, void *data);
/*
* nghttp2_ksl_remove removes the |key| from |ksl|.
*
* This function assigns the iterator to |*it|, which points to the
* node which is located at the right next of the removed node if |it|
* is not NULL. If |key| is not found, no deletion takes place and
* the return value of nghttp2_ksl_end(ksl) is assigned to |*it|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
* |key| does not exist.
*/
int nghttp2_ksl_remove(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
const nghttp2_ksl_key *key);
/*
* nghttp2_ksl_lower_bound returns the iterator which points to the
* first node which has the key which is equal to |key| or the last
* node which satisfies !compar(&node->key, key). If there is no such
* node, it returns the iterator which satisfies nghttp2_ksl_it_end(it)
* != 0.
*/
nghttp2_ksl_it nghttp2_ksl_lower_bound(nghttp2_ksl *ksl,
const nghttp2_ksl_key *key);
/*
* nghttp2_ksl_lower_bound_compar works like nghttp2_ksl_lower_bound,
* but it takes custom function |compar| to do lower bound search.
*/
nghttp2_ksl_it nghttp2_ksl_lower_bound_compar(nghttp2_ksl *ksl,
const nghttp2_ksl_key *key,
nghttp2_ksl_compar compar);
/*
* nghttp2_ksl_update_key replaces the key of nodes which has |old_key|
* with |new_key|. |new_key| must be strictly greater than the
* previous node and strictly smaller than the next node.
*/
void nghttp2_ksl_update_key(nghttp2_ksl *ksl, const nghttp2_ksl_key *old_key,
const nghttp2_ksl_key *new_key);
/*
* nghttp2_ksl_begin returns the iterator which points to the first
* node. If there is no node in |ksl|, it returns the iterator which
* satisfies nghttp2_ksl_it_end(it) != 0.
*/
nghttp2_ksl_it nghttp2_ksl_begin(const nghttp2_ksl *ksl);
/*
* nghttp2_ksl_end returns the iterator which points to the node
* following the last node. The returned object satisfies
* nghttp2_ksl_it_end(). If there is no node in |ksl|, it returns the
* iterator which satisfies nghttp2_ksl_it_begin(it) != 0.
*/
nghttp2_ksl_it nghttp2_ksl_end(const nghttp2_ksl *ksl);
/*
* nghttp2_ksl_len returns the number of elements stored in |ksl|.
*/
size_t nghttp2_ksl_len(nghttp2_ksl *ksl);
/*
* nghttp2_ksl_clear removes all elements stored in |ksl|.
*/
void nghttp2_ksl_clear(nghttp2_ksl *ksl);
/*
* nghttp2_ksl_nth_node returns the |n|th node under |blk|.
*/
#define nghttp2_ksl_nth_node(KSL, BLK, N) \
((nghttp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
/*
* nghttp2_ksl_print prints its internal state in stderr. It assumes
* that the key is of type int64_t. This function should be used for
* the debugging purpose only.
*/
void nghttp2_ksl_print(nghttp2_ksl *ksl);
/*
* nghttp2_ksl_it_init initializes |it|.
*/
void nghttp2_ksl_it_init(nghttp2_ksl_it *it, const nghttp2_ksl *ksl,
nghttp2_ksl_blk *blk, size_t i);
/*
* nghttp2_ksl_it_get returns the data associated to the node which
* |it| points to. It is undefined to call this function when
* nghttp2_ksl_it_end(it) returns nonzero.
*/
void *nghttp2_ksl_it_get(const nghttp2_ksl_it *it);
/*
* nghttp2_ksl_it_next advances the iterator by one. It is undefined
* if this function is called when nghttp2_ksl_it_end(it) returns
* nonzero.
*/
#define nghttp2_ksl_it_next(IT) \
(++(IT)->i == (IT)->blk->n && (IT)->blk->next \
? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \
: 0)
/*
* nghttp2_ksl_it_prev moves backward the iterator by one. It is
* undefined if this function is called when nghttp2_ksl_it_begin(it)
* returns nonzero.
*/
void nghttp2_ksl_it_prev(nghttp2_ksl_it *it);
/*
* nghttp2_ksl_it_end returns nonzero if |it| points to the beyond the
* last node.
*/
#define nghttp2_ksl_it_end(IT) \
((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
/*
* nghttp2_ksl_it_begin returns nonzero if |it| points to the first
* node. |it| might satisfy both nghttp2_ksl_it_begin(&it) and
* nghttp2_ksl_it_end(&it) if the skip list has no node.
*/
int nghttp2_ksl_it_begin(const nghttp2_ksl_it *it);
/*
* nghttp2_ksl_key returns the key of the node which |it| points to.
* It is undefined to call this function when nghttp2_ksl_it_end(it)
* returns nonzero.
*/
#define nghttp2_ksl_it_key(IT) \
((nghttp2_ksl_key *)nghttp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
#endif /* NGHTTP2_KSL_H */

View File

@@ -27,14 +27,16 @@
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "nghttp2_helper.h"
#define INITIAL_TABLE_LENGTH 256
#define NGHTTP2_INITIAL_TABLE_LENBITS 8
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
map->mem = mem;
map->tablelen = INITIAL_TABLE_LENGTH;
map->tablelen = 1 << NGHTTP2_INITIAL_TABLE_LENBITS;
map->tablelenbits = NGHTTP2_INITIAL_TABLE_LENBITS;
map->table =
nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_bucket));
if (map->table == NULL) {
@@ -47,151 +49,145 @@ int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
}
void nghttp2_map_free(nghttp2_map *map) {
size_t i;
nghttp2_map_bucket *bkt;
if (!map) {
return;
}
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->ksl) {
nghttp2_ksl_free(bkt->ksl);
nghttp2_mem_free(map->mem, bkt->ksl);
}
}
nghttp2_mem_free(map->mem, map->table);
}
void nghttp2_map_each_free(nghttp2_map *map,
int (*func)(nghttp2_map_entry *entry, void *ptr),
void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
uint32_t i;
nghttp2_map_bucket *bkt;
nghttp2_ksl_it it;
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->ptr) {
func(bkt->ptr, ptr);
bkt->ptr = NULL;
assert(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0);
if (bkt->data == NULL) {
continue;
}
if (bkt->ksl) {
for (it = nghttp2_ksl_begin(bkt->ksl); !nghttp2_ksl_it_end(&it);
nghttp2_ksl_it_next(&it)) {
func(nghttp2_ksl_it_get(&it), ptr);
}
nghttp2_ksl_free(bkt->ksl);
nghttp2_mem_free(map->mem, bkt->ksl);
bkt->ksl = NULL;
}
func(bkt->data, ptr);
}
}
int nghttp2_map_each(nghttp2_map *map,
int (*func)(nghttp2_map_entry *entry, void *ptr),
int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
int rv;
uint32_t i;
nghttp2_map_bucket *bkt;
nghttp2_ksl_it it;
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->ptr) {
rv = func(bkt->ptr, ptr);
if (rv != 0) {
return rv;
}
assert(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0);
if (bkt->data == NULL) {
continue;
}
if (bkt->ksl) {
for (it = nghttp2_ksl_begin(bkt->ksl); !nghttp2_ksl_it_end(&it);
nghttp2_ksl_it_next(&it)) {
rv = func(nghttp2_ksl_it_get(&it), ptr);
if (rv != 0) {
return rv;
}
}
}
}
return 0;
}
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) {
entry->key = key;
entry->next = NULL;
}
/* FNV1a hash */
static uint32_t hash(key_type key, uint32_t mod) {
uint8_t *p, *end;
uint32_t h = 0x811C9DC5u;
p = (uint8_t *)&key;
end = p + sizeof(key_type);
for (; p != end;) {
h ^= *p++;
h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
}
return h & (mod - 1);
}
static int less(const nghttp2_ksl_key *lhs, const nghttp2_ksl_key *rhs) {
return *(key_type *)lhs < *(key_type *)rhs;
}
static int map_insert(nghttp2_map *map, nghttp2_map_bucket *table,
uint32_t tablelen, nghttp2_map_entry *entry) {
uint32_t h = hash(entry->key, tablelen);
nghttp2_map_bucket *bkt = &table[h];
nghttp2_mem *mem = map->mem;
int rv;
if (bkt->ptr == NULL &&
(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0)) {
bkt->ptr = entry;
return 0;
}
if (!bkt->ksl) {
bkt->ksl = nghttp2_mem_malloc(mem, sizeof(*bkt->ksl));
if (bkt->ksl == NULL) {
return NGHTTP2_ERR_NOMEM;
}
nghttp2_ksl_init(bkt->ksl, less, sizeof(key_type), mem);
}
if (bkt->ptr) {
rv = nghttp2_ksl_insert(bkt->ksl, NULL, &bkt->ptr->key, bkt->ptr);
rv = func(bkt->data, ptr);
if (rv != 0) {
return rv;
}
bkt->ptr = NULL;
}
return nghttp2_ksl_insert(bkt->ksl, NULL, &entry->key, entry);
return 0;
}
/* new_tablelen must be power of 2 */
static int map_resize(nghttp2_map *map, uint32_t new_tablelen) {
static uint32_t hash(nghttp2_map_key_type key) {
return (uint32_t)key * 2654435769u;
}
static size_t h2idx(uint32_t hash, uint32_t bits) {
return hash >> (32 - bits);
}
static size_t distance(uint32_t tablelen, uint32_t tablelenbits,
nghttp2_map_bucket *bkt, size_t idx) {
return (idx - h2idx(bkt->hash, tablelenbits)) & (tablelen - 1);
}
static void map_bucket_swap(nghttp2_map_bucket *bkt, uint32_t *phash,
nghttp2_map_key_type *pkey, void **pdata) {
uint32_t h = bkt->hash;
nghttp2_map_key_type key = bkt->key;
void *data = bkt->data;
bkt->hash = *phash;
bkt->key = *pkey;
bkt->data = *pdata;
*phash = h;
*pkey = key;
*pdata = data;
}
static void map_bucket_set_data(nghttp2_map_bucket *bkt, uint32_t hash,
nghttp2_map_key_type key, void *data) {
bkt->hash = hash;
bkt->key = key;
bkt->data = data;
}
void nghttp2_map_print_distance(nghttp2_map *map) {
uint32_t i;
size_t idx;
nghttp2_map_bucket *bkt;
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
fprintf(stderr, "@%u <EMPTY>\n", i);
continue;
}
idx = h2idx(bkt->hash, map->tablelenbits);
fprintf(stderr, "@%u hash=%08x key=%d base=%zu distance=%zu\n", i,
bkt->hash, bkt->key, idx,
distance(map->tablelen, map->tablelenbits, bkt, idx));
}
}
static int insert(nghttp2_map_bucket *table, uint32_t tablelen,
uint32_t tablelenbits, uint32_t hash,
nghttp2_map_key_type key, void *data) {
size_t idx = h2idx(hash, tablelenbits);
size_t d = 0, dd;
nghttp2_map_bucket *bkt;
for (;;) {
bkt = &table[idx];
if (bkt->data == NULL) {
map_bucket_set_data(bkt, hash, key, data);
return 0;
}
dd = distance(tablelen, tablelenbits, bkt, idx);
if (d > dd) {
map_bucket_swap(bkt, &hash, &key, &data);
d = dd;
} else if (bkt->key == key) {
/* TODO This check is just a waste after first swap or if this
function is called from map_resize. That said, there is no
difference with or without this conditional in performance
wise. */
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
++d;
idx = (idx + 1) & (tablelen - 1);
}
}
/* new_tablelen must be power of 2 and new_tablelen == (1 <<
new_tablelenbits) must hold. */
static int map_resize(nghttp2_map *map, uint32_t new_tablelen,
uint32_t new_tablelenbits) {
uint32_t i;
nghttp2_map_bucket *new_table;
nghttp2_map_bucket *bkt;
nghttp2_ksl_it it;
int rv;
new_table =
@@ -202,64 +198,38 @@ static int map_resize(nghttp2_map *map, uint32_t new_tablelen) {
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->ptr) {
rv = map_insert(map, new_table, new_tablelen, bkt->ptr);
if (rv != 0) {
goto fail;
}
assert(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0);
if (bkt->data == NULL) {
continue;
}
rv = insert(new_table, new_tablelen, new_tablelenbits, bkt->hash, bkt->key,
bkt->data);
if (bkt->ksl) {
for (it = nghttp2_ksl_begin(bkt->ksl); !nghttp2_ksl_it_end(&it);
nghttp2_ksl_it_next(&it)) {
rv = map_insert(map, new_table, new_tablelen, nghttp2_ksl_it_get(&it));
if (rv != 0) {
goto fail;
}
}
}
}
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->ksl) {
nghttp2_ksl_free(bkt->ksl);
nghttp2_mem_free(map->mem, bkt->ksl);
}
assert(0 == rv);
}
nghttp2_mem_free(map->mem, map->table);
map->tablelen = new_tablelen;
map->tablelenbits = new_tablelenbits;
map->table = new_table;
return 0;
fail:
for (i = 0; i < new_tablelen; ++i) {
bkt = &new_table[i];
if (bkt->ksl) {
nghttp2_ksl_free(bkt->ksl);
nghttp2_mem_free(map->mem, bkt->ksl);
}
}
return rv;
}
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
int rv;
assert(data);
/* Load factor is 0.75 */
if ((map->size + 1) * 4 > map->tablelen * 3) {
rv = map_resize(map, map->tablelen * 2);
rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
if (rv != 0) {
return rv;
}
}
rv = map_insert(map, map->table, map->tablelen, new_entry);
rv = insert(map->table, map->tablelen, map->tablelenbits, hash(key), key,
data);
if (rv != 0) {
return rv;
}
@@ -267,68 +237,75 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
return 0;
}
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) {
nghttp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
nghttp2_ksl_it it;
void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
uint32_t h = hash(key);
size_t idx = h2idx(h, map->tablelenbits);
nghttp2_map_bucket *bkt;
size_t d = 0;
if (bkt->ptr) {
if (bkt->ptr->key == key) {
return bkt->ptr;
}
return NULL;
}
for (;;) {
bkt = &map->table[idx];
if (bkt->ksl) {
it = nghttp2_ksl_lower_bound(bkt->ksl, &key);
if (nghttp2_ksl_it_end(&it) ||
*(key_type *)nghttp2_ksl_it_key(&it) != key) {
if (bkt->data == NULL ||
d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
return NULL;
}
return nghttp2_ksl_it_get(&it);
}
return NULL;
if (bkt->key == key) {
return bkt->data;
}
++d;
idx = (idx + 1) & (map->tablelen - 1);
}
}
int nghttp2_map_remove(nghttp2_map *map, key_type key) {
nghttp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
int rv;
int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
uint32_t h = hash(key);
size_t idx = h2idx(h, map->tablelenbits), didx;
nghttp2_map_bucket *bkt;
size_t d = 0;
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL ||
d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
if (bkt->key == key) {
map_bucket_set_data(bkt, 0, 0, NULL);
didx = idx;
idx = (idx + 1) & (map->tablelen - 1);
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL ||
distance(map->tablelen, map->tablelenbits, bkt, idx) == 0) {
break;
}
map->table[didx] = *bkt;
map_bucket_set_data(bkt, 0, 0, NULL);
didx = idx;
idx = (idx + 1) & (map->tablelen - 1);
}
if (bkt->ptr) {
if (bkt->ptr->key == key) {
bkt->ptr = NULL;
--map->size;
return 0;
}
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
if (bkt->ksl) {
rv = nghttp2_ksl_remove(bkt->ksl, NULL, &key);
if (rv != 0) {
return rv;
}
--map->size;
return 0;
++d;
idx = (idx + 1) & (map->tablelen - 1);
}
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
void nghttp2_map_clear(nghttp2_map *map) {
uint32_t i;
nghttp2_map_bucket *bkt;
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
bkt->ptr = NULL;
if (bkt->ksl) {
nghttp2_ksl_free(bkt->ksl);
nghttp2_mem_free(map->mem, bkt->ksl);
bkt->ksl = NULL;
}
}
memset(map->table, 0, sizeof(*map->table) * map->tablelen);
map->size = 0;
}

View File

@@ -33,31 +33,23 @@
#include <nghttp2/nghttp2.h>
#include "nghttp2_mem.h"
#include "nghttp2_ksl.h"
/* Implementation of unordered map */
typedef int32_t key_type;
typedef struct nghttp2_map_entry {
struct nghttp2_map_entry *next;
key_type key;
#if SIZEOF_INT_P == 4
/* we requires 8 bytes aligment */
int64_t pad;
#endif
} nghttp2_map_entry;
typedef int32_t nghttp2_map_key_type;
typedef struct nghttp2_map_bucket {
nghttp2_map_entry *ptr;
nghttp2_ksl *ksl;
uint32_t hash;
nghttp2_map_key_type key;
void *data;
} nghttp2_map_bucket;
typedef struct {
typedef struct nghttp2_map {
nghttp2_map_bucket *table;
nghttp2_mem *mem;
size_t size;
uint32_t tablelen;
uint32_t tablelenbits;
} nghttp2_map;
/*
@@ -81,21 +73,14 @@ void nghttp2_map_free(nghttp2_map *map);
/*
* Deallocates each entries using |func| function and any resources
* allocated for |map|. The |func| function is responsible for freeing
* given the |entry| object. The |ptr| will be passed to the |func| as
* given the |data| object. The |ptr| will be passed to the |func| as
* send argument. The return value of the |func| will be ignored.
*/
void nghttp2_map_each_free(nghttp2_map *map,
int (*func)(nghttp2_map_entry *entry, void *ptr),
void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr);
/*
* Initializes the |entry| with the |key|. All entries to be inserted
* to the map must be initialized with this function.
*/
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
/*
* Inserts the new |entry| with the key |entry->key| to the map |map|.
* Inserts the new |data| with the |key| to the map |map|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -105,25 +90,25 @@ void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data);
/*
* Returns the entry associated by the key |key|. If there is no such
* entry, this function returns NULL.
* Returns the data associated by the key |key|. If there is no such
* data, this function returns NULL.
*/
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key);
/*
* Removes the entry associated by the key |key| from the |map|. The
* removed entry is not freed by this function.
* Removes the data associated by the key |key| from the |map|. The
* removed data is not freed by this function.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
* The entry associated by |key| does not exist.
* The data associated by |key| does not exist.
*/
int nghttp2_map_remove(nghttp2_map *map, key_type key);
int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key);
/*
* Removes all entries from |map|.
@@ -136,21 +121,22 @@ void nghttp2_map_clear(nghttp2_map *map);
size_t nghttp2_map_size(nghttp2_map *map);
/*
* Applies the function |func| to each entry in the |map| with the
* Applies the function |func| to each data in the |map| with the
* optional user supplied pointer |ptr|.
*
* If the |func| returns 0, this function calls the |func| with the
* next entry. If the |func| returns nonzero, it will not call the
* next data. If the |func| returns nonzero, it will not call the
* |func| for further entries and return the return value of the
* |func| immediately. Thus, this function returns 0 if all the
* invocations of the |func| return 0, or nonzero value which the last
* invocation of |func| returns.
*
* Don't use this function to free each entry. Use
* Don't use this function to free each data. Use
* nghttp2_map_each_free() instead.
*/
int nghttp2_map_each(nghttp2_map *map,
int (*func)(nghttp2_map_entry *entry, void *ptr),
int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr);
void nghttp2_map_print_distance(nghttp2_map *map);
#endif /* NGHTTP2_MAP_H */

View File

@@ -666,7 +666,7 @@ int nghttp2_session_server_new3(nghttp2_session **session_ptr,
return 0;
}
static int free_streams(nghttp2_map_entry *entry, void *ptr) {
static int free_streams(void *entry, void *ptr) {
nghttp2_session *session;
nghttp2_stream *stream;
nghttp2_outbound_item *item;
@@ -1102,7 +1102,7 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
(int32_t)session->local_settings.initial_window_size,
stream_user_data, mem);
rv = nghttp2_map_insert(&session->streams, &stream->map_entry);
rv = nghttp2_map_insert(&session->streams, stream_id, stream);
if (rv != 0) {
nghttp2_stream_free(stream);
nghttp2_mem_free(mem, stream);
@@ -2424,7 +2424,7 @@ static int session_call_on_frame_send(nghttp2_session *session,
return 0;
}
static int find_stream_on_goaway_func(nghttp2_map_entry *entry, void *ptr) {
static int find_stream_on_goaway_func(void *entry, void *ptr) {
nghttp2_close_stream_on_goaway_arg *arg;
nghttp2_stream *stream;
@@ -4194,8 +4194,7 @@ static int session_process_rst_stream_frame(nghttp2_session *session) {
return nghttp2_session_on_rst_stream_received(session, frame);
}
static int update_remote_initial_window_size_func(nghttp2_map_entry *entry,
void *ptr) {
static int update_remote_initial_window_size_func(void *entry, void *ptr) {
int rv;
nghttp2_update_window_size_arg *arg;
nghttp2_stream *stream;
@@ -4248,8 +4247,7 @@ session_update_remote_initial_window_size(nghttp2_session *session,
update_remote_initial_window_size_func, &arg);
}
static int update_local_initial_window_size_func(nghttp2_map_entry *entry,
void *ptr) {
static int update_local_initial_window_size_func(void *entry, void *ptr) {
int rv;
nghttp2_update_window_size_arg *arg;
nghttp2_stream *stream;
@@ -6432,8 +6430,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
/* CONTINUATION won't bear NGHTTP2_PADDED flag */
iframe->frame.hd.flags = (uint8_t)(
iframe->frame.hd.flags | (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS));
iframe->frame.hd.flags =
(uint8_t)(iframe->frame.hd.flags |
(cont_hd.flags & NGHTTP2_FLAG_END_HEADERS));
iframe->frame.hd.length += cont_hd.length;
busy = 1;

View File

@@ -62,7 +62,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
int32_t weight, int32_t remote_initial_window_size,
int32_t local_initial_window_size,
void *stream_user_data, nghttp2_mem *mem) {
nghttp2_map_entry_init(&stream->map_entry, (key_type)stream_id);
nghttp2_pq_init(&stream->obq, stream_less, mem);
stream->stream_id = stream_id;

View File

@@ -135,8 +135,6 @@ typedef enum {
} nghttp2_http_flag;
struct nghttp2_stream {
/* Intrusive Map */
nghttp2_map_entry map_entry;
/* Entry for dep_prev->obq */
nghttp2_pq_entry pq_entry;
/* Priority Queue storing direct descendant (nghttp2_stream). Only

View File

@@ -1,5 +1,5 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_python_devel.html
# https://www.gnu.org/software/autoconf-archive/ax_python_devel.html
# ===========================================================================
#
# SYNOPSIS
@@ -12,8 +12,8 @@
# in your configure.ac.
#
# This macro checks for Python and tries to get the include path to
# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS)
# output variables. It also exports $(PYTHON_EXTRA_LIBS) and
# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LIBS) output
# variables. It also exports $(PYTHON_EXTRA_LIBS) and
# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
#
# You can search for some particular version of Python by passing a
@@ -52,7 +52,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -67,7 +67,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 16
#serial 21
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
AC_DEFUN([AX_PYTHON_DEVEL],[
@@ -81,12 +81,10 @@ AC_DEFUN([AX_PYTHON_DEVEL],[
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
if test -z "$PYTHON"; then
AC_MSG_WARN([Cannot find python$PYTHON_VERSION in your system path])
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
PYTHON_VERSION=""
no_python_devel=yes
fi
AS_IF([test -z "$no_python_devel"], [
#
# Check for a version of Python >= 2.1.0
#
@@ -97,25 +95,22 @@ AS_IF([test -z "$no_python_devel"], [
if test "$ac_supports_python_ver" != "True"; then
if test -z "$PYTHON_NOVERSIONCHECK"; then
AC_MSG_RESULT([no])
AC_MSG_WARN([
AC_MSG_FAILURE([
This version of the AC@&t@_PYTHON_DEVEL macro
doesn't work properly with versions of Python before
2.1.0. You may need to re-run configure, setting the
variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG,
variables PYTHON_CPPFLAGS, PYTHON_LIBS, PYTHON_SITE_PKG,
PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
to something else than an empty string.
])
no_python_devel=yes
else
AC_MSG_RESULT([skip at user request])
fi
else
AC_MSG_RESULT([yes])
fi
]) # AS_IF
AS_IF([test -z "$no_python_devel"], [
#
# if the macro parameter ``version'' is set, honour it
#
@@ -128,36 +123,30 @@ AS_IF([test -z "$no_python_devel"], [
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_WARN([this package requires Python $1.
AC_MSG_ERROR([this package requires Python $1.
If you have it installed, but it isn't the default Python
interpreter in your system path, please pass the PYTHON_VERSION
variable to configure. See ``configure --help'' for reference.
])
PYTHON_VERSION=""
no_python_devel=yes
fi
fi
]) # AS_IF
AS_IF([test -z "$no_python_devel"], [
#
# Check if you have distutils, else fail
#
AC_MSG_CHECKING([for the distutils Python package])
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
if test -z "$ac_distutils_result"; then
if test $? -eq 0; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_WARN([cannot import Python module "distutils".
AC_MSG_ERROR([cannot import Python module "distutils".
Please check your Python installation. The error was:
$ac_distutils_result])
PYTHON_VERSION=""
no_python_devel=yes
fi
]) # AS_IF
AS_IF([test -z "$no_python_devel"], [
#
# Check for Python include path
#
@@ -183,7 +172,7 @@ AS_IF([test -z "$no_python_devel"], [
# Check for Python library path
#
AC_MSG_CHECKING([for Python library path])
if test -z "$PYTHON_LDFLAGS"; then
if test -z "$PYTHON_LIBS"; then
# (makes two attempts to ensure we've got a version number
# from the interpreter)
ac_python_version=`cat<<EOD | $PYTHON -
@@ -238,29 +227,26 @@ EOD`
then
# use the official shared library
ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
PYTHON_LDFLAGS="-L$ac_python_libdir -l$ac_python_library"
PYTHON_LIBS="-L$ac_python_libdir -l$ac_python_library"
else
# old way: use libpython from python_configdir
ac_python_libdir=`$PYTHON -c \
"from distutils.sysconfig import get_python_lib as f; \
import os; \
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
PYTHON_LDFLAGS="-L$ac_python_libdir -lpython$ac_python_version"
PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
fi
if test -z "PYTHON_LDFLAGS"; then
AC_MSG_WARN([
if test -z "PYTHON_LIBS"; then
AC_MSG_ERROR([
Cannot determine location of your Python DSO. Please check it was installed with
dynamic libraries enabled, or try setting PYTHON_LDFLAGS by hand.
dynamic libraries enabled, or try setting PYTHON_LIBS by hand.
])
no_python_devel=yes
fi
fi
AC_MSG_RESULT([$PYTHON_LDFLAGS])
AC_SUBST([PYTHON_LDFLAGS])
]) # AS_IF
AC_MSG_RESULT([$PYTHON_LIBS])
AC_SUBST([PYTHON_LIBS])
AS_IF([test -z "$no_python_devel"], [
#
# Check for site packages
#
@@ -279,7 +265,7 @@ AS_IF([test -z "$no_python_devel"], [
if test -z "$PYTHON_EXTRA_LIBS"; then
PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
print (conf('LIBS'))"`
print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
fi
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
AC_SUBST(PYTHON_EXTRA_LIBS)
@@ -302,8 +288,10 @@ AS_IF([test -z "$no_python_devel"], [
AC_MSG_CHECKING([consistency of all components of python development environment])
# save current global flags
ac_save_LIBS="$LIBS"
ac_save_LDFLAGS="$LDFLAGS"
ac_save_CPPFLAGS="$CPPFLAGS"
LIBS="$ac_save_LIBS $PYTHON_LDFLAGS $PYTHON_EXTRA_LDFLAGS $PYTHON_EXTRA_LIBS"
LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS $PYTHON_EXTRA_LIBS"
LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
AC_LANG_PUSH([C])
AC_LINK_IFELSE([
@@ -314,15 +302,16 @@ AS_IF([test -z "$no_python_devel"], [
# turn back to default flags
CPPFLAGS="$ac_save_CPPFLAGS"
LIBS="$ac_save_LIBS"
LDFLAGS="$ac_save_LDFLAGS"
AC_MSG_RESULT([$pythonexists])
if test ! "x$pythonexists" = "xyes"; then
AC_MSG_WARN([
AC_MSG_FAILURE([
Could not link test program to Python. Maybe the main Python library has been
installed in some non-standard library path. If so, pass it to configure,
via the LDFLAGS environment variable.
Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
via the LIBS environment variable.
Example: ./configure LIBS="-L/usr/non-standard-path/python/lib"
============================================================================
ERROR!
You probably have to install the development version of the Python package
@@ -330,15 +319,9 @@ AS_IF([test -z "$no_python_devel"], [
============================================================================
])
PYTHON_VERSION=""
no_python_devel=yes
fi
#
# all done!
#
]) # AS_IF
AS_IF([test -z "$no_python_devel"],
[have_python_dev=yes], [have_python_dev=no])
]) # AS_IF
])

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This script read cipher suite list csv file [1] and prints out id
@@ -8,7 +8,6 @@
# [1] http://www.iana.org/assignments/tls-parameters/tls-parameters-4.csv
# [2] http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
from __future__ import unicode_literals
import re
import sys
import csv
@@ -295,7 +294,7 @@ blacklist = [
ciphers = []
found = set()
for hl, name, _, _ in csv.reader(sys.stdin):
for hl, name, _, _, _ in csv.reader(sys.stdin):
if name not in blacklist:
continue
@@ -306,21 +305,21 @@ for hl, name, _, _ in csv.reader(sys.stdin):
id = high + low[2:] + 'u'
ciphers.append((id, name))
print '''\
enum {'''
print('''\
enum {''')
for id, name in ciphers:
print '{} = {},'.format(name, id)
print('{} = {},'.format(name, id))
print '''\
print('''\
};
'''
''')
for id, name in ciphers:
print '''\
case {}:'''.format(name)
print('''\
case {}:'''.format(name))
if len(found) != len(blacklist):
print '{} found out of {}; not all cipher was found: {}'.format(
print('{} found out of {}; not all cipher was found: {}'.format(
len(found), len(blacklist),
found.symmetric_difference(blacklist))
found.symmetric_difference(blacklist)))

View File

@@ -1,16 +1,15 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This script reads Huffman Code table [1] and generates symbol table
# and decoding tables in C language. The resulting code is used in
# lib/nghttp2_hd_huffman.h and lib/nghttp2_hd_huffman_data.c
#
# [1] http://http2.github.io/http2-spec/compression.html
# [1] https://httpwg.org/specs/rfc7541.html
from __future__ import unicode_literals
import re
import sys
import StringIO
from io import StringIO
# From [1]
HUFFMAN_CODE_TABLE = """\
@@ -363,8 +362,8 @@ NGHTTP2_HUFF_SYM = 1 << 15
def _print_transition_table(node):
if node.term is not None:
return
print '/* {} */'.format(node.id)
print '{'
print('/* {} */'.format(node.id))
print('{')
for nd, sym in node.trans:
flags = 0
if sym is None:
@@ -382,38 +381,38 @@ def _print_transition_table(node):
flags |= NGHTTP2_HUFF_ACCEPTED
elif nd.accept:
flags |= NGHTTP2_HUFF_ACCEPTED
print ' {{0x{:02x}, {}}},'.format(id | flags, out)
print '},'
print(' {{0x{:02x}, {}}},'.format(id | flags, out))
print('},')
_print_transition_table(node.left)
_print_transition_table(node.right)
def huffman_tree_print_transition_table(ctx):
_print_transition_table(ctx.root)
print '/* 256 */'
print '{'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print ' {0x100, 0},'
print '},'
print('/* 256 */')
print('{')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print(' {0x100, 0},')
print('},')
if __name__ == '__main__':
ctx = Context()
symbol_tbl = [(None, 0) for i in range(257)]
for line in StringIO.StringIO(HUFFMAN_CODE_TABLE):
for line in StringIO(HUFFMAN_CODE_TABLE):
m = re.match(
r'.*\(\s*(\d+)\)\s+([|01]+)\s+(\S+)\s+\[\s*(\d+)\].*', line)
if m:
@@ -430,40 +429,40 @@ if __name__ == '__main__':
huffman_tree_set_node_id(ctx)
huffman_tree_build_transition_table(ctx)
print '''\
print('''\
typedef struct {
uint32_t nbits;
uint32_t code;
} nghttp2_huff_sym;
'''
''')
print '''\
const nghttp2_huff_sym huff_sym_table[] = {'''
print('''\
const nghttp2_huff_sym huff_sym_table[] = {''')
for i in range(257):
nbits = symbol_tbl[i][0]
k = int(symbol_tbl[i][1], 16)
k = k << (32 - nbits)
print '''\
print('''\
{{ {}, 0x{}u }}{}\
'''.format(symbol_tbl[i][0], hex(k)[2:], ',' if i < 256 else '')
print '};'
print ''
'''.format(symbol_tbl[i][0], hex(k)[2:], ',' if i < 256 else ''))
print('};')
print()
print '''\
print('''\
enum {{
NGHTTP2_HUFF_ACCEPTED = {},
NGHTTP2_HUFF_SYM = {},
}} nghttp2_huff_decode_flag;
'''.format(NGHTTP2_HUFF_ACCEPTED, NGHTTP2_HUFF_SYM)
'''.format(NGHTTP2_HUFF_ACCEPTED, NGHTTP2_HUFF_SYM))
print '''\
print('''\
typedef struct {
uint16_t fstate;
uint8_t sym;
} nghttp2_huff_decode;
'''
''')
print '''\
const nghttp2_huff_decode huff_decode_table[][16] = {'''
print('''\
const nghttp2_huff_decode huff_decode_table[][16] = {''')
huffman_tree_print_transition_table(ctx)
print '};'
print('};')

View File

@@ -1,13 +1,12 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This scripts reads static table entries [1] and generates
# nghttp2_hd_static_entry table. This table is used in
# lib/nghttp2_hd.c.
#
# [1] http://http2.github.io/http2-spec/compression.html
# [1] https://httpwg.org/specs/rfc7541.html
from __future__ import unicode_literals
import re, sys
def hd_map_hash(name):
@@ -27,11 +26,11 @@ for line in sys.stdin:
val = m.group(3).strip() if m.group(3) else ''
entries.append((int(m.group(1)), m.group(2), val))
print 'static nghttp2_hd_entry static_table[] = {'
print('static nghttp2_hd_entry static_table[] = {')
idx = 0
for i, ent in enumerate(entries):
if entries[idx][1] != ent[1]:
idx = i
print 'MAKE_STATIC_ENT("{}", "{}", {}, {}u),'\
.format(ent[1], ent[2], entries[idx][0] - 1, hd_map_hash(ent[1]))
print '};'
print('MAKE_STATIC_ENT("{}", "{}", {}, {}u),'\
.format(ent[1], ent[2], entries[idx][0] - 1, hd_map_hash(ent[1])))
print('};')

View File

@@ -44,6 +44,6 @@ clean-local:
-rm -f $(builddir)/nghttp2.c
.pyx.c:
$(CYTHON) -o $@ $<
$(CYTHON) -3 -o $@ $<
endif # ENABLE_PYTHON_BINDINGS

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# This script reads json files given in the command-line (each file
# must be written in the format described in

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# This script reads input headers from json file given in the
# command-line (each file must be written in the format described in

View File

@@ -857,7 +857,7 @@ cdef class _HTTP2SessionCore(_HTTP2SessionCoreBase):
rv = cnghttp2.nghttp2_submit_settings(self.session,
cnghttp2.NGHTTP2_FLAG_NONE,
iv, sizeof(iv) / sizeof(iv[0]))
iv, sizeof(iv) // sizeof(iv[0]))
if rv != 0:
raise Exception('nghttp2_submit_settings failed: {}'.format\
@@ -971,7 +971,7 @@ cdef class _HTTP2ClientSessionCore(_HTTP2SessionCoreBase):
rv = cnghttp2.nghttp2_submit_settings(self.session,
cnghttp2.NGHTTP2_FLAG_NONE,
iv, sizeof(iv) / sizeof(iv[0]))
iv, sizeof(iv) // sizeof(iv[0]))
if rv != 0:
raise Exception('nghttp2_submit_settings failed: {}'.format\

View File

@@ -15,10 +15,14 @@ include_directories(
${JEMALLOC_INCLUDE_DIRS}
${LIBXML2_INCLUDE_DIRS}
${LIBEV_INCLUDE_DIRS}
${LIBNGHTTP3_INCLUDE_DIRS}
${LIBNGTCP2_INCLUDE_DIRS}
${LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIRS}
${LIBCARES_INCLUDE_DIRS}
${JANSSON_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
${LIBBPF_INCLUDE_DIRS}
)
# XXX per-target?
@@ -27,11 +31,15 @@ link_libraries(
${JEMALLOC_LIBRARIES}
${LIBXML2_LIBRARIES}
${LIBEV_LIBRARIES}
${LIBNGHTTP3_LIBRARIES}
${LIBNGTCP2_LIBRARIES}
${LIBNGTCP2_CRYPTO_OPENSSL_LIBRARIES}
${OPENSSL_LIBRARIES}
${LIBCARES_LIBRARIES}
${JANSSON_LIBRARIES}
${ZLIB_LIBRARIES}
${APP_LIBRARIES}
${LIBBPF_LIBRARIES}
)
if(ENABLE_APP)
@@ -67,7 +75,13 @@ if(ENABLE_APP)
h2load_http2_session.cc
h2load_http1_session.cc
)
if(ENABLE_HTTP3)
list(APPEND H2LOAD_SOURCES
h2load_http3_session.cc
h2load_quic.cc
quic.cc
)
endif()
# Common libnhttpx sources (used for nghttpx and unit tests)
set(NGHTTPX_SRCS
@@ -104,6 +118,7 @@ if(ENABLE_APP)
shrpx_router.cc
shrpx_api_downstream_connection.cc
shrpx_health_monitor_downstream_connection.cc
shrpx_null_downstream_connection.cc
shrpx_exec.cc
shrpx_dns_resolver.cc
shrpx_dual_dns_resolver.cc
@@ -119,6 +134,16 @@ if(ENABLE_APP)
shrpx_mruby_module_response.cc
)
endif()
if(ENABLE_HTTP3)
list(APPEND NGHTTPX_SRCS
shrpx_quic.cc
shrpx_quic_listener.cc
shrpx_quic_connection_handler.cc
shrpx_http3_upstream.cc
http3.cc
quic.cc
)
endif()
add_library(nghttpx_static STATIC ${NGHTTPX_SRCS})
set_target_properties(nghttpx_static PROPERTIES ARCHIVE_OUTPUT_NAME nghttpx)
@@ -189,7 +214,10 @@ if(ENABLE_APP)
add_executable(nghttpx ${NGHTTPX-bin_SOURCES} $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:url-parser>
)
target_compile_definitions(nghttpx PRIVATE "-DPKGDATADIR=\"${PKGDATADIR}\"")
target_compile_definitions(nghttpx PRIVATE
"-DPKGDATADIR=\"${PKGDATADIR}\""
"-DPKGLIBDIR=\"${PKGLIBDIR}\""
)
target_link_libraries(nghttpx nghttpx_static)
add_executable(h2load ${H2LOAD_SOURCES} $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:url-parser>

View File

@@ -52,8 +52,13 @@
#include <mutex>
#include <deque>
#include "ssl_compat.h"
#include <openssl/err.h>
#include <openssl/dh.h>
#if OPENSSL_3_0_0_API
# include <openssl/decoder.h>
#endif // OPENSSL_3_0_0_API
#include <zlib.h>
@@ -2138,15 +2143,22 @@ int HttpServer::run() {
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER);
#ifndef OPENSSL_NO_EC
// Disabled SSL_CTX_set_ecdh_auto, because computational cost of
// chosen curve is much higher than P-256.
// #if OPENSSL_VERSION_NUMBER >= 0x10002000L
// SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
// #else // OPENSSL_VERSION_NUBMER < 0x10002000L
// Use P-256, which is sufficiently secure at the time of this
// writing.
# if OPENSSL_3_0_0_API
auto ecdh = EVP_EC_gen("P-256");
if (ecdh == nullptr) {
std::cerr << "EC_KEY_new_by_curv_name failed: "
<< ERR_error_string(ERR_get_error(), nullptr);
return -1;
}
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
EVP_PKEY_free(ecdh);
# else // !OPENSSL_3_0_0_API
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (ecdh == nullptr) {
std::cerr << "EC_KEY_new_by_curv_name failed: "
@@ -2155,19 +2167,33 @@ int HttpServer::run() {
}
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
EC_KEY_free(ecdh);
// #endif // OPENSSL_VERSION_NUBMER < 0x10002000L
#endif // OPENSSL_NO_EC
# endif // !OPENSSL_3_0_0_API
#endif // OPENSSL_NO_EC
if (!config_->dh_param_file.empty()) {
// Read DH parameters from file
auto bio = BIO_new_file(config_->dh_param_file.c_str(), "r");
auto bio = BIO_new_file(config_->dh_param_file.c_str(), "rb");
if (bio == nullptr) {
std::cerr << "BIO_new_file() failed: "
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
return -1;
}
#if OPENSSL_3_0_0_API
EVP_PKEY *dh = nullptr;
auto dctx = OSSL_DECODER_CTX_new_for_pkey(
&dh, "PEM", nullptr, "DH", OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS,
nullptr, nullptr);
if (!OSSL_DECODER_from_bio(dctx, bio)) {
std::cerr << "OSSL_DECODER_from_bio() failed: "
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
return -1;
}
SSL_CTX_set_tmp_dh(ssl_ctx, dh);
EVP_PKEY_free(dh);
#else // !OPENSSL_3_0_0_API
auto dh = PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr);
if (dh == nullptr) {
@@ -2178,6 +2204,7 @@ int HttpServer::run() {
SSL_CTX_set_tmp_dh(ssl_ctx, dh);
DH_free(dh);
#endif // !OPENSSL_3_0_0_API
BIO_free(bio);
}

View File

@@ -242,7 +242,7 @@ private:
};
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length, int *eof,
uint8_t *buf, size_t length, uint32_t *data_flags,
nghttp2_data_source *source, void *user_data);
} // namespace nghttp2

View File

@@ -35,19 +35,27 @@ AM_CFLAGS = $(WARNCFLAGS)
AM_CXXFLAGS = $(WARNCXXFLAGS) $(CXX1XCXXFLAGS)
AM_CPPFLAGS = \
-DPKGDATADIR='"$(pkgdatadir)"' \
-DPKGLIBDIR='"$(pkglibdir)"' \
-I$(top_srcdir)/lib/includes \
-I$(top_builddir)/lib/includes \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/src/includes \
-I$(top_srcdir)/third-party \
-I$(top_srcdir)/third-party/llhttp/include \
@JEMALLOC_CFLAGS@ \
@LIBXML2_CFLAGS@ \
@LIBEV_CFLAGS@ \
@LIBNGHTTP3_CFLAGS@ \
@LIBNGTCP2_CRYPTO_OPENSSL_CFLAGS@ \
@LIBNGTCP2_CFLAGS@ \
@OPENSSL_CFLAGS@ \
@LIBCARES_CFLAGS@ \
@JANSSON_CFLAGS@ \
@LIBBPF_CFLAGS@ \
@ZLIB_CFLAGS@ \
@EXTRA_DEFS@ \
@DEFS@
AM_LDFLAGS = @LIBTOOL_LDFLAGS@
LDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/liburl-parser.la \
@@ -55,10 +63,14 @@ LDADD = $(top_builddir)/lib/libnghttp2.la \
@JEMALLOC_LIBS@ \
@LIBXML2_LIBS@ \
@LIBEV_LIBS@ \
@LIBNGHTTP3_LIBS@ \
@LIBNGTCP2_CRYPTO_OPENSSL_LIBS@ \
@LIBNGTCP2_LIBS@ \
@OPENSSL_LIBS@ \
@LIBCARES_LIBS@ \
@SYSTEMD_LIBS@ \
@JANSSON_LIBS@ \
@LIBBPF_LIBS@ \
@ZLIB_LIBS@ \
@APPLDFLAGS@
@@ -97,6 +109,13 @@ h2load_SOURCES = util.cc util.h \
h2load_http2_session.cc h2load_http2_session.h \
h2load_http1_session.cc h2load_http1_session.h
if ENABLE_HTTP3
h2load_SOURCES += \
h2load_http3_session.cc h2load_http3_session.h \
h2load_quic.cc h2load_quic.h \
quic.cc quic.h
endif # ENABLE_HTTP3
NGHTTPX_SRCS = \
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \
app_helper.cc app_helper.h \
@@ -137,6 +156,7 @@ NGHTTPX_SRCS = \
shrpx_api_downstream_connection.cc shrpx_api_downstream_connection.h \
shrpx_health_monitor_downstream_connection.cc \
shrpx_health_monitor_downstream_connection.h \
shrpx_null_downstream_connection.cc shrpx_null_downstream_connection.h \
shrpx_exec.cc shrpx_exec.h \
shrpx_dns_resolver.cc shrpx_dns_resolver.h \
shrpx_dual_dns_resolver.cc shrpx_dual_dns_resolver.h \
@@ -153,6 +173,16 @@ NGHTTPX_SRCS += \
shrpx_mruby_module_response.cc shrpx_mruby_module_response.h
endif # HAVE_MRUBY
if ENABLE_HTTP3
NGHTTPX_SRCS += \
shrpx_quic.cc shrpx_quic.h \
shrpx_quic_listener.cc shrpx_quic_listener.h \
shrpx_quic_connection_handler.cc shrpx_quic_connection_handler.h \
shrpx_http3_upstream.cc shrpx_http3_upstream.h \
http3.cc http3.h \
quic.cc quic.h
endif # ENABLE_HTTP3
noinst_LIBRARIES = libnghttpx.a
libnghttpx_a_SOURCES = ${NGHTTPX_SRCS}
libnghttpx_a_CPPFLAGS = ${AM_CPPFLAGS}
@@ -262,7 +292,7 @@ libnghttp2_asio_la_SOURCES = \
asio_client_tls_context.cc asio_client_tls_context.h
libnghttp2_asio_la_CPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
libnghttp2_asio_la_LDFLAGS = -no-undefined -version-info 1:0:0
libnghttp2_asio_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0
libnghttp2_asio_la_LIBADD = \
$(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/liburl-parser.la \

View File

@@ -197,7 +197,7 @@ inline size_t concat_string_ref_count(size_t acc) { return acc; }
// accumulated, and passed to the next function.
template <typename... Args>
size_t concat_string_ref_count(size_t acc, const StringRef &value,
Args &&... args) {
Args &&...args) {
return concat_string_ref_count(acc + value.size(),
std::forward<Args>(args)...);
}
@@ -212,7 +212,7 @@ inline uint8_t *concat_string_ref_copy(uint8_t *p) { return p; }
// beyond the last byte written.
template <typename... Args>
uint8_t *concat_string_ref_copy(uint8_t *p, const StringRef &value,
Args &&... args) {
Args &&...args) {
p = std::copy(std::begin(value), std::end(value), p);
return concat_string_ref_copy(p, std::forward<Args>(args)...);
}
@@ -220,7 +220,7 @@ uint8_t *concat_string_ref_copy(uint8_t *p, const StringRef &value,
// Returns the string which is the concatenation of |args| in the
// given order. The resulting string will be NULL-terminated.
template <typename BlockAllocator, typename... Args>
StringRef concat_string_ref(BlockAllocator &alloc, Args &&... args) {
StringRef concat_string_ref(BlockAllocator &alloc, Args &&...args) {
size_t len = concat_string_ref_count(0, std::forward<Args>(args)...);
auto dst = static_cast<uint8_t *>(alloc.alloc(len + 1));
auto p = dst;
@@ -237,7 +237,7 @@ StringRef concat_string_ref(BlockAllocator &alloc, Args &&... args) {
// then just call concat_string_ref().
template <typename BlockAllocator, typename... Args>
StringRef realloc_concat_string_ref(BlockAllocator &alloc,
const StringRef &value, Args &&... args) {
const StringRef &value, Args &&...args) {
if (value.empty()) {
return concat_string_ref(alloc, std::forward<Args>(args)...);
}

View File

@@ -97,7 +97,7 @@ generator_cb deferred_generator() {
}
template <typename F, typename... T>
std::shared_ptr<Defer<F, T...>> defer_shared(F &&f, T &&... t) {
std::shared_ptr<Defer<F, T...>> defer_shared(F &&f, T &&...t) {
return std::make_shared<Defer<F, T...>>(std::forward<F>(f),
std::forward<T>(t)...);
}

View File

@@ -75,7 +75,7 @@ public:
serve_mux &mux,
const boost::posix_time::time_duration &tls_handshake_timeout,
const boost::posix_time::time_duration &read_timeout,
SocketArgs &&... args)
SocketArgs &&...args)
: socket_(std::forward<SocketArgs>(args)...),
mux_(mux),
deadline_(GET_IO_SERVICE(socket_)),

View File

@@ -34,6 +34,8 @@
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif // HAVE_FCNTL_H
#include <sys/mman.h>
#include <netinet/udp.h>
#include <cstdio>
#include <cassert>
@@ -48,10 +50,18 @@
#include <openssl/err.h>
#ifdef ENABLE_HTTP3
# include <ngtcp2/ngtcp2.h>
#endif // ENABLE_HTTP3
#include "url-parser/url_parser.h"
#include "h2load_http1_session.h"
#include "h2load_http2_session.h"
#ifdef ENABLE_HTTP3
# include "h2load_http3_session.h"
# include "h2load_quic.h"
#endif // ENABLE_HTTP3
#include "tls.h"
#include "http2.h"
#include "util.h"
@@ -71,9 +81,24 @@ bool recorded(const std::chrono::steady_clock::time_point &t) {
}
} // namespace
#if OPENSSL_1_1_1_API
namespace {
std::ofstream keylog_file;
void keylog_callback(const SSL *ssl, const char *line) {
keylog_file.write(line, strlen(line));
keylog_file.put('\n');
keylog_file.flush();
}
} // namespace
#endif // OPENSSL_1_1_1_API
Config::Config()
: ciphers(tls::DEFAULT_CIPHER_LIST),
tls13_ciphers("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_"
"CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256"),
groups("X25519:P-256:P-384:P-521"),
data_length(-1),
data(nullptr),
addrs(nullptr),
nreqs(1),
nclients(1),
@@ -92,13 +117,17 @@ Config::Config()
encoder_header_table_size(4_k),
data_fd(-1),
log_fd(-1),
qlog_file_base(),
port(0),
default_port(0),
connect_to_port(0),
verbose(false),
timing_script(false),
base_uri_unix(false),
unix_addr{} {}
unix_addr{},
rps(0.),
no_udp_gso(false),
max_udp_payload_size(0) {}
Config::~Config() {
if (addrs) {
@@ -117,6 +146,15 @@ Config::~Config() {
bool Config::is_rate_mode() const { return (this->rate != 0); }
bool Config::is_timing_based_mode() const { return (this->duration > 0); }
bool Config::has_base_uri() const { return (!this->base_uri.empty()); }
bool Config::rps_enabled() const { return this->rps > 0.0; }
bool Config::is_quic() const {
#ifdef ENABLE_HTTP3
return !npn_list.empty() &&
(npn_list[0] == NGHTTP3_ALPN_H3 || npn_list[0] == "\x5h3-29");
#else // !ENABLE_HTTP3
return false;
#endif // !ENABLE_HTTP3
}
Config config;
namespace {
@@ -136,7 +174,9 @@ Stats::Stats(size_t req_todo, size_t nclients)
bytes_head(0),
bytes_head_decomp(0),
bytes_body(0),
status() {}
status(),
udp_dgram_recv(0),
udp_dgram_sent(0) {}
Stream::Stream() : req_stat{}, status_success(-1) {}
@@ -193,8 +233,7 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) {
delete client;
return;
}
writecb(loop, &client->wev, revents);
// client->disconnect() and client->fail() may be called
client->signal_write();
}
} // namespace
@@ -286,6 +325,51 @@ void warmup_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
}
} // namespace
namespace {
void rps_cb(struct ev_loop *loop, ev_timer *w, int revents) {
auto client = static_cast<Client *>(w->data);
auto &session = client->session;
assert(!config.timing_script);
if (client->req_left == 0) {
ev_timer_stop(loop, w);
return;
}
auto now = ev_now(loop);
auto d = now - client->rps_duration_started;
auto n = static_cast<size_t>(round(d * config.rps));
client->rps_req_pending += n;
client->rps_duration_started = now - d + static_cast<double>(n) / config.rps;
if (client->rps_req_pending == 0) {
return;
}
auto nreq = session->max_concurrent_streams() - client->rps_req_inflight;
if (nreq == 0) {
return;
}
nreq = config.is_timing_based_mode() ? std::max(nreq, client->req_left)
: std::min(nreq, client->req_left);
nreq = std::min(nreq, client->rps_req_pending);
client->rps_req_inflight += nreq;
client->rps_req_pending -= nreq;
for (; nreq > 0; --nreq) {
if (client->submit_request() != 0) {
client->process_request_failure();
break;
}
}
client->signal_write();
}
} // namespace
namespace {
// Called when an a connection has been inactive for a set period of time
// or a fixed amount of time after all requests have been made on a
@@ -362,6 +446,9 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo)
cstat{},
worker(worker),
ssl(nullptr),
#ifdef ENABLE_HTTP3
quic{},
#endif // ENABLE_HTTP3
next_addr(config.addrs),
current_addr(nullptr),
reqidx(0),
@@ -373,8 +460,12 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo)
req_done(0),
id(id),
fd(-1),
local_addr{},
new_connection_requested(false),
final(false) {
final(false),
rps_duration_started(0),
rps_req_pending(0),
rps_req_inflight(0) {
if (req_todo == 0) { // this means infinite number of requests are to be made
// This ensures that number of requests are unbounded
// Just a positive number is fine, we chose the first positive number
@@ -396,11 +487,25 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo)
ev_timer_init(&request_timeout_watcher, client_request_timeout_cb, 0., 0.);
request_timeout_watcher.data = this;
ev_timer_init(&rps_watcher, rps_cb, 0., 0.);
rps_watcher.data = this;
#ifdef ENABLE_HTTP3
ev_timer_init(&quic.pkt_timer, quic_pkt_timeout_cb, 0., 0.);
quic.pkt_timer.data = this;
#endif // ENABLE_HTTP3
}
Client::~Client() {
disconnect();
#ifdef ENABLE_HTTP3
if (config.is_quic()) {
quic_free();
}
#endif // ENABLE_HTTP3
if (ssl) {
SSL_free(ssl);
}
@@ -413,26 +518,59 @@ int Client::do_read() { return readfn(*this); }
int Client::do_write() { return writefn(*this); }
int Client::make_socket(addrinfo *addr) {
fd = util::create_nonblock_socket(addr->ai_family);
if (fd == -1) {
return -1;
}
if (config.scheme == "https") {
if (!ssl) {
ssl = SSL_new(worker->ssl_ctx);
int rv;
if (config.is_quic()) {
#ifdef ENABLE_HTTP3
fd = util::create_nonblock_udp_socket(addr->ai_family);
if (fd == -1) {
return -1;
}
auto config = worker->config;
if (!util::numeric_host(config->host.c_str())) {
SSL_set_tlsext_host_name(ssl, config->host.c_str());
rv = util::bind_any_addr_udp(fd, addr->ai_family);
if (rv != 0) {
close(fd);
fd = -1;
return -1;
}
SSL_set_fd(ssl, fd);
SSL_set_connect_state(ssl);
socklen_t addrlen = sizeof(local_addr.su.storage);
rv = getsockname(fd, &local_addr.su.sa, &addrlen);
if (rv == -1) {
return -1;
}
local_addr.len = addrlen;
if (quic_init(&local_addr.su.sa, local_addr.len, addr->ai_addr,
addr->ai_addrlen) != 0) {
std::cerr << "quic_init failed" << std::endl;
return -1;
}
#endif // ENABLE_HTTP3
} else {
fd = util::create_nonblock_socket(addr->ai_family);
if (fd == -1) {
return -1;
}
if (config.scheme == "https") {
if (!ssl) {
ssl = SSL_new(worker->ssl_ctx);
}
SSL_set_fd(ssl, fd);
SSL_set_connect_state(ssl);
}
}
auto rv = ::connect(fd, addr->ai_addr, addr->ai_addrlen);
if (ssl && !util::numeric_host(config.host.c_str())) {
SSL_set_tlsext_host_name(ssl, config.host.c_str());
}
if (config.is_quic()) {
return 0;
}
rv = ::connect(fd, addr->ai_addr, addr->ai_addrlen);
if (rv != 0 && errno != EINPROGRESS) {
if (ssl) {
SSL_free(ssl);
@@ -489,13 +627,22 @@ int Client::connect() {
current_addr = addr;
}
writefn = &Client::connected;
ev_io_set(&rev, fd, EV_READ);
ev_io_set(&wev, fd, EV_WRITE);
ev_io_start(worker->loop, &wev);
if (config.is_quic()) {
#ifdef ENABLE_HTTP3
ev_io_start(worker->loop, &rev);
readfn = &Client::read_quic;
writefn = &Client::write_quic;
#endif // ENABLE_HTTP3
} else {
writefn = &Client::connected;
}
return 0;
}
@@ -550,8 +697,18 @@ void Client::fail() {
void Client::disconnect() {
record_client_end_time();
#ifdef ENABLE_HTTP3
if (config.is_quic()) {
quic_close_connection();
}
#endif // ENABLE_HTTP3
#ifdef ENABLE_HTTP3
ev_timer_stop(worker->loop, &quic.pkt_timer);
#endif // ENABLE_HTTP3
ev_timer_stop(worker->loop, &conn_inactivity_watcher);
ev_timer_stop(worker->loop, &conn_active_watcher);
ev_timer_stop(worker->loop, &rps_watcher);
ev_timer_stop(worker->loop, &request_timeout_watcher);
streams.clear();
session.reset();
@@ -672,6 +829,16 @@ void print_server_tmp_key(SSL *ssl) {
std::cout << "DH " << EVP_PKEY_bits(key) << " bits" << std::endl;
break;
case EVP_PKEY_EC: {
# if OPENSSL_3_0_0_API
std::array<char, 64> curve_name;
const char *cname;
if (!EVP_PKEY_get_utf8_string_param(key, "group", curve_name.data(),
curve_name.size(), nullptr)) {
cname = "<unknown>";
} else {
cname = curve_name.data();
}
# else // !OPENSSL_3_0_0_API
auto ec = EVP_PKEY_get1_EC_KEY(key);
auto ec_del = defer(EC_KEY_free, ec);
auto nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
@@ -679,6 +846,7 @@ void print_server_tmp_key(SSL *ssl) {
if (!cname) {
cname = OBJ_nid2sn(nid);
}
# endif // !OPENSSL_3_0_0_API
std::cout << "ECDH " << cname << " " << EVP_PKEY_bits(key) << " bits"
<< std::endl;
@@ -711,7 +879,14 @@ void Client::report_app_info() {
}
void Client::terminate_session() {
session->terminate();
#ifdef ENABLE_HTTP3
if (config.is_quic()) {
quic.close_requested = true;
}
#endif // ENABLE_HTTP3
if (session) {
session->terminate();
}
// http1 session needs writecb to tear down session.
signal_write();
}
@@ -866,8 +1041,18 @@ void Client::on_stream_close(int32_t stream_id, bool success, bool final) {
if (!ev_is_active(&request_timeout_watcher)) {
ev_feed_event(worker->loop, &request_timeout_watcher, EV_TIMER);
}
} else if (submit_request() != 0) {
process_request_failure();
} else if (!config.rps_enabled()) {
if (submit_request() != 0) {
process_request_failure();
}
} else if (rps_req_pending) {
--rps_req_pending;
if (submit_request() != 0) {
process_request_failure();
}
} else {
assert(rps_req_inflight);
--rps_req_inflight;
}
}
}
@@ -899,7 +1084,15 @@ int Client::connection_made() {
if (next_proto) {
auto proto = StringRef{next_proto, next_proto_len};
if (util::check_h2_is_selected(proto)) {
if (config.is_quic()) {
#ifdef ENABLE_HTTP3
assert(session);
if (!util::streq(StringRef{&NGHTTP3_ALPN_H3[1]}, proto) &&
!util::streq_l("h3-29", proto)) {
return -1;
}
#endif // ENABLE_HTTP3
} else if (util::check_h2_is_selected(proto)) {
session = std::make_unique<Http2Session>(this);
} else if (util::streq(NGHTTP2_H1_1, proto)) {
session = std::make_unique<Http1Session>(this);
@@ -908,6 +1101,9 @@ int Client::connection_made() {
// Just assign next_proto to selected_proto anyway to show the
// negotiation result.
selected_proto = proto.str();
} else if (config.is_quic()) {
std::cerr << "QUIC requires ALPN negotiation" << std::endl;
return -1;
} else {
std::cout << "No protocol negotiated. Fallback behaviour may be activated"
<< std::endl;
@@ -962,10 +1158,25 @@ int Client::connection_made() {
record_connect_time();
if (!config.timing_script) {
if (config.rps_enabled()) {
rps_watcher.repeat = std::max(0.01, 1. / config.rps);
ev_timer_again(worker->loop, &rps_watcher);
rps_duration_started = ev_now(worker->loop);
}
if (config.rps_enabled()) {
assert(req_left);
++rps_req_inflight;
if (submit_request() != 0) {
process_request_failure();
}
} else if (!config.timing_script) {
auto nreq = config.is_timing_based_mode()
? std::max(req_left, session->max_concurrent_streams())
: std::min(req_left, session->max_concurrent_streams());
for (; nreq > 0; --nreq) {
if (submit_request() != 0) {
process_request_failure();
@@ -1206,6 +1417,46 @@ int Client::write_tls() {
return 0;
}
#ifdef ENABLE_HTTP3
int Client::write_udp(const sockaddr *addr, socklen_t addrlen,
const uint8_t *data, size_t datalen, size_t gso_size) {
iovec msg_iov;
msg_iov.iov_base = const_cast<uint8_t *>(data);
msg_iov.iov_len = datalen;
msghdr msg{};
msg.msg_name = const_cast<sockaddr *>(addr);
msg.msg_namelen = addrlen;
msg.msg_iov = &msg_iov;
msg.msg_iovlen = 1;
# ifdef UDP_SEGMENT
std::array<uint8_t, CMSG_SPACE(sizeof(uint16_t))> msg_ctrl{};
if (gso_size && datalen > gso_size) {
msg.msg_control = msg_ctrl.data();
msg.msg_controllen = msg_ctrl.size();
auto cm = CMSG_FIRSTHDR(&msg);
cm->cmsg_level = SOL_UDP;
cm->cmsg_type = UDP_SEGMENT;
cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
*(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size;
}
# endif // UDP_SEGMENT
auto nwrite = sendmsg(fd, &msg, 0);
if (nwrite < 0) {
std::cerr << "sendto: errno=" << errno << std::endl;
} else {
++worker->stats.udp_dgram_sent;
}
ev_io_stop(worker->loop, &wev);
return 0;
}
#endif // ENABLE_HTTP3
void Client::record_request_time(RequestStat *req_stat) {
req_stat->request_time = std::chrono::steady_clock::now();
req_stat->request_wall_time = std::chrono::system_clock::now();
@@ -1324,7 +1575,7 @@ Worker::~Worker() {
void Worker::stop_all_clients() {
for (auto client : clients) {
if (client && client->session) {
if (client) {
client->terminate_session();
}
}
@@ -1859,6 +2110,7 @@ Options:
Default: 1
-w, --window-bits=<N>
Sets the stream level initial window size to (2**<N>)-1.
For QUIC, <N> is capped to 26 (roughly 64MiB).
Default: )"
<< config.window_bits << R"(
-W, --connection-window-bits=<N>
@@ -1869,10 +2121,15 @@ Options:
-H, --header=<HEADER>
Add/Override a header to the requests.
--ciphers=<SUITE>
Set allowed cipher list. The format of the string is
described in OpenSSL ciphers(1).
Set allowed cipher list for TLSv1.2 or ealier. The
format of the string is described in OpenSSL ciphers(1).
Default: )"
<< config.ciphers << R"(
--tls13-ciphers=<SUITE>
Set allowed cipher list for TLSv1.3. The format of the
string is described in OpenSSL ciphers(1).
Default: )"
<< config.tls13_ciphers << R"(
-p, --no-tls-proto=<PROTOID>
Specify ALPN identifier of the protocol to be used when
accessing http URI without SSL/TLS.
@@ -1903,7 +2160,7 @@ Options:
length of the period in time. This option is ignored if
the rate option is not used. The default value for this
option is 1s.
-D, --duration=<N>
-D, --duration=<DURATION>
Specifies the main duration for the measurements in case
of timing-based benchmarking. -D and -r are mutually
exclusive.
@@ -1943,7 +2200,8 @@ Options:
port defined in the first URI are used solely. Values
contained in other URIs, if present, are ignored.
Definition of a base URI overrides all scheme, host or
port values.
port values. --timing-script-file and --rps are
mutually exclusive.
-B, --base-uri=(<URI>|unix:<PATH>)
Specify URI from which the scheme, host and port will be
used for all requests. The base URI overrides all
@@ -1985,9 +2243,26 @@ Options:
response time when using one worker thread, but may
appear slightly out of order with multiple threads due
to buffering. Status code is -1 for failed streams.
--qlog-file-base=<PATH>
Enable qlog output and specify base file name for qlogs.
Qlog is emitted for each connection.
For a given base name "base", each output file name
becomes "base.M.N.qlog" where M is worker ID and N is
client ID (e.g. "base.0.3.qlog").
Only effective in QUIC runs.
--connect-to=<HOST>[:<PORT>]
Host and port to connect instead of using the authority
in <URI>.
--rps=<N> Specify request per second for each client. --rps and
--timing-script-file are mutually exclusive.
--groups=<GROUPS>
Specify the supported groups.
Default: )"
<< config.groups << R"(
--no-udp-gso
Disable UDP GSO.
--max-udp-payload-size=<SIZE>
Specify the maximum outgoing UDP datagram payload size.
-v, --verbose
Output debug information.
--version Display version information and exit.
@@ -2015,6 +2290,7 @@ int main(int argc, char **argv) {
std::string datafile;
std::string logfile;
std::string qlog_base;
bool nreqs_set_manually = false;
while (1) {
static int flag = 0;
@@ -2047,6 +2323,12 @@ int main(int argc, char **argv) {
{"warm-up-time", required_argument, &flag, 9},
{"log-file", required_argument, &flag, 10},
{"connect-to", required_argument, &flag, 11},
{"rps", required_argument, &flag, 12},
{"groups", required_argument, &flag, 13},
{"tls13-ciphers", required_argument, &flag, 14},
{"no-udp-gso", no_argument, &flag, 15},
{"qlog-file-base", required_argument, &flag, 16},
{"max-udp-payload-size", required_argument, &flag, 17},
{nullptr, 0, nullptr, 0}};
int option_index = 0;
auto c = getopt_long(argc, argv,
@@ -2199,10 +2481,9 @@ int main(int argc, char **argv) {
break;
}
case 'D':
config.duration = strtoul(optarg, nullptr, 10);
if (config.duration == 0) {
std::cerr << "-D: the main duration for timing-based benchmarking "
<< "must be positive." << std::endl;
config.duration = util::parse_duration_with_unit(optarg);
if (!std::isfinite(config.duration)) {
std::cerr << "-D: value error " << optarg << std::endl;
exit(EXIT_FAILURE);
}
break;
@@ -2287,6 +2568,49 @@ int main(int argc, char **argv) {
config.connect_to_port = port;
break;
}
case 12: {
char *end;
auto v = std::strtod(optarg, &end);
if (end == optarg || *end != '\0' || !std::isfinite(v) ||
1. / v < 1e-6) {
std::cerr << "--rps: Invalid value " << optarg << std::endl;
exit(EXIT_FAILURE);
}
config.rps = v;
break;
}
case 13:
// --groups
config.groups = optarg;
break;
case 14:
// --tls13-ciphers
config.tls13_ciphers = optarg;
break;
case 15:
// --no-udp-gso
config.no_udp_gso = true;
break;
case 16:
// --qlog-file-base
qlog_base = optarg;
break;
case 17: {
// --max-udp-payload-size
auto n = util::parse_uint_with_unit(optarg);
if (n == -1) {
std::cerr << "--max-udp-payload-size: bad option value: " << optarg
<< std::endl;
exit(EXIT_FAILURE);
}
if (static_cast<uint64_t>(n) > 64_k) {
std::cerr << "--max-udp-payload-size: must not exceed 65536"
<< std::endl;
exit(EXIT_FAILURE);
}
config.max_udp_payload_size = n;
break;
}
}
break;
default:
@@ -2377,6 +2701,12 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
if (config.timing_script && config.rps_enabled()) {
std::cerr << "--timing-script-file, --rps: they are mutually exclusive."
<< std::endl;
exit(EXIT_FAILURE);
}
if (config.nreqs == 0 && !config.is_timing_based_mode()) {
std::cerr << "-n: the number of requests must be strictly greater than 0 "
"if timing-based test is not being run."
@@ -2447,6 +2777,13 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
config.data_length = data_stat.st_size;
auto addr = mmap(nullptr, config.data_length, PROT_READ, MAP_SHARED,
config.data_fd, 0);
if (addr == MAP_FAILED) {
std::cerr << "-d: Could not mmap file " << datafile << std::endl;
exit(EXIT_FAILURE);
}
config.data = static_cast<uint8_t *>(addr);
}
if (!logfile.empty()) {
@@ -2458,6 +2795,18 @@ int main(int argc, char **argv) {
}
}
if (!qlog_base.empty()) {
if (!config.is_quic()) {
std::cerr
<< "Warning: --qlog-file-base: only effective in quic, ignoring."
<< std::endl;
} else {
#ifdef ENABLE_HTTP3
config.qlog_file_base = qlog_base;
#endif // ENABLE_HTTP3
}
}
struct sigaction act {};
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, nullptr);
@@ -2477,9 +2826,14 @@ int main(int argc, char **argv) {
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
if (nghttp2::tls::ssl_ctx_set_proto_versions(
ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
if (config.is_quic()) {
#ifdef ENABLE_HTTP3
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
#endif // ENABLE_HTTP3
} else if (nghttp2::tls::ssl_ctx_set_proto_versions(
ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
std::cerr << "Could not set TLS versions" << std::endl;
exit(EXIT_FAILURE);
}
@@ -2491,6 +2845,20 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
#if OPENSSL_1_1_1_API
if (SSL_CTX_set_ciphersuites(ssl_ctx, config.tls13_ciphers.c_str()) == 0) {
std::cerr << "SSL_CTX_set_ciphersuites with " << config.tls13_ciphers
<< " failed: " << ERR_error_string(ERR_get_error(), nullptr)
<< std::endl;
exit(EXIT_FAILURE);
}
#endif // OPENSSL_1_1_1_API
if (SSL_CTX_set1_groups_list(ssl_ctx, config.groups.c_str()) != 1) {
std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl;
exit(EXIT_FAILURE);
}
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
nullptr);
@@ -2505,6 +2873,16 @@ int main(int argc, char **argv) {
SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#if OPENSSL_1_1_1_API
auto keylog_filename = getenv("SSLKEYLOGFILE");
if (keylog_filename) {
keylog_file.open(keylog_filename, std::ios_base::app);
if (keylog_file) {
SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
}
}
#endif // OPENSSL_1_1_1_API
std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION;
Headers shared_nva;
shared_nva.emplace_back(":scheme", config.scheme);
@@ -2723,6 +3101,8 @@ int main(int argc, char **argv) {
stats.bytes_head += s.bytes_head;
stats.bytes_head_decomp += s.bytes_head_decomp;
stats.bytes_body += s.bytes_body;
stats.udp_dgram_recv += s.udp_dgram_recv;
stats.udp_dgram_sent += s.udp_dgram_sent;
for (size_t i = 0; i < stats.status.size(); ++i) {
stats.status[i] += s.status[i];
@@ -2781,30 +3161,37 @@ traffic: )" << util::utos_funit(stats.bytes_total)
<< util::utos_funit(stats.bytes_head) << "B (" << stats.bytes_head
<< ") headers (space savings " << header_space_savings * 100
<< "%), " << util::utos_funit(stats.bytes_body) << "B ("
<< stats.bytes_body << R"() data
min max mean sd +/- sd
<< stats.bytes_body << R"() data)" << std::endl;
#ifdef ENABLE_HTTP3
if (config.is_quic()) {
std::cout << "UDP datagram: " << stats.udp_dgram_sent << " sent, "
<< stats.udp_dgram_recv << " received" << std::endl;
}
#endif // ENABLE_HTTP3
std::cout
<< R"( min max mean sd +/- sd
time for request: )"
<< std::setw(10) << util::format_duration(ts.request.min) << " "
<< std::setw(10) << util::format_duration(ts.request.max) << " "
<< std::setw(10) << util::format_duration(ts.request.mean) << " "
<< std::setw(10) << util::format_duration(ts.request.sd)
<< std::setw(9) << util::dtos(ts.request.within_sd) << "%"
<< "\ntime for connect: " << std::setw(10)
<< util::format_duration(ts.connect.min) << " " << std::setw(10)
<< util::format_duration(ts.connect.max) << " " << std::setw(10)
<< util::format_duration(ts.connect.mean) << " " << std::setw(10)
<< util::format_duration(ts.connect.sd) << std::setw(9)
<< util::dtos(ts.connect.within_sd) << "%"
<< "\ntime to 1st byte: " << std::setw(10)
<< util::format_duration(ts.ttfb.min) << " " << std::setw(10)
<< util::format_duration(ts.ttfb.max) << " " << std::setw(10)
<< util::format_duration(ts.ttfb.mean) << " " << std::setw(10)
<< util::format_duration(ts.ttfb.sd) << std::setw(9)
<< util::dtos(ts.ttfb.within_sd) << "%"
<< "\nreq/s : " << std::setw(10) << ts.rps.min << " "
<< std::setw(10) << ts.rps.max << " " << std::setw(10)
<< ts.rps.mean << " " << std::setw(10) << ts.rps.sd << std::setw(9)
<< util::dtos(ts.rps.within_sd) << "%" << std::endl;
<< std::setw(10) << util::format_duration(ts.request.min) << " "
<< std::setw(10) << util::format_duration(ts.request.max) << " "
<< std::setw(10) << util::format_duration(ts.request.mean) << " "
<< std::setw(10) << util::format_duration(ts.request.sd) << std::setw(9)
<< util::dtos(ts.request.within_sd) << "%"
<< "\ntime for connect: " << std::setw(10)
<< util::format_duration(ts.connect.min) << " " << std::setw(10)
<< util::format_duration(ts.connect.max) << " " << std::setw(10)
<< util::format_duration(ts.connect.mean) << " " << std::setw(10)
<< util::format_duration(ts.connect.sd) << std::setw(9)
<< util::dtos(ts.connect.within_sd) << "%"
<< "\ntime to 1st byte: " << std::setw(10)
<< util::format_duration(ts.ttfb.min) << " " << std::setw(10)
<< util::format_duration(ts.ttfb.max) << " " << std::setw(10)
<< util::format_duration(ts.ttfb.mean) << " " << std::setw(10)
<< util::format_duration(ts.ttfb.sd) << std::setw(9)
<< util::dtos(ts.ttfb.within_sd) << "%"
<< "\nreq/s : " << std::setw(10) << ts.rps.min << " "
<< std::setw(10) << ts.rps.max << " " << std::setw(10) << ts.rps.mean
<< " " << std::setw(10) << ts.rps.sd << std::setw(9)
<< util::dtos(ts.rps.within_sd) << "%" << std::endl;
SSL_CTX_free(ssl_ctx);

View File

@@ -45,11 +45,19 @@
#include <nghttp2/nghttp2.h>
#ifdef ENABLE_HTTP3
# include <ngtcp2/ngtcp2.h>
# include <ngtcp2/ngtcp2_crypto.h>
#endif // ENABLE_HTTP3
#include <ev.h>
#include <openssl/ssl.h>
#include "http2.h"
#ifdef ENABLE_HTTP3
# include "quic.h"
#endif // ENABLE_HTTP3
#include "memchunk.h"
#include "template.h"
@@ -72,8 +80,13 @@ struct Config {
std::string connect_to_host;
std::string ifile;
std::string ciphers;
std::string tls13_ciphers;
// supported groups (or curves).
std::string groups;
// length of upload data
int64_t data_length;
// memory mapped upload data
uint8_t *data;
addrinfo *addrs;
size_t nreqs;
size_t nclients;
@@ -100,6 +113,8 @@ struct Config {
int data_fd;
// file descriptor to write per-request stats to.
int log_fd;
// base file name of qlog output files
std::string qlog_file_base;
uint16_t port;
uint16_t default_port;
uint16_t connect_to_port;
@@ -114,6 +129,12 @@ struct Config {
// list of supported NPN/ALPN protocol strings in the order of
// preference.
std::vector<std::string> npn_list;
// The number of request per second for each client.
double rps;
// Disables GSO for UDP connections.
bool no_udp_gso;
// The maximum UDP datagram payload size to send.
size_t max_udp_payload_size;
Config();
~Config();
@@ -121,6 +142,8 @@ struct Config {
bool is_rate_mode() const;
bool is_timing_based_mode() const;
bool has_base_uri() const;
bool rps_enabled() const;
bool is_quic() const;
};
struct RequestStat {
@@ -215,8 +238,12 @@ struct Stats {
std::array<size_t, 6> status;
// The statistics per request
std::vector<RequestStat> req_stats;
// THe statistics per client
// The statistics per client
std::vector<ClientStat> client_stats;
// The number of UDP datagrams received.
size_t udp_dgram_recv;
// The number of UDP datagrams sent.
size_t udp_dgram_sent;
};
enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
@@ -306,6 +333,15 @@ struct Client {
std::function<int(Client &)> readfn, writefn;
Worker *worker;
SSL *ssl;
#ifdef ENABLE_HTTP3
struct {
ev_timer pkt_timer;
ngtcp2_conn *conn;
quic::Error last_error;
bool close_requested;
FILE *qlog_file;
} quic;
#endif // ENABLE_HTTP3
ev_timer request_timeout_watcher;
addrinfo *next_addr;
// Address for the current address. When try_new_connection() is
@@ -329,6 +365,7 @@ struct Client {
// The client id per worker
uint32_t id;
int fd;
Address local_addr;
ev_timer conn_active_watcher;
ev_timer conn_inactivity_watcher;
std::string selected_proto;
@@ -336,6 +373,20 @@ struct Client {
// true if the current connection will be closed, and no more new
// request cannot be processed.
bool final;
// rps_watcher is a timer to invoke callback periodically to
// generate a new request.
ev_timer rps_watcher;
// The timestamp that starts the period which contributes to the
// next request generation.
ev_tstamp rps_duration_started;
// The number of requests allowed by rps, but limited by stream
// concurrency.
size_t rps_req_pending;
// The number of in-flight streams. req_inflight has similar value
// but it only measures requests made during Phase::MAIN_DURATION.
// rps_req_inflight measures the number of requests in all phases,
// and it is only used if --rps is given.
size_t rps_req_inflight;
enum { ERR_CONNECT_FAIL = -100 };
@@ -402,6 +453,37 @@ struct Client {
void record_client_end_time();
void signal_write();
#ifdef ENABLE_HTTP3
// QUIC
int quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
const sockaddr *remote_addr, socklen_t remote_addrlen);
void quic_free();
int read_quic();
int write_quic();
int write_udp(const sockaddr *addr, socklen_t addrlen, const uint8_t *data,
size_t datalen, size_t gso_size);
void quic_close_connection();
int quic_handshake_completed();
int quic_recv_stream_data(uint32_t flags, int64_t stream_id,
const uint8_t *data, size_t datalen);
int quic_acked_stream_data_offset(int64_t stream_id, size_t datalen);
int quic_stream_close(int64_t stream_id, uint64_t app_error_code);
int quic_stream_reset(int64_t stream_id, uint64_t app_error_code);
int quic_stream_stop_sending(int64_t stream_id, uint64_t app_error_code);
int quic_extend_max_local_streams();
int quic_on_key(ngtcp2_crypto_level level, const uint8_t *rx_secret,
const uint8_t *tx_secret, size_t secretlen);
void quic_set_tls_alert(uint8_t alert);
void quic_write_client_handshake(ngtcp2_crypto_level level,
const uint8_t *data, size_t datalen);
int quic_pkt_timeout();
void quic_restart_pkt_timer();
void quic_write_qlog(const void *data, size_t datalen);
#endif // ENABLE_HTTP3
};
} // namespace h2load

View File

@@ -105,23 +105,6 @@ int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
}
} // namespace
namespace {
int on_frame_not_send_callback(nghttp2_session *session,
const nghttp2_frame *frame, int lib_error_code,
void *user_data) {
if (frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
auto client = static_cast<Client *>(user_data);
// request was not sent. Mark it as error.
client->on_stream_close(frame->hd.stream_id, false);
return 0;
}
} // namespace
namespace {
int before_frame_send_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data) {
@@ -211,9 +194,6 @@ void Http2Session::on_connect() {
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_frame_not_send_callback(
callbacks, on_frame_not_send_callback);
nghttp2_session_callbacks_set_before_frame_send_callback(
callbacks, before_frame_send_callback);

427
src/h2load_http3_session.cc Normal file
View File

@@ -0,0 +1,427 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2019 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "h2load_http3_session.h"
#include <iostream>
#include <ngtcp2/ngtcp2.h>
#include "h2load.h"
namespace h2load {
Http3Session::Http3Session(Client *client)
: client_(client), conn_(nullptr), npending_request_(0), reqidx_(0) {}
Http3Session::~Http3Session() { nghttp3_conn_del(conn_); }
void Http3Session::on_connect() {}
int Http3Session::submit_request() {
if (npending_request_) {
++npending_request_;
return 0;
}
auto config = client_->worker->config;
reqidx_ = client_->reqidx;
if (++client_->reqidx == config->nva.size()) {
client_->reqidx = 0;
}
auto stream_id = submit_request_internal();
if (stream_id < 0) {
if (stream_id == NGTCP2_ERR_STREAM_ID_BLOCKED) {
++npending_request_;
return 0;
}
return -1;
}
return 0;
}
namespace {
nghttp3_ssize read_data(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec,
size_t veccnt, uint32_t *pflags, void *user_data,
void *stream_user_data) {
auto s = static_cast<Http3Session *>(user_data);
s->read_data(vec, veccnt, pflags);
return 1;
}
} // namespace
void Http3Session::read_data(nghttp3_vec *vec, size_t veccnt,
uint32_t *pflags) {
assert(veccnt > 0);
auto config = client_->worker->config;
vec[0].base = config->data;
vec[0].len = config->data_length;
*pflags |= NGHTTP3_DATA_FLAG_EOF;
}
int64_t Http3Session::submit_request_internal() {
int rv;
int64_t stream_id;
auto config = client_->worker->config;
auto &nva = config->nva[reqidx_];
rv = ngtcp2_conn_open_bidi_stream(client_->quic.conn, &stream_id, nullptr);
if (rv != 0) {
return rv;
}
nghttp3_data_reader dr{};
dr.read_data = h2load::read_data;
rv = nghttp3_conn_submit_request(
conn_, stream_id, reinterpret_cast<nghttp3_nv *>(nva.data()), nva.size(),
config->data_fd == -1 ? nullptr : &dr, nullptr);
if (rv != 0) {
return rv;
}
client_->on_request(stream_id);
auto req_stat = client_->get_req_stat(stream_id);
assert(req_stat);
client_->record_request_time(req_stat);
return stream_id;
}
int Http3Session::on_read(const uint8_t *data, size_t len) { return -1; }
int Http3Session::on_write() { return -1; }
void Http3Session::terminate() {}
size_t Http3Session::max_concurrent_streams() {
return (size_t)client_->worker->config->max_concurrent_streams;
}
namespace {
int stream_close(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code,
void *user_data, void *stream_user_data) {
auto s = static_cast<Http3Session *>(user_data);
if (s->stream_close(stream_id, app_error_code) != 0) {
return NGHTTP3_ERR_CALLBACK_FAILURE;
}
return 0;
}
} // namespace
int Http3Session::stream_close(int64_t stream_id, uint64_t app_error_code) {
if (!ngtcp2_is_bidi_stream(stream_id)) {
assert(!ngtcp2_conn_is_local_stream(client_->quic.conn, stream_id));
ngtcp2_conn_extend_max_streams_uni(client_->quic.conn, 1);
}
client_->on_stream_close(stream_id, app_error_code == NGHTTP3_H3_NO_ERROR);
return 0;
}
namespace {
int recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data,
size_t datalen, void *user_data, void *stream_user_data) {
auto s = static_cast<Http3Session *>(user_data);
s->recv_data(stream_id, data, datalen);
return 0;
}
} // namespace
void Http3Session::recv_data(int64_t stream_id, const uint8_t *data,
size_t datalen) {
client_->record_ttfb();
client_->worker->stats.bytes_body += datalen;
consume(stream_id, datalen);
}
namespace {
int deferred_consume(nghttp3_conn *conn, int64_t stream_id, size_t nconsumed,
void *user_data, void *stream_user_data) {
auto s = static_cast<Http3Session *>(user_data);
s->consume(stream_id, nconsumed);
return 0;
}
} // namespace
void Http3Session::consume(int64_t stream_id, size_t nconsumed) {
ngtcp2_conn_extend_max_stream_offset(client_->quic.conn, stream_id,
nconsumed);
ngtcp2_conn_extend_max_offset(client_->quic.conn, nconsumed);
}
namespace {
int begin_headers(nghttp3_conn *conn, int64_t stream_id, void *user_data,
void *stream_user_data) {
auto s = static_cast<Http3Session *>(user_data);
s->begin_headers(stream_id);
return 0;
}
} // namespace
void Http3Session::begin_headers(int64_t stream_id) {
auto payloadlen = nghttp3_conn_get_frame_payload_left(conn_, stream_id);
assert(payloadlen > 0);
client_->worker->stats.bytes_head += payloadlen;
}
namespace {
int recv_header(nghttp3_conn *conn, int64_t stream_id, int32_t token,
nghttp3_rcbuf *name, nghttp3_rcbuf *value, uint8_t flags,
void *user_data, void *stream_user_data) {
auto s = static_cast<Http3Session *>(user_data);
auto k = nghttp3_rcbuf_get_buf(name);
auto v = nghttp3_rcbuf_get_buf(value);
s->recv_header(stream_id, &k, &v);
return 0;
}
} // namespace
void Http3Session::recv_header(int64_t stream_id, const nghttp3_vec *name,
const nghttp3_vec *value) {
client_->on_header(stream_id, name->base, name->len, value->base, value->len);
client_->worker->stats.bytes_head_decomp += name->len + value->len;
}
namespace {
int send_stop_sending(nghttp3_conn *conn, int64_t stream_id,
uint64_t app_error_code, void *user_data,
void *stream_user_data) {
auto s = static_cast<Http3Session *>(user_data);
if (s->send_stop_sending(stream_id, app_error_code) != 0) {
return NGHTTP3_ERR_CALLBACK_FAILURE;
}
return 0;
}
} // namespace
int Http3Session::send_stop_sending(int64_t stream_id,
uint64_t app_error_code) {
auto rv = ngtcp2_conn_shutdown_stream_read(client_->quic.conn, stream_id,
app_error_code);
if (rv != 0) {
std::cerr << "ngtcp2_conn_shutdown_stream_read: " << ngtcp2_strerror(rv)
<< std::endl;
return -1;
}
return 0;
}
int Http3Session::close_stream(int64_t stream_id, uint64_t app_error_code) {
auto rv = nghttp3_conn_close_stream(conn_, stream_id, app_error_code);
switch (rv) {
case 0:
return 0;
case NGHTTP3_ERR_STREAM_NOT_FOUND:
if (!ngtcp2_is_bidi_stream(stream_id)) {
assert(!ngtcp2_conn_is_local_stream(client_->quic.conn, stream_id));
ngtcp2_conn_extend_max_streams_uni(client_->quic.conn, 1);
}
return 0;
default:
return -1;
}
}
int Http3Session::shutdown_stream_read(int64_t stream_id) {
auto rv = nghttp3_conn_shutdown_stream_read(conn_, stream_id);
if (rv != 0) {
return -1;
}
return 0;
}
int Http3Session::extend_max_local_streams() {
auto config = client_->worker->config;
for (; npending_request_; --npending_request_) {
auto stream_id = submit_request_internal();
if (stream_id < 0) {
if (stream_id == NGTCP2_ERR_STREAM_ID_BLOCKED) {
return 0;
}
return -1;
}
if (++reqidx_ == config->nva.size()) {
reqidx_ = 0;
}
}
return 0;
}
int Http3Session::init_conn() {
int rv;
assert(conn_ == nullptr);
if (ngtcp2_conn_get_max_local_streams_uni(client_->quic.conn) < 3) {
return -1;
}
nghttp3_callbacks callbacks{
nullptr, // acked_stream_data
h2load::stream_close,
h2load::recv_data,
h2load::deferred_consume,
h2load::begin_headers,
h2load::recv_header,
nullptr, // end_headers
nullptr, // begin_trailers
h2load::recv_header,
nullptr, // end_trailers
h2load::send_stop_sending,
};
auto config = client_->worker->config;
nghttp3_settings settings;
nghttp3_settings_default(&settings);
settings.qpack_max_table_capacity = config->header_table_size;
settings.qpack_blocked_streams = 100;
auto mem = nghttp3_mem_default();
rv = nghttp3_conn_client_new(&conn_, &callbacks, &settings, mem, this);
if (rv != 0) {
std::cerr << "nghttp3_conn_client_new: " << nghttp3_strerror(rv)
<< std::endl;
return -1;
}
int64_t ctrl_stream_id;
rv = ngtcp2_conn_open_uni_stream(client_->quic.conn, &ctrl_stream_id, NULL);
if (rv != 0) {
std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
<< std::endl;
return -1;
}
rv = nghttp3_conn_bind_control_stream(conn_, ctrl_stream_id);
if (rv != 0) {
std::cerr << "nghttp3_conn_bind_control_stream: " << nghttp3_strerror(rv)
<< std::endl;
return -1;
}
int64_t qpack_enc_stream_id, qpack_dec_stream_id;
rv = ngtcp2_conn_open_uni_stream(client_->quic.conn, &qpack_enc_stream_id,
NULL);
if (rv != 0) {
std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
<< std::endl;
return -1;
}
rv = ngtcp2_conn_open_uni_stream(client_->quic.conn, &qpack_dec_stream_id,
NULL);
if (rv != 0) {
std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
<< std::endl;
return -1;
}
rv = nghttp3_conn_bind_qpack_streams(conn_, qpack_enc_stream_id,
qpack_dec_stream_id);
if (rv != 0) {
std::cerr << "nghttp3_conn_bind_qpack_streams: " << nghttp3_strerror(rv)
<< std::endl;
return -1;
}
return 0;
}
ssize_t Http3Session::read_stream(uint32_t flags, int64_t stream_id,
const uint8_t *data, size_t datalen) {
auto nconsumed = nghttp3_conn_read_stream(
conn_, stream_id, data, datalen, flags & NGTCP2_STREAM_DATA_FLAG_FIN);
if (nconsumed < 0) {
std::cerr << "nghttp3_conn_read_stream: " << nghttp3_strerror(nconsumed)
<< std::endl;
client_->quic.last_error = quic::err_application(nconsumed);
return -1;
}
return nconsumed;
}
ssize_t Http3Session::write_stream(int64_t &stream_id, int &fin,
nghttp3_vec *vec, size_t veccnt) {
auto sveccnt =
nghttp3_conn_writev_stream(conn_, &stream_id, &fin, vec, veccnt);
if (sveccnt < 0) {
client_->quic.last_error = quic::err_application(sveccnt);
return -1;
}
return sveccnt;
}
int Http3Session::block_stream(int64_t stream_id) {
auto rv = nghttp3_conn_block_stream(conn_, stream_id);
if (rv != 0) {
client_->quic.last_error = quic::err_application(rv);
return -1;
}
return 0;
}
int Http3Session::shutdown_stream_write(int64_t stream_id) {
auto rv = nghttp3_conn_shutdown_stream_write(conn_, stream_id);
if (rv != 0) {
client_->quic.last_error = quic::err_application(rv);
return -1;
}
return 0;
}
int Http3Session::add_write_offset(int64_t stream_id, size_t ndatalen) {
auto rv = nghttp3_conn_add_write_offset(conn_, stream_id, ndatalen);
if (rv != 0) {
client_->quic.last_error = quic::err_application(rv);
return -1;
}
return 0;
}
int Http3Session::add_ack_offset(int64_t stream_id, size_t datalen) {
auto rv = nghttp3_conn_add_ack_offset(conn_, stream_id, datalen);
if (rv != 0) {
client_->quic.last_error = quic::err_application(rv);
return -1;
}
return 0;
}
} // namespace h2load

View File

@@ -0,0 +1,81 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2019 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef H2LOAD_HTTP3_SESSION_H
#define H2LOAD_HTTP3_SESSION_H
#include "h2load_session.h"
#include <nghttp3/nghttp3.h>
namespace h2load {
struct Client;
class Http3Session : public Session {
public:
Http3Session(Client *client);
virtual ~Http3Session();
virtual void on_connect();
virtual int submit_request();
virtual int on_read(const uint8_t *data, size_t len);
virtual int on_write();
virtual void terminate();
virtual size_t max_concurrent_streams();
int init_conn();
int stream_close(int64_t stream_id, uint64_t app_error_code);
void recv_data(int64_t stream_id, const uint8_t *data, size_t datalen);
void consume(int64_t stream_id, size_t nconsumed);
void begin_headers(int64_t stream_id);
void recv_header(int64_t stream_id, const nghttp3_vec *name,
const nghttp3_vec *value);
int send_stop_sending(int64_t stream_id, uint64_t app_error_code);
int close_stream(int64_t stream_id, uint64_t app_error_code);
int shutdown_stream_read(int64_t stream_id);
int extend_max_local_streams();
int64_t submit_request_internal();
ssize_t read_stream(uint32_t flags, int64_t stream_id, const uint8_t *data,
size_t datalen);
ssize_t write_stream(int64_t &stream_id, int &fin, nghttp3_vec *vec,
size_t veccnt);
int block_stream(int64_t stream_id);
int shutdown_stream_write(int64_t stream_id);
int add_write_offset(int64_t stream_id, size_t ndatalen);
int add_ack_offset(int64_t stream_id, size_t datalen);
void read_data(nghttp3_vec *vec, size_t veccnt, uint32_t *pflags);
private:
Client *client_;
nghttp3_conn *conn_;
size_t npending_request_;
size_t reqidx_;
};
} // namespace h2load
#endif // H2LOAD_HTTP3_SESSION_H

680
src/h2load_quic.cc Normal file
View File

@@ -0,0 +1,680 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2019 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "h2load_quic.h"
#include <netinet/udp.h>
#include <iostream>
#include <ngtcp2/ngtcp2_crypto_openssl.h>
#include <openssl/err.h>
#include "h2load_http3_session.h"
namespace h2load {
namespace {
auto randgen = util::make_mt19937();
} // namespace
namespace {
int handshake_completed(ngtcp2_conn *conn, void *user_data) {
auto c = static_cast<Client *>(user_data);
if (c->quic_handshake_completed() != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
} // namespace
int Client::quic_handshake_completed() { return connection_made(); }
namespace {
int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
uint64_t offset, const uint8_t *data, size_t datalen,
void *user_data, void *stream_user_data) {
auto c = static_cast<Client *>(user_data);
if (c->quic_recv_stream_data(flags, stream_id, data, datalen) != 0) {
// TODO Better to do this gracefully rather than
// NGTCP2_ERR_CALLBACK_FAILURE. Perhaps, call
// ngtcp2_conn_write_application_close() ?
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
} // namespace
int Client::quic_recv_stream_data(uint32_t flags, int64_t stream_id,
const uint8_t *data, size_t datalen) {
if (worker->current_phase == Phase::MAIN_DURATION) {
worker->stats.bytes_total += datalen;
}
auto s = static_cast<Http3Session *>(session.get());
auto nconsumed = s->read_stream(flags, stream_id, data, datalen);
if (nconsumed == -1) {
return -1;
}
ngtcp2_conn_extend_max_stream_offset(quic.conn, stream_id, nconsumed);
ngtcp2_conn_extend_max_offset(quic.conn, nconsumed);
return 0;
}
namespace {
int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id,
uint64_t offset, uint64_t datalen, void *user_data,
void *stream_user_data) {
auto c = static_cast<Client *>(user_data);
if (c->quic_acked_stream_data_offset(stream_id, datalen) != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
} // namespace
int Client::quic_acked_stream_data_offset(int64_t stream_id, size_t datalen) {
auto s = static_cast<Http3Session *>(session.get());
if (s->add_ack_offset(stream_id, datalen) != 0) {
return -1;
}
return 0;
}
namespace {
int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
uint64_t app_error_code, void *user_data,
void *stream_user_data) {
auto c = static_cast<Client *>(user_data);
if (!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
app_error_code = NGHTTP3_H3_NO_ERROR;
}
if (c->quic_stream_close(stream_id, app_error_code) != 0) {
return -1;
}
return 0;
}
} // namespace
int Client::quic_stream_close(int64_t stream_id, uint64_t app_error_code) {
auto s = static_cast<Http3Session *>(session.get());
if (s->close_stream(stream_id, app_error_code) != 0) {
return -1;
}
return 0;
}
namespace {
int stream_reset(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size,
uint64_t app_error_code, void *user_data,
void *stream_user_data) {
auto c = static_cast<Client *>(user_data);
if (c->quic_stream_reset(stream_id, app_error_code) != 0) {
return -1;
}
return 0;
}
} // namespace
int Client::quic_stream_reset(int64_t stream_id, uint64_t app_error_code) {
auto s = static_cast<Http3Session *>(session.get());
if (s->shutdown_stream_read(stream_id) != 0) {
return -1;
}
return 0;
}
namespace {
int stream_stop_sending(ngtcp2_conn *conn, int64_t stream_id,
uint64_t app_error_code, void *user_data,
void *stream_user_data) {
auto c = static_cast<Client *>(user_data);
if (c->quic_stream_stop_sending(stream_id, app_error_code) != 0) {
return -1;
}
return 0;
}
} // namespace
int Client::quic_stream_stop_sending(int64_t stream_id,
uint64_t app_error_code) {
auto s = static_cast<Http3Session *>(session.get());
if (s->shutdown_stream_read(stream_id) != 0) {
return -1;
}
return 0;
}
namespace {
int extend_max_local_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams,
void *user_data) {
auto c = static_cast<Client *>(user_data);
if (c->quic_extend_max_local_streams() != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
} // namespace
int Client::quic_extend_max_local_streams() {
auto s = static_cast<Http3Session *>(session.get());
if (s->extend_max_local_streams() != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
namespace {
int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token,
size_t cidlen, void *user_data) {
auto dis = std::uniform_int_distribution<uint8_t>(
0, std::numeric_limits<uint8_t>::max());
auto f = [&dis]() { return dis(randgen); };
std::generate_n(cid->data, cidlen, f);
cid->datalen = cidlen;
std::generate_n(token, NGTCP2_STATELESS_RESET_TOKENLEN, f);
return 0;
}
} // namespace
namespace {
void debug_log_printf(void *user_data, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
} // namespace
namespace {
void generate_cid(ngtcp2_cid &dest) {
auto dis = std::uniform_int_distribution<uint8_t>(
0, std::numeric_limits<uint8_t>::max());
dest.datalen = 8;
std::generate_n(dest.data, dest.datalen, [&dis]() { return dis(randgen); });
}
} // namespace
namespace {
ngtcp2_tstamp timestamp(struct ev_loop *loop) {
return ev_now(loop) * NGTCP2_SECONDS;
}
} // namespace
namespace {
int set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
const uint8_t *rx_secret, const uint8_t *tx_secret,
size_t secret_len) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
if (c->quic_on_key(
ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level),
rx_secret, tx_secret, secret_len) != 0) {
return 0;
}
return 1;
}
} // namespace
namespace {
int add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
const uint8_t *data, size_t len) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
c->quic_write_client_handshake(
ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level), data, len);
return 1;
}
} // namespace
namespace {
int flush_flight(SSL *ssl) { return 1; }
} // namespace
namespace {
int send_alert(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
c->quic_set_tls_alert(alert);
return 1;
}
} // namespace
namespace {
auto quic_method = SSL_QUIC_METHOD{
set_encryption_secrets,
add_handshake_data,
flush_flight,
send_alert,
};
} // namespace
// qlog write callback -- excerpted from ngtcp2/examples/client_base.cc
namespace {
void qlog_write_cb(void *user_data, uint32_t flags, const void *data,
size_t datalen) {
auto c = static_cast<Client *>(user_data);
c->quic_write_qlog(data, datalen);
}
} // namespace
void Client::quic_write_qlog(const void *data, size_t datalen) {
assert(quic.qlog_file != nullptr);
fwrite(data, 1, datalen, quic.qlog_file);
}
int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
const sockaddr *remote_addr, socklen_t remote_addrlen) {
int rv;
if (!ssl) {
ssl = SSL_new(worker->ssl_ctx);
SSL_set_app_data(ssl, this);
SSL_set_connect_state(ssl);
SSL_set_quic_method(ssl, &quic_method);
SSL_set_quic_use_legacy_codepoint(ssl, 0);
}
auto callbacks = ngtcp2_callbacks{
ngtcp2_crypto_client_initial_cb,
nullptr, // recv_client_initial
ngtcp2_crypto_recv_crypto_data_cb,
h2load::handshake_completed,
nullptr, // recv_version_negotiation
ngtcp2_crypto_encrypt_cb,
ngtcp2_crypto_decrypt_cb,
ngtcp2_crypto_hp_mask_cb,
h2load::recv_stream_data,
h2load::acked_stream_data_offset,
nullptr, // stream_open
h2load::stream_close,
nullptr, // recv_stateless_reset
ngtcp2_crypto_recv_retry_cb,
h2load::extend_max_local_streams_bidi,
nullptr, // extend_max_local_streams_uni
nullptr, // rand
get_new_connection_id,
nullptr, // remove_connection_id
ngtcp2_crypto_update_key_cb,
nullptr, // path_validation
nullptr, // select_preferred_addr
h2load::stream_reset,
nullptr, // extend_max_remote_streams_bidi
nullptr, // extend_max_remote_streams_uni
nullptr, // extend_max_stream_data
nullptr, // dcid_status
nullptr, // handshake_confirmed
nullptr, // recv_new_token
ngtcp2_crypto_delete_crypto_aead_ctx_cb,
ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
nullptr, // recv_datagram
nullptr, // ack_datagram
nullptr, // lost_datagram
nullptr, // get_path_challenge_data
h2load::stream_stop_sending,
};
ngtcp2_cid scid, dcid;
generate_cid(scid);
generate_cid(dcid);
auto config = worker->config;
ngtcp2_settings settings;
ngtcp2_settings_default(&settings);
if (config->verbose) {
settings.log_printf = debug_log_printf;
}
settings.initial_ts = timestamp(worker->loop);
if (!config->qlog_file_base.empty()) {
assert(quic.qlog_file == nullptr);
auto path = config->qlog_file_base;
path += '.';
path += util::utos(worker->id);
path += '.';
path += util::utos(id);
path += ".qlog";
quic.qlog_file = fopen(path.c_str(), "w");
if (quic.qlog_file == nullptr) {
std::cerr << "Failed to open a qlog file: " << path << std::endl;
return -1;
}
settings.qlog.write = qlog_write_cb;
}
if (config->max_udp_payload_size) {
settings.max_udp_payload_size = config->max_udp_payload_size;
settings.no_udp_payload_size_shaping = 1;
}
ngtcp2_transport_params params;
ngtcp2_transport_params_default(&params);
auto max_stream_data =
std::min((1 << 26) - 1, (1 << config->window_bits) - 1);
params.initial_max_stream_data_bidi_local = max_stream_data;
params.initial_max_stream_data_uni = max_stream_data;
params.initial_max_data = (1 << config->connection_window_bits) - 1;
params.initial_max_streams_bidi = 0;
params.initial_max_streams_uni = 100;
params.max_idle_timeout = 30 * NGTCP2_SECONDS;
auto path = ngtcp2_path{
{local_addrlen, const_cast<sockaddr *>(local_addr)},
{remote_addrlen, const_cast<sockaddr *>(remote_addr)},
};
assert(config->npn_list.size());
uint32_t quic_version;
if (config->npn_list[0] == NGHTTP3_ALPN_H3) {
quic_version = NGTCP2_PROTO_VER_V1;
} else {
quic_version = NGTCP2_PROTO_VER_MIN;
}
rv = ngtcp2_conn_client_new(&quic.conn, &dcid, &scid, &path, quic_version,
&callbacks, &settings, &params, nullptr, this);
if (rv != 0) {
return -1;
}
ngtcp2_conn_set_tls_native_handle(quic.conn, ssl);
return 0;
}
void Client::quic_free() {
ngtcp2_conn_del(quic.conn);
if (quic.qlog_file != nullptr) {
fclose(quic.qlog_file);
quic.qlog_file = nullptr;
}
}
void Client::quic_close_connection() {
if (!quic.conn) {
return;
}
std::array<uint8_t, NGTCP2_MAX_UDP_PAYLOAD_SIZE> buf;
ngtcp2_ssize nwrite;
ngtcp2_path_storage ps;
ngtcp2_path_storage_zero(&ps);
switch (quic.last_error.type) {
case quic::ErrorType::TransportVersionNegotiation:
return;
case quic::ErrorType::Transport:
nwrite = ngtcp2_conn_write_connection_close(
quic.conn, &ps.path, nullptr, buf.data(), buf.size(),
quic.last_error.code, timestamp(worker->loop));
break;
case quic::ErrorType::Application:
nwrite = ngtcp2_conn_write_application_close(
quic.conn, &ps.path, nullptr, buf.data(), buf.size(),
quic.last_error.code, timestamp(worker->loop));
break;
default:
assert(0);
}
if (nwrite < 0) {
return;
}
write_udp(reinterpret_cast<sockaddr *>(ps.path.remote.addr),
ps.path.remote.addrlen, buf.data(), nwrite, 0);
}
int Client::quic_on_key(ngtcp2_crypto_level level, const uint8_t *rx_secret,
const uint8_t *tx_secret, size_t secretlen) {
if (ngtcp2_crypto_derive_and_install_rx_key(quic.conn, nullptr, nullptr,
nullptr, level, rx_secret,
secretlen) != 0) {
std::cerr << "ngtcp2_crypto_derive_and_install_rx_key() failed"
<< std::endl;
return -1;
}
if (ngtcp2_crypto_derive_and_install_tx_key(quic.conn, nullptr, nullptr,
nullptr, level, tx_secret,
secretlen) != 0) {
std::cerr << "ngtcp2_crypto_derive_and_install_tx_key() failed"
<< std::endl;
return -1;
}
if (level == NGTCP2_CRYPTO_LEVEL_APPLICATION) {
auto s = std::make_unique<Http3Session>(this);
if (s->init_conn() == -1) {
return -1;
}
session = std::move(s);
}
return 0;
}
void Client::quic_set_tls_alert(uint8_t alert) {
quic.last_error = quic::err_transport_tls(alert);
}
void Client::quic_write_client_handshake(ngtcp2_crypto_level level,
const uint8_t *data, size_t datalen) {
assert(level < 2);
ngtcp2_conn_submit_crypto_data(quic.conn, level, data, datalen);
}
void quic_pkt_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
auto c = static_cast<Client *>(w->data);
if (c->quic_pkt_timeout() != 0) {
c->fail();
c->worker->free_client(c);
delete c;
return;
}
}
int Client::quic_pkt_timeout() {
int rv;
auto now = timestamp(worker->loop);
rv = ngtcp2_conn_handle_expiry(quic.conn, now);
if (rv != 0) {
quic.last_error = quic::err_transport(NGTCP2_ERR_INTERNAL);
return -1;
}
return write_quic();
}
void Client::quic_restart_pkt_timer() {
auto expiry = ngtcp2_conn_get_expiry(quic.conn);
auto now = timestamp(worker->loop);
auto t = expiry > now ? static_cast<ev_tstamp>(expiry - now) / NGTCP2_SECONDS
: 1e-9;
quic.pkt_timer.repeat = t;
ev_timer_again(worker->loop, &quic.pkt_timer);
}
int Client::read_quic() {
std::array<uint8_t, 65536> buf;
sockaddr_union su;
socklen_t addrlen = sizeof(su);
int rv;
size_t pktcnt = 0;
ngtcp2_pkt_info pi{};
for (;;) {
auto nread =
recvfrom(fd, buf.data(), buf.size(), MSG_DONTWAIT, &su.sa, &addrlen);
if (nread == -1) {
return 0;
}
assert(quic.conn);
++worker->stats.udp_dgram_recv;
auto path = ngtcp2_path{
{local_addr.len, &local_addr.su.sa},
{addrlen, &su.sa},
};
rv = ngtcp2_conn_read_pkt(quic.conn, &path, &pi, buf.data(), nread,
timestamp(worker->loop));
if (rv != 0) {
std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl;
return -1;
}
if (++pktcnt == 100) {
break;
}
}
return 0;
}
int Client::write_quic() {
ev_io_stop(worker->loop, &wev);
if (quic.close_requested) {
return -1;
}
std::array<nghttp3_vec, 16> vec;
size_t pktcnt = 0;
auto max_udp_payload_size =
ngtcp2_conn_get_path_max_udp_payload_size(quic.conn);
size_t max_pktcnt =
#ifdef UDP_SEGMENT
worker->config->no_udp_gso
? 1
: std::min(static_cast<size_t>(10),
static_cast<size_t>(64_k / max_udp_payload_size));
#else // !UDP_SEGMENT
1;
#endif // !UDP_SEGMENT
std::array<uint8_t, 64_k> buf;
uint8_t *bufpos = buf.data();
ngtcp2_path_storage ps;
ngtcp2_path_storage_zero(&ps);
auto s = static_cast<Http3Session *>(session.get());
for (;;) {
int64_t stream_id = -1;
int fin = 0;
ssize_t sveccnt = 0;
if (session && ngtcp2_conn_get_max_data_left(quic.conn)) {
sveccnt = s->write_stream(stream_id, fin, vec.data(), vec.size());
if (sveccnt == -1) {
return -1;
}
}
ngtcp2_ssize ndatalen;
auto v = vec.data();
auto vcnt = static_cast<size_t>(sveccnt);
uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE;
if (fin) {
flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
}
auto nwrite = ngtcp2_conn_writev_stream(
quic.conn, &ps.path, nullptr, bufpos, max_udp_payload_size, &ndatalen,
flags, stream_id, reinterpret_cast<const ngtcp2_vec *>(v), vcnt,
timestamp(worker->loop));
if (nwrite < 0) {
switch (nwrite) {
case NGTCP2_ERR_STREAM_DATA_BLOCKED:
assert(ndatalen == -1);
if (s->block_stream(stream_id) != 0) {
return -1;
}
continue;
case NGTCP2_ERR_STREAM_SHUT_WR:
assert(ndatalen == -1);
if (s->shutdown_stream_write(stream_id) != 0) {
return -1;
}
continue;
case NGTCP2_ERR_WRITE_MORE:
assert(ndatalen >= 0);
if (s->add_write_offset(stream_id, ndatalen) != 0) {
return -1;
}
continue;
}
quic.last_error = quic::err_transport(nwrite);
return -1;
} else if (ndatalen >= 0 && s->add_write_offset(stream_id, ndatalen) != 0) {
return -1;
}
quic_restart_pkt_timer();
if (nwrite == 0) {
if (bufpos - buf.data()) {
write_udp(ps.path.remote.addr, ps.path.remote.addrlen, buf.data(),
bufpos - buf.data(), max_udp_payload_size);
}
return 0;
}
bufpos += nwrite;
// Assume that the path does not change.
if (++pktcnt == max_pktcnt ||
static_cast<size_t>(nwrite) < max_udp_payload_size) {
write_udp(ps.path.remote.addr, ps.path.remote.addrlen, buf.data(),
bufpos - buf.data(), max_udp_payload_size);
signal_write();
return 0;
}
}
}
} // namespace h2load

38
src/h2load_quic.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2019 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef H2LOAD_QUIC_H
#define H2LOAD_QUIC_H
#include "nghttp2_config.h"
#include <ev.h>
#include "h2load.h"
namespace h2load {
void quic_pkt_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents);
} // namespace h2load
#endif // H2LOAD_QUIC_H

View File

@@ -1841,6 +1841,53 @@ StringRef normalize_path(BlockAllocator &balloc, const StringRef &path,
query);
}
StringRef normalize_path_colon(BlockAllocator &balloc, const StringRef &path,
const StringRef &query) {
// First, decode %XX for unreserved characters and ':', then do
// http2::path_join
// We won't find %XX if length is less than 3.
if (path.size() < 3 ||
std::find(std::begin(path), std::end(path), '%') == std::end(path)) {
return path_join(balloc, StringRef{}, StringRef{}, path, query);
}
// includes last terminal NULL.
auto result = make_byte_ref(balloc, path.size() + 1);
auto p = result.base;
auto it = std::begin(path);
for (; it + 2 < std::end(path);) {
if (*it == '%') {
if (util::is_hex_digit(*(it + 1)) && util::is_hex_digit(*(it + 2))) {
auto c =
(util::hex_to_uint(*(it + 1)) << 4) + util::hex_to_uint(*(it + 2));
if (util::in_rfc3986_unreserved_chars(c) || c == ':') {
*p++ = c;
it += 3;
continue;
}
*p++ = '%';
*p++ = util::upcase(*(it + 1));
*p++ = util::upcase(*(it + 2));
it += 3;
continue;
}
}
*p++ = *it++;
}
p = std::copy(it, std::end(path), p);
*p = '\0';
return path_join(balloc, StringRef{}, StringRef{}, StringRef{result.base, p},
query);
}
std::string normalize_path(const StringRef &path, const StringRef &query) {
BlockAllocator balloc(1024, 1024);

View File

@@ -410,6 +410,12 @@ StringRef to_method_string(int method_token);
StringRef normalize_path(BlockAllocator &balloc, const StringRef &path,
const StringRef &query);
// normalize_path_colon is like normalize_path, but it additionally
// does percent-decoding %3A in order to workaround the issue that ':'
// cannot be included in backend pattern.
StringRef normalize_path_colon(BlockAllocator &balloc, const StringRef &path,
const StringRef &query);
std::string normalize_path(const StringRef &path, const StringRef &query);
StringRef rewrite_clean_path(BlockAllocator &balloc, const StringRef &src);

206
src/http3.cc Normal file
View File

@@ -0,0 +1,206 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2021 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "http3.h"
namespace nghttp2 {
namespace http3 {
namespace {
nghttp3_nv make_nv_internal(const std::string &name, const std::string &value,
bool never_index, uint8_t nv_flags) {
uint8_t flags;
flags = nv_flags |
(never_index ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE);
return {(uint8_t *)name.c_str(), (uint8_t *)value.c_str(), name.size(),
value.size(), flags};
}
} // namespace
namespace {
nghttp3_nv make_nv_internal(const StringRef &name, const StringRef &value,
bool never_index, uint8_t nv_flags) {
uint8_t flags;
flags = nv_flags |
(never_index ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE);
return {(uint8_t *)name.c_str(), (uint8_t *)value.c_str(), name.size(),
value.size(), flags};
}
} // namespace
nghttp3_nv make_nv(const std::string &name, const std::string &value,
bool never_index) {
return make_nv_internal(name, value, never_index, NGHTTP3_NV_FLAG_NONE);
}
nghttp3_nv make_nv(const StringRef &name, const StringRef &value,
bool never_index) {
return make_nv_internal(name, value, never_index, NGHTTP3_NV_FLAG_NONE);
}
nghttp3_nv make_nv_nocopy(const std::string &name, const std::string &value,
bool never_index) {
return make_nv_internal(name, value, never_index,
NGHTTP3_NV_FLAG_NO_COPY_NAME |
NGHTTP3_NV_FLAG_NO_COPY_VALUE);
}
nghttp3_nv make_nv_nocopy(const StringRef &name, const StringRef &value,
bool never_index) {
return make_nv_internal(name, value, never_index,
NGHTTP3_NV_FLAG_NO_COPY_NAME |
NGHTTP3_NV_FLAG_NO_COPY_VALUE);
}
namespace {
void copy_headers_to_nva_internal(std::vector<nghttp3_nv> &nva,
const HeaderRefs &headers, uint8_t nv_flags,
uint32_t flags) {
auto it_forwarded = std::end(headers);
auto it_xff = std::end(headers);
auto it_xfp = std::end(headers);
auto it_via = std::end(headers);
for (auto it = std::begin(headers); it != std::end(headers); ++it) {
auto kv = &(*it);
if (kv->name.empty() || kv->name[0] == ':') {
continue;
}
switch (kv->token) {
case http2::HD_COOKIE:
case http2::HD_CONNECTION:
case http2::HD_HOST:
case http2::HD_HTTP2_SETTINGS:
case http2::HD_KEEP_ALIVE:
case http2::HD_PROXY_CONNECTION:
case http2::HD_SERVER:
case http2::HD_TE:
case http2::HD_TRANSFER_ENCODING:
case http2::HD_UPGRADE:
continue;
case http2::HD_EARLY_DATA:
if (flags & http2::HDOP_STRIP_EARLY_DATA) {
continue;
}
break;
case http2::HD_SEC_WEBSOCKET_ACCEPT:
if (flags & http2::HDOP_STRIP_SEC_WEBSOCKET_ACCEPT) {
continue;
}
break;
case http2::HD_SEC_WEBSOCKET_KEY:
if (flags & http2::HDOP_STRIP_SEC_WEBSOCKET_KEY) {
continue;
}
break;
case http2::HD_FORWARDED:
if (flags & http2::HDOP_STRIP_FORWARDED) {
continue;
}
if (it_forwarded == std::end(headers)) {
it_forwarded = it;
continue;
}
kv = &(*it_forwarded);
it_forwarded = it;
break;
case http2::HD_X_FORWARDED_FOR:
if (flags & http2::HDOP_STRIP_X_FORWARDED_FOR) {
continue;
}
if (it_xff == std::end(headers)) {
it_xff = it;
continue;
}
kv = &(*it_xff);
it_xff = it;
break;
case http2::HD_X_FORWARDED_PROTO:
if (flags & http2::HDOP_STRIP_X_FORWARDED_PROTO) {
continue;
}
if (it_xfp == std::end(headers)) {
it_xfp = it;
continue;
}
kv = &(*it_xfp);
it_xfp = it;
break;
case http2::HD_VIA:
if (flags & http2::HDOP_STRIP_VIA) {
continue;
}
if (it_via == std::end(headers)) {
it_via = it;
continue;
}
kv = &(*it_via);
it_via = it;
break;
}
nva.push_back(
make_nv_internal(kv->name, kv->value, kv->no_index, nv_flags));
}
}
} // namespace
void copy_headers_to_nva(std::vector<nghttp3_nv> &nva,
const HeaderRefs &headers, uint32_t flags) {
copy_headers_to_nva_internal(nva, headers, NGHTTP3_NV_FLAG_NONE, flags);
}
void copy_headers_to_nva_nocopy(std::vector<nghttp3_nv> &nva,
const HeaderRefs &headers, uint32_t flags) {
copy_headers_to_nva_internal(
nva, headers,
NGHTTP3_NV_FLAG_NO_COPY_NAME | NGHTTP3_NV_FLAG_NO_COPY_VALUE, flags);
}
int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
size_t valuelen) {
if (!nghttp3_check_header_name(name, namelen)) {
return 0;
}
if (!nghttp3_check_header_value(value, valuelen)) {
return 0;
}
return 1;
}
} // namespace http3
} // namespace nghttp2

Some files were not shown because too many files have changed in this diff Show More