Compare commits

..

195 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
6384375098 Update manual pages 2018-12-10 00:25:36 +09:00
Tatsuhiro Tsujikawa
27801e98ae Bump up version number to 1.35.1 2018-12-10 00:22:37 +09:00
Tatsuhiro Tsujikawa
60e020a85b nghttpx: Fix broken trailing slash handling
nghttpx allows a pattern with trailing slash to match a request path
without it.  Previously, under certain pattern registration, this does
not work.
2018-12-10 00:22:02 +09:00
Tatsuhiro Tsujikawa
e520469b3e Update manual pages 2018-11-23 10:07:33 +09:00
Tatsuhiro Tsujikawa
54067256eb Bump up version number to 1.35.0 2018-11-23 10:04:04 +09:00
Tatsuhiro Tsujikawa
c4d2eeeec7 Update AUTHORS 2018-11-23 10:01:20 +09:00
Tatsuhiro Tsujikawa
f51e696e4a asio: Add stop() to listen_and_serve doc 2018-11-18 17:30:35 +09:00
Tatsuhiro Tsujikawa
a433b132fc Merge pull request #1260 from nghttp2/h2load-non-final-response
h2load: Handle HTTP/1 non-final response
2018-11-15 17:32:15 +09:00
Tatsuhiro Tsujikawa
cf48a56d2e Merge pull request #1238 from jktjkt/cmake-fix-libevent-detection
cmake: Fix libevent version detection
2018-11-15 17:11:02 +09:00
Tatsuhiro Tsujikawa
6cad1b243b nghttpx: Write mruby send_info early 2018-11-15 10:17:47 +09:00
Tatsuhiro Tsujikawa
3c393dca58 nghttpx: Fix assertion failure on mruby send_info with HTTP/1 frontend 2018-11-15 10:17:41 +09:00
Tatsuhiro Tsujikawa
172924457f h2load: Handle HTTP/1 non-final response 2018-11-15 10:13:19 +09:00
Tatsuhiro Tsujikawa
f6644a92af make clang-format 2018-11-09 22:29:18 +09:00
Tatsuhiro Tsujikawa
48998f7239 Merge pull request #1222 from donny-dont/fix/declspec
Use __has_declspec_attribute for shared builds
2018-11-09 22:18:06 +09:00
Tatsuhiro Tsujikawa
15ff52f9fb Update README 2018-11-02 18:28:00 +09:00
Tatsuhiro Tsujikawa
6c03bb142b Upgrade travis toolchain 2018-11-02 17:57:16 +09:00
Tatsuhiro Tsujikawa
524b439221 Fix travis build failure 2018-11-02 17:56:53 +09:00
Tatsuhiro Tsujikawa
859bf2bc41 Update manual pages 2018-11-02 15:44:57 +09:00
Tatsuhiro Tsujikawa
b5619fb156 h2load: Clarify that time for connect includes TLS handshake 2018-11-02 15:43:35 +09:00
Tatsuhiro Tsujikawa
dcbe0c690f nghttpx: Simplify move ctor and operator 2018-11-02 15:40:53 +09:00
Tatsuhiro Tsujikawa
2996c28456 nghttpx: Cleanup 2018-11-02 15:16:36 +09:00
Tatsuhiro Tsujikawa
42e8ceb656 nghttpx: Convert API status code to enum class 2018-11-02 14:14:48 +09:00
Tatsuhiro Tsujikawa
1daf9ce8b7 nghttpx: Convert WorkerEventType to enum class 2018-11-02 14:14:48 +09:00
Tatsuhiro Tsujikawa
d68edf56c0 nghttpx: Convert MemcachedStatusCode to enum class 2018-11-02 14:14:48 +09:00
Tatsuhiro Tsujikawa
0c4e9fef29 nghttpx: Convert memcached op to enum class 2018-11-02 14:14:48 +09:00
Tatsuhiro Tsujikawa
571404c6e8 nghttpx: Convert MemcachedParseState to enum class 2018-11-02 14:14:48 +09:00
Tatsuhiro Tsujikawa
4d562b773b nghttpx: Convert LogFragmentType to enum class 2018-11-02 14:14:48 +09:00
Tatsuhiro Tsujikawa
e62258713e nghttpx: Convert connection check status to enum class 2018-11-02 14:14:48 +09:00
Tatsuhiro Tsujikawa
4bd075defd nghttpx: Convert Http2Session state to enum class 2018-11-02 14:14:48 +09:00
Tatsuhiro Tsujikawa
b46a324943 nghttpx: Convert FreelistZone to enum class 2018-10-17 14:19:58 +09:00
Tatsuhiro Tsujikawa
4bd44b9cdf nghttpx: Convert dispatch state to enum class 2018-10-17 14:19:58 +09:00
Tatsuhiro Tsujikawa
1b42110d4f nghttpx: Make Downstream state enum class 2018-10-17 14:19:58 +09:00
Tatsuhiro Tsujikawa
0735ec55f3 nghttpx: Convert shrpx_connect_proto to enum class 2018-10-17 14:19:58 +09:00
Tatsuhiro Tsujikawa
00554779e1 nghttpx: Convert DNSResolverStatus to enum class 2018-10-17 14:19:58 +09:00
Tatsuhiro Tsujikawa
0963f38935 nghttpx: Convert SerialEventType to enum class 2018-10-17 14:19:58 +09:00
Tatsuhiro Tsujikawa
1abfa3ca5f nghttpx: Make TLS handshake state enum class 2018-10-17 08:52:27 +09:00
Tatsuhiro Tsujikawa
f2159bc2c1 nghttpx: Convert UpstreamAltMode to enum class 2018-10-17 08:38:55 +09:00
Tatsuhiro Tsujikawa
b0eb68ee9e nghttpx: Convert shrpx_forwarded_node_type to enum class 2018-10-16 23:10:17 +09:00
Tatsuhiro Tsujikawa
e7b7b037f6 nghttpx: Convert shrpx_cookie_secure to enum class 2018-10-16 23:06:59 +09:00
Tatsuhiro Tsujikawa
5e4f434fd8 nghttpx: Convert shrpx_session_affinity to enum class 2018-10-16 23:03:17 +09:00
Tatsuhiro Tsujikawa
20ea964f2f nghttpx: Convert shrpx_proto to enum class 2018-10-16 22:59:34 +09:00
Tatsuhiro Tsujikawa
d105619bc3 src: Remove extra braces if possible 2018-10-15 23:46:33 +09:00
Tatsuhiro Tsujikawa
ec5729b1fa Use std::make_unique 2018-10-15 23:02:44 +09:00
Tatsuhiro Tsujikawa
6c9196953e Use C++14 2018-10-15 22:35:05 +09:00
Tatsuhiro Tsujikawa
46576178a3 Don't send Transfer-Encoding to pre-HTTP/1.1 clients 2018-10-14 22:57:54 +09:00
Tatsuhiro Tsujikawa
5e925f873e Update doc 2018-10-14 22:57:11 +09:00
Tatsuhiro Tsujikawa
153531d4d0 nghttpx: Use the same type as standard stream operator<< 2018-10-07 22:19:00 +09:00
Tatsuhiro Tsujikawa
f7287df03f Bump up version number to 1.35.0-DEV 2018-10-04 12:38:10 +09:00
Tatsuhiro Tsujikawa
2b085815b7 Update manual pages 2018-10-04 12:31:06 +09:00
Tatsuhiro Tsujikawa
986fa30264 Bump up version number to 1.34.0, LT revision to 31:1:17 2018-10-04 12:30:18 +09:00
Tatsuhiro Tsujikawa
7c8cb3a0ce nghttpx: Improve CONNECT response status handling 2018-10-04 12:04:15 +09:00
Tatsuhiro Tsujikawa
334c439ce0 Fix bug that regular CONNECT does not work 2018-10-04 12:02:46 +09:00
Jan Kundrát
6c17ed7e61 cmake: Fix libevent version detection
On my x86_64 Gentoo Linux, the CMake build won't find libevent because
Gentoo wraps include files via multilib-aware wrappers. This means that
the "real" include file lives in
/usr/include/x86_64-pc-linux-gnu/event2/event-config.h , and that
there's a proxy file at /usr/include/event2/event-config.h which check
the compile target's architecture and includes the real file from a
correct directory.

In other words, nghttp2's CMake FindLibevent.cmake reads a wrong file
and ends up not detecting the libevent's version.

This patch fixes it by simply using the version reported by pkg-config
as the libevent's version if the original method fails. I will be happy
to change this patch to always check version from pkg-config if you're
OK with that.

Signed-off-by: Jan Kundrát <jan.kundrat@cesnet.cz>
2018-10-03 17:38:17 +02:00
Tatsuhiro Tsujikawa
6700626c30 Rule out content-length in the successful response to CONNECT 2018-10-03 23:24:32 +09:00
Tatsuhiro Tsujikawa
15162addc4 Update manual pages 2018-10-02 01:34:32 +09:00
Tatsuhiro Tsujikawa
9327077741 Merge pull request #1235 from nghttp2/backend-conn-timeout
nghttpx: Add read/write-timeout parameters to backend option
2018-09-30 13:17:24 +09:00
Tatsuhiro Tsujikawa
aeb92bbbe2 nghttpx: Add read/write-timeout parameters to backend option 2018-09-30 12:32:43 +09:00
Tatsuhiro Tsujikawa
fc7489e044 nghttpx: Fix mruby parameter validation 2018-09-30 12:30:19 +09:00
Tatsuhiro Tsujikawa
87ac872fdc nghttpx: Update doc 2018-09-30 12:28:43 +09:00
Tatsuhiro Tsujikawa
c278adde7a nghttpx: Log error when mruby file cannot be opened 2018-09-30 12:23:01 +09:00
Tatsuhiro Tsujikawa
f94d720909 Merge pull request #1234 from nghttp2/nghttpx-rfc8441
nghttpx: Implement RFC 8441 Bootstrapping WebSocket with HTTP/2
2018-09-29 11:54:47 +09:00
Tatsuhiro Tsujikawa
9b9baa6bd9 Update doc 2018-09-29 11:46:11 +09:00
Tatsuhiro Tsujikawa
02566ee383 nghttpx: Update doc 2018-09-29 11:42:37 +09:00
Tatsuhiro Tsujikawa
3002f31b1f src: Add debug output for SETTINGS_ENABLE_CONNECT_PROTOCOL 2018-09-29 11:39:49 +09:00
Tatsuhiro Tsujikawa
d2a594a753 nghttpx: Implement RFC 8441 Bootstrapping WebSocket with HTTP/2 2018-09-29 11:35:41 +09:00
Tatsuhiro Tsujikawa
651e147711 Allow client sending :protocol optimistically 2018-09-28 00:12:02 +09:00
Tatsuhiro Tsujikawa
a42faf1cc2 nghttpx: Write TLS alert during handshake 2018-09-23 18:01:38 +09:00
Tatsuhiro Tsujikawa
4aac05e193 Merge pull request #1231 from nghttp2/ws-lib-only
Implement RFC 8441
2018-09-23 17:34:53 +09:00
Tatsuhiro Tsujikawa
b80dfaa8a0 Adjustment for RFC 8441 2018-09-23 11:22:30 +09:00
Tatsuhiro Tsujikawa
a19d8f5d31 Deal with :protocol pseudo header 2018-09-23 10:36:30 +09:00
Tatsuhiro Tsujikawa
33f6e90a56 Add NGHTTP2_TOKEN__PROTOCOL 2018-09-23 10:36:30 +09:00
Tatsuhiro Tsujikawa
ed7fabcbc2 Add SETTINGS_ENABLE_CONNECT_PROTOCOL 2018-09-23 10:36:30 +09:00
Tatsuhiro Tsujikawa
8753b6da14 Update doc 2018-09-17 16:12:15 +09:00
Tatsuhiro Tsujikawa
f2de733bdf Update neverbleed to fix OpenSSL 1.1.1 issues 2018-09-16 22:55:07 +09:00
Tatsuhiro Tsujikawa
88ff8c69a0 Update mruby 1.4.1 2018-09-16 22:54:09 +09:00
Tatsuhiro Tsujikawa
a63558a1eb nghttpx: Call OCSP_response_get1_basic only when OCSP status is successful 2018-09-16 22:19:27 +09:00
Tatsuhiro Tsujikawa
3575a1325e nghttpx: Fix crash with plain text HTTP 2018-09-15 12:16:23 +09:00
Tatsuhiro Tsujikawa
e2de2fee69 Update bash_completion 2018-09-15 11:15:22 +09:00
Tatsuhiro Tsujikawa
9f415979fb Update manual pages 2018-09-15 11:15:04 +09:00
Tatsuhiro Tsujikawa
4bfc0cd196 Merge pull request #1230 from nghttp2/nghttpx-faster-logging
nghttpx: Get rid of std::stringstream from Log
2018-09-14 23:13:03 +09:00
Tatsuhiro Tsujikawa
9c824b87fe nghttpx: Get rid of std::stringstream from Log 2018-09-14 22:58:48 +09:00
Tatsuhiro Tsujikawa
a1ea1696be Make VALID_HD_NAME_CHARS and VALID_HD_VALUE_CHARS const qualified 2018-09-13 23:50:31 +09:00
Tatsuhiro Tsujikawa
dfc0f248c6 Make static_table const qualified 2018-09-13 23:48:53 +09:00
Tatsuhiro Tsujikawa
ed7c9db2a6 nghttpx: Add mruby env.tls_handshake_finished 2018-09-09 22:59:35 +09:00
Tatsuhiro Tsujikawa
5b42815afb nghttpx: Strip incoming Early-Data header field by default 2018-09-09 22:37:22 +09:00
Tatsuhiro Tsujikawa
cfe7fa9a75 nghttpx: Add --tls13-ciphers and --tls-client-ciphers options 2018-09-09 16:35:47 +09:00
Tatsuhiro Tsujikawa
cb8a9d58fd src: Remove TLSv1.3 ciphers from DEFAULT_CIPHER_LIST
TLSv1.3 ciphers are treated differently from the ciphers for TLSv1.2
or earlier.
2018-09-09 15:53:04 +09:00
Tatsuhiro Tsujikawa
023b94480b Merge branch 'tls13-early-data' 2018-09-09 15:48:25 +09:00
Tatsuhiro Tsujikawa
9b03c64f68 nghttpx: Should postpone early data by default 2018-09-08 19:22:30 +09:00
Tatsuhiro Tsujikawa
b8eccec62d nghttpx: Disable OpenSSL anti-replay 2018-09-08 19:10:59 +09:00
Tatsuhiro Tsujikawa
9f21258720 Specify SSL_CTX_set_max_early_data and add an option to change max value 2018-09-08 17:59:28 +09:00
Tatsuhiro Tsujikawa
47f6012407 nghttpx: Add an option to postpone early data processing 2018-09-08 17:57:21 +09:00
Tatsuhiro Tsujikawa
770e44de4d Implement draft-ietf-httpbis-replay-02
nghttpx sends early-data header field when forwarding requests which
are received in TLSv1.3 early data, and the TLS handshake is still in
progress.
2018-09-08 17:54:35 +09:00
Tatsuhiro Tsujikawa
2ab319c137 Don't hide error code from openssl 2018-09-08 17:54:35 +09:00
Tatsuhiro Tsujikawa
3992302432 Remove SSL_ERROR_WANT_WRITE handling 2018-09-08 17:54:35 +09:00
Tatsuhiro Tsujikawa
b30f312a70 Honor SSL_read semantics 2018-09-08 17:54:35 +09:00
Tatsuhiro Tsujikawa
c5cdb78a95 nghttpx: Add TLSv1.3 0-RTT early data support 2018-09-08 17:54:35 +09:00
Don
d82811303b Use __has_declspec_attribute for shared builds 2018-09-05 10:01:50 -07:00
Tatsuhiro Tsujikawa
f79a58120e Bump up version number to 1.34.0 2018-09-02 15:55:08 +09:00
Tatsuhiro Tsujikawa
9d843334d6 Update bash_completion 2018-09-02 15:34:33 +09:00
Tatsuhiro Tsujikawa
23cb3f38a6 Update manual pages 2018-09-02 15:33:58 +09:00
Tatsuhiro Tsujikawa
1d682dcdae Bump up version number to 1.33.0, LT revision to 31:0:17 2018-09-02 15:24:28 +09:00
Tatsuhiro Tsujikawa
601fbbb4ae Update doc 2018-09-02 15:24:12 +09:00
Tatsuhiro Tsujikawa
f44aa2466f Update AUTHORS 2018-09-02 15:15:52 +09:00
Tatsuhiro Tsujikawa
dd74a6dd34 Update manual pages 2018-09-02 14:59:38 +09:00
Tatsuhiro Tsujikawa
e959e7338e src: Refactor utos 2018-09-01 22:29:11 +09:00
Tatsuhiro Tsujikawa
fb9a204de2 nghttpx: Fix compile error without mruby 2018-08-31 21:58:35 +09:00
Tatsuhiro Tsujikawa
cd096802bd Update doc 2018-08-28 17:58:18 +09:00
Tatsuhiro Tsujikawa
7417fd71a4 nghttpx: Per-pattern not per-backend 2018-08-28 17:50:01 +09:00
Tatsuhiro Tsujikawa
2d1a981c81 Merge branch 'akonskarm-master' 2018-08-27 21:34:41 +09:00
Tatsuhiro Tsujikawa
45acc922eb clang-format 2018-08-27 21:34:18 +09:00
Tatsuhiro Tsujikawa
214d089910 Merge branch 'master' of https://github.com/akonskarm/nghttp2 into akonskarm-master 2018-08-27 21:30:36 +09:00
Tatsuhiro Tsujikawa
31fd707d0c nghttpx: Fix broken healthmon frontend 2018-08-27 21:21:55 +09:00
Alexandros Konstantinakis-Karmis
9a2e38e058 fix code for reuse addr on asio client 2018-08-27 10:53:14 +03:00
Tatsuhiro Tsujikawa
d24527e7e6 Bump up LT revision due to v1.32.1 release 2018-08-25 17:01:22 +09:00
Tatsuhiro Tsujikawa
6195d747ce nghttpx: Share mruby context if it is compiled from same file 2018-08-24 23:11:21 +09:00
Tatsuhiro Tsujikawa
fb97f596e1 nghttpx: Allocate mruby file because fopen requires NULL terminated string 2018-08-24 23:08:15 +09:00
Tatsuhiro Tsujikawa
0ccc7a770d nghttpx: Move blocked request data to request buffer for API request 2018-08-24 23:07:43 +09:00
Tatsuhiro Tsujikawa
32826466f5 nghttpx: Fix crash with API request 2018-08-24 23:07:16 +09:00
Tatsuhiro Tsujikawa
0422f8a844 nghttpx: Fix worker process crash with neverbleed write error 2018-08-24 22:22:53 +09:00
Tatsuhiro Tsujikawa
e329479a99 Merge pull request #1215 from nghttp2/mruby-per-backend
nghttpx: Support per-backend mruby script
2018-08-23 18:41:40 +09:00
Tatsuhiro Tsujikawa
f80a7873ba Merge branch 'akonskarm-reuse_addr' 2018-08-23 18:19:46 +09:00
Alexandros Konstantinakis-Karmis
866ac6ab27 add option reuse addr in local endpoint configuration of asio client 2018-08-23 18:19:10 +09:00
Tatsuhiro Tsujikawa
b574ae6aa2 nghttpx: Support per-backend mruby script 2018-08-23 18:13:29 +09:00
Tatsuhiro Tsujikawa
de4fd7cd35 doc: Update doc 2018-08-23 11:01:12 +09:00
Tatsuhiro Tsujikawa
32d7883c47 nghttpx: Downstream::request_buf_full: take into account blocked_request_buf_ 2018-08-23 10:55:42 +09:00
Tatsuhiro Tsujikawa
9b24e19763 nghttpx: Choose h1 protocol if headers have been sent to backend on retry 2018-08-22 23:20:13 +09:00
Tatsuhiro Tsujikawa
13ffece12d Merge pull request #1214 from nghttp2/fix-rst-without-dconn
Fix stream reset if data from client is arrived before dconn is attached
2018-08-22 23:05:01 +09:00
Tatsuhiro Tsujikawa
9d5b781df6 Fix stream reset if data from client is arrived before dconn is attached 2018-08-22 22:32:25 +09:00
Tatsuhiro Tsujikawa
11d822c2a7 Merge pull request #1211 from nghttp2/stream-user-data
Tweak nghttp2_session_set_stream_user_data
2018-08-19 21:01:08 +09:00
Tatsuhiro Tsujikawa
4098512b5d Tweak nghttp2_session_set_stream_user_data
nghttp2_session_set_stream_user_data now works for a stream which is
not created yet, but the request which creates the stream is queued.
2018-08-18 17:38:58 +09:00
Tatsuhiro Tsujikawa
7e06ac1072 Merge branch 'akonskarm-master' 2018-08-02 16:18:51 +09:00
Alexandros Konstantinakis-Karmis
c6d8c4013c support definition of local endpoint for cleartext client session 2018-08-02 16:18:23 +09:00
Tatsuhiro Tsujikawa
e5b3f9addd Compile with clang-6.0 2018-06-09 16:27:43 +09:00
Tatsuhiro Tsujikawa
880f948684 Enable IndentPPDirectives 2018-06-09 16:21:30 +09:00
Tatsuhiro Tsujikawa
bda7e079e2 Update .clang-format 2018-06-09 16:20:27 +09:00
Tatsuhiro Tsujikawa
fc94018b97 clang-format-6.0 2018-06-09 16:02:26 +09:00
Tatsuhiro Tsujikawa
159c5e446a Merge pull request #1184 from PiotrSikora/max_streams
Fix handling of SETTINGS_MAX_CONCURRENT_STREAMS.
2018-06-05 22:02:02 +09:00
Tatsuhiro Tsujikawa
bfd4d8b052 Merge pull request #1183 from PiotrSikora/spdy
Remove remaining SPDY code from the integration tests.
2018-06-03 13:14:25 +09:00
Tatsuhiro Tsujikawa
388e785822 Fix typo 2018-06-03 13:10:32 +09:00
Piotr Sikora
2ba1389993 Fix handling of SETTINGS_MAX_CONCURRENT_STREAMS.
The maximum number of outgoing concurrent streams is initially
limited to 100 to avoid issues when the local endpoint submits
lots of requests before receiving initial SETTINGS frame from
the remote endpoint, since sending them at once to the remote
endpoint could lead to rejection of some of the requests.

This initial limit is overwritten with the value advertised in
SETTINGS_MAX_CONCURRENT_STREAMS setting by the remote endpoint,
but previously, it wasn't lifted if the remote endpoint didn't
advertise that setting (implying no limits), in which case the
limit of 100 was retained, even though it was never advertised
by the remote endpoint.

Signed-off-by: Piotr Sikora <piotrsikora@google.com>
2018-05-30 20:24:00 -07:00
Piotr Sikora
d65a417306 Remove remaining SPDY code from the integration tests.
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
2018-05-30 17:45:20 -07:00
Tatsuhiro Tsujikawa
575bc309b9 Fix typo 2018-05-12 13:07:52 +09:00
Tatsuhiro Tsujikawa
00909d0742 Update doc 2018-05-12 13:07:04 +09:00
Tatsuhiro Tsujikawa
a7e38724e7 Merge pull request #1177 from nghttp2/origin-frame
ORIGIN frame
2018-05-12 13:03:12 +09:00
Tatsuhiro Tsujikawa
325612bcde nghttp: Receive ORIGIN frame 2018-05-12 12:35:08 +09:00
Tatsuhiro Tsujikawa
8034221525 Implement ORIGIN frame 2018-05-12 12:35:08 +09:00
Tatsuhiro Tsujikawa
2e6593e5a5 Bump up version number to 1.33.0-DEV 2018-05-08 22:36:31 +09:00
Tatsuhiro Tsujikawa
572735e496 Update manual pages 2018-05-08 22:18:42 +09:00
Tatsuhiro Tsujikawa
e8d693c395 Bump up version number to 1.32.0, LT revision to 30:2:16 2018-05-08 22:12:43 +09:00
Tatsuhiro Tsujikawa
f44dfcd9dc Update AUTHORS 2018-05-08 22:11:06 +09:00
Tatsuhiro Tsujikawa
1f1b0d93d4 Update manual pages 2018-05-07 21:43:13 +09:00
Tatsuhiro Tsujikawa
ce8c749b77 Merge pull request #1173 from nghttp2/asio-client-sni
asio: Support client side SNI
2018-05-04 10:26:31 +09:00
Tatsuhiro Tsujikawa
3e4f257b91 asio: Support client side SNI 2018-05-03 20:29:16 +09:00
Tatsuhiro Tsujikawa
86fab997b4 Upgrade neverbleed to the latest master 2018-05-03 14:51:59 +09:00
Tatsuhiro Tsujikawa
c3ecd44592 Merge pull request #1171 from nghttp2/h2load-rate-and-duration
h2load: -r and --duration are mutually exclusive
2018-04-28 01:23:22 +09:00
Tatsuhiro Tsujikawa
c65ca20a49 h2load: -r and --duration are mutually exclusive 2018-04-28 00:30:43 +09:00
Tatsuhiro Tsujikawa
a5c408c5e3 Ignore all input after calling session_terminate_session 2018-04-22 14:42:28 +09:00
Tatsuhiro Tsujikawa
06379b2861 Fix treatment of padding 2018-04-22 14:42:28 +09:00
Tatsuhiro Tsujikawa
e04de48ed9 Merge pull request #1162 from nghttp2/libressl
Libressl
2018-04-14 23:57:20 +09:00
Tatsuhiro Tsujikawa
009646421c Use LIBRESSL_IN_USE instead of defined(LIBRESSL_VERSION_NUMBER) 2018-04-14 18:31:57 +09:00
Tatsuhiro Tsujikawa
8d0b4544f8 libressl 2.7 has X509_VERIFY_PARAM_* 2018-04-14 18:31:57 +09:00
Tatsuhiro Tsujikawa
d8a34131e1 libressl 2.7 has SSL_CTX_get0_certificate 2018-04-14 18:31:57 +09:00
Tatsuhiro Tsujikawa
5db17d0af9 Compile with libressl 2.7.2 2018-04-14 18:09:47 +09:00
Tatsuhiro Tsujikawa
1bf69b5662 Define LIBRESSL_LEGACY_API and LIBRESSL_2_7_API
LIBRESSL_LEGACY_API is drop-in replacement for LIBRESSL_IN_USE.  In
the upcoming commits, we will add changes to support libressl 2.7.
2018-04-14 18:09:47 +09:00
Tatsuhiro Tsujikawa
3febaef1fa Bump up LT revision to 30:1:16 due to v1.31.1 release 2018-04-13 00:24:13 +09:00
Tatsuhiro Tsujikawa
b1bd6035e8 Fix frame handling 2018-04-07 00:27:55 +09:00
Tatsuhiro Tsujikawa
b48bcb214a examples: Use C style comment in .c files 2018-04-03 22:08:24 +09:00
Tatsuhiro Tsujikawa
6f3ce2c72d examples: Remove unused lambda capture 2018-04-03 22:07:02 +09:00
Tatsuhiro Tsujikawa
2f9121cf44 Merge branch 'Sp1l-Sp1l/allow-no-npn' 2018-04-03 21:42:17 +09:00
Tatsuhiro Tsujikawa
e65e7711ca Add comment on #endif 2018-04-03 21:39:44 +09:00
Tatsuhiro Tsujikawa
636ef51b0f Fix compile error with -Wunused-function 2018-04-03 21:33:09 +09:00
Bernard Spil
400934e5a3 [PATCH] Allow building without NPN
NPN has been superseeded by ALPN. OpenSSL provides a configure
option to disable npn (no-npn) which results in an OpenSSL
installation that defines OPENSSL_NO_NEXTPROTONEG in opensslconf.h

The #ifdef's look safe here (as the next_proto is initialized as
nullptr). Alteratively, macros could be defined for the used npn
methods that return a 0 for next_proto.

Signed-off-by: Bernard Spil <brnrd@FreeBSD.org>
2018-03-25 18:27:23 +02:00
Tatsuhiro Tsujikawa
4c3a3acf9b Merge pull request #1146 from vszakats/cmakestaticlib
cmake: add ENABLE_STATIC_LIB option to build static lib
2018-03-13 23:06:29 +09:00
Tatsuhiro Tsujikawa
9aa6002c37 Merge pull request #1144 from hellojaewon/master
Fix typo
2018-03-13 23:04:05 +09:00
Viktor Szakats
f342260bfe cmake: add ENABLE_STATIC_LIB option to build static lib
When using the ENABLE_LIB_ONLY option, only the shared
library was built. This new option allows to build the
static library as well.
2018-03-12 22:41:37 +00:00
jwchoi
a6dd497016 Fix typo 2018-03-12 09:19:19 +09:00
Tatsuhiro Tsujikawa
842509dab6 Don't allow 101 HTTP status code because HTTP/2 removes HTTP Upgrade 2018-03-11 15:37:30 +09:00
Tatsuhiro Tsujikawa
4add618a3f Bump up version number to 1.32.0-DEV 2018-02-27 22:32:00 +09:00
Tatsuhiro Tsujikawa
6e74466231 Update bash_completion 2018-02-27 21:18:50 +09:00
Tatsuhiro Tsujikawa
478eac099f Update manual pages 2018-02-27 21:18:05 +09:00
Tatsuhiro Tsujikawa
88e2029e37 Bump up version number to 1.31.0, LT revision to 30:0:16 2018-02-27 21:15:26 +09:00
Tatsuhiro Tsujikawa
45d76cf501 nghttpx: Close listening socket on graceful shutdown 2018-02-26 22:40:24 +09:00
Tatsuhiro Tsujikawa
54573f28a8 Merge pull request #1137 from nghttp2/session-set-user-data
Add nghttp2_session_set_user_data() public API function
2018-02-25 18:26:43 +09:00
Tatsuhiro Tsujikawa
17793e99dc Add nghttp2_session_set_user_data() public API function 2018-02-22 21:02:16 +09:00
Tatsuhiro Tsujikawa
5eac3c9025 Update manual pages 2018-02-22 16:14:34 +09:00
Tatsuhiro Tsujikawa
e70195ae91 nghttpx: Update doc 2018-02-22 16:12:38 +09:00
Tatsuhiro Tsujikawa
fe51e7fa1a Merge pull request #1130 from nghttp2/avoid-inet_pton-macro
src: Define nghttp2_inet_pton wrapper to avoid inet_pton macro
2018-02-17 22:58:37 +09:00
Tatsuhiro Tsujikawa
eb951c2ce4 src: Define nghttp2_inet_pton wrapper to avoid inet_pton macro 2018-02-12 16:22:47 +09:00
Tatsuhiro Tsujikawa
39f0ce7c25 Merge pull request #1126 from nghttp2/nghttpx-expired-client-cert
nghttpx: Add an option to accept expired client certificate
2018-02-10 16:00:43 +09:00
Tatsuhiro Tsujikawa
65157811d4 Merge pull request #1123 from nghttp2/mruby-client-cert-not-before-after
nghttpx: Add mruby tls_client_not_before, and tls_client_not_after
2018-02-10 16:00:29 +09:00
Tatsuhiro Tsujikawa
e8af7afc65 nghttpx: Add an option to accept expired client certificate 2018-02-08 16:51:23 +09:00
Tatsuhiro Tsujikawa
38abfd1863 nghttpx: Add mruby tls_client_not_before, and tls_client_not_after 2018-02-08 16:25:31 +09:00
Tatsuhiro Tsujikawa
ff3edc09ed nghttpx: Fix potential memory leak 2018-02-03 18:21:42 +09:00
Tatsuhiro Tsujikawa
0bb1540682 Bump up version number to 1.31.0-DEV 2018-02-02 22:17:47 +09:00
211 changed files with 6294 additions and 2193 deletions

View File

@@ -28,6 +28,7 @@ BraceWrapping:
AfterObjCDeclaration: false AfterObjCDeclaration: false
AfterStruct: false AfterStruct: false
AfterUnion: false AfterUnion: false
AfterExternBlock: false
BeforeCatch: false BeforeCatch: false
BeforeElse: false BeforeElse: false
IndentBraces: false IndentBraces: false
@@ -57,6 +58,7 @@ ForEachMacros:
- foreach - foreach
- Q_FOREACH - Q_FOREACH
- BOOST_FOREACH - BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories: IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2 Priority: 2
@@ -66,6 +68,7 @@ IncludeCategories:
Priority: 1 Priority: 1
IncludeIsMainRegex: '$' IncludeIsMainRegex: '$'
IndentCaseLabels: false IndentCaseLabels: false
IndentPPDirectives: AfterHash
IndentWidth: 2 IndentWidth: 2
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave JavaScriptQuotes: Leave
@@ -86,6 +89,10 @@ PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000 PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60 PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right PointerAlignment: Right
RawStringFormats:
- Delimiter: pb
Language: TextProto
BasedOnStyle: google
ReflowComments: true ReflowComments: true
SortIncludes: false SortIncludes: false
SortUsingDeclarations: true SortUsingDeclarations: true

3
.gitmodules vendored
View File

@@ -3,4 +3,5 @@
url = https://github.com/mruby/mruby url = https://github.com/mruby/mruby
[submodule "third-party/neverbleed"] [submodule "third-party/neverbleed"]
path = third-party/neverbleed path = third-party/neverbleed
url = https://github.com/h2o/neverbleed.git url = https://github.com/tatsuhiro-t/neverbleed.git
branch = openssl111fix

View File

@@ -12,8 +12,10 @@ addons:
apt: apt:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- llvm-toolchain-trusty-7
packages: packages:
- g++-7 - g++-8
- clang-7
- autoconf - autoconf
- automake - automake
- autotools-dev - autotools-dev
@@ -32,7 +34,8 @@ addons:
- cmake-data - cmake-data
before_install: before_install:
- $CC --version - $CC --version
- if [ "$CXX" = "g++" ]; then export CXX="g++-7" CC="gcc-7"; fi - if [ "$CXX" = "g++" ]; then export CXX="g++-8" CC="gcc-8"; fi
- if [ "$CXX" = "clang++" ]; then export CXX="clang++-7" CC="clang-7"; fi
- $CC --version - $CC --version
- go version - go version
- cmake --version - cmake --version

View File

@@ -16,6 +16,7 @@ github issues [2].
187j3x1 187j3x1
Alek Storm Alek Storm
Alex Nalivko Alex Nalivko
Alexandros Konstantinakis-Karmis
Alexis La Goutte Alexis La Goutte
Amir Pakdel Amir Pakdel
Anders Bakken Anders Bakken
@@ -35,6 +36,7 @@ Dave Reisner
David Beitey David Beitey
David Weekly David Weekly
Dmitriy Vetutnev Dmitriy Vetutnev
Don
Dylan Plecki Dylan Plecki
Etienne Cimon Etienne Cimon
Fabian Möller Fabian Möller
@@ -43,6 +45,7 @@ Gabi Davar
Gitai Gitai
Google Inc. Google Inc.
Jacob Champion Jacob Champion
Jan Kundrát
Jan-E Jan-E
Janusz Dziemidowicz Janusz Dziemidowicz
Jay Satiro Jay Satiro
@@ -92,6 +95,7 @@ Tomasz Buchert
Tomasz Torcz Tomasz Torcz
Vernon Tang Vernon Tang
Viacheslav Biriukov Viacheslav Biriukov
Viktor Szakats
Viktor Szépe Viktor Szépe
Wenfeng Liu Wenfeng Liu
Xiaoguang Sun Xiaoguang Sun
@@ -103,6 +107,7 @@ clemahieu
dalf dalf
es es
fangdingjun fangdingjun
jwchoi
kumagi kumagi
lstefani lstefani
makovich makovich

View File

@@ -24,13 +24,13 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
# XXX using 1.8.90 instead of 1.9.0-DEV # XXX using 1.8.90 instead of 1.9.0-DEV
project(nghttp2 VERSION 1.30.0) project(nghttp2 VERSION 1.35.1)
# See versioning rule: # See versioning rule:
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
set(LT_CURRENT 29) set(LT_CURRENT 31)
set(LT_REVISION 2) set(LT_REVISION 1)
set(LT_AGE 15) set(LT_AGE 17)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
include(Version) include(Version)
@@ -117,7 +117,7 @@ else()
endif() endif()
include(ExtractValidFlags) include(ExtractValidFlags)
foreach(_cxx1x_flag -std=c++11 -std=c++0x) foreach(_cxx1x_flag -std=c++14)
extract_valid_cxx_flags(_cxx1x_flag_supported ${_cxx1x_flag}) extract_valid_cxx_flags(_cxx1x_flag_supported ${_cxx1x_flag})
if(_cxx1x_flag_supported) if(_cxx1x_flag_supported)
set(CXX1XCXXFLAGS ${_cxx1x_flag}) set(CXX1XCXXFLAGS ${_cxx1x_flag})

View File

@@ -14,6 +14,7 @@ option(ENABLE_PYTHON_BINDINGS "Build Python bindings"
${ENABLE_PYTHON_BINDINGS_DEFAULT}) ${ENABLE_PYTHON_BINDINGS_DEFAULT})
option(ENABLE_FAILMALLOC "Build failmalloc test program" ON) option(ENABLE_FAILMALLOC "Build failmalloc test program" ON)
option(ENABLE_LIB_ONLY "Build libnghttp2 only. This is a short hand for -DENABLE_APP=0 -DENABLE_EXAMPLES=0 -DENABLE_HPACK_TOOLS=0 -DENABLE_PYTHON_BINDINGS=0") option(ENABLE_LIB_ONLY "Build libnghttp2 only. This is a short hand for -DENABLE_APP=0 -DENABLE_EXAMPLES=0 -DENABLE_HPACK_TOOLS=0 -DENABLE_PYTHON_BINDINGS=0")
option(ENABLE_STATIC_LIB "Build libnghttp2 in static mode also")
option(WITH_LIBXML2 "Use libxml2" option(WITH_LIBXML2 "Use libxml2"
${WITH_LIBXML2_DEFAULT}) ${WITH_LIBXML2_DEFAULT})

View File

@@ -145,8 +145,8 @@ minimizes the risk of private key leakage when serious bug like
Heartbleed is exploited. The neverbleed is disabled by default. To Heartbleed is exploited. The neverbleed is disabled by default. To
enable it, use ``--with-neverbleed`` configure option. enable it, use ``--with-neverbleed`` configure option.
In order to compile the source code, gcc >= 4.8.3 or clang >= 3.4 is In order to compile the source code, gcc >= 6.0 or clang >= 6.0 is
required. required. C++ source code requires C++14 language features.
.. note:: .. note::
@@ -951,7 +951,7 @@ output_length
The length of the compressed header block. The length of the compressed header block.
percentage_of_original_size percentage_of_original_size
``input_length`` / ``output_length`` * 100 ``output_length`` / ``input_length`` * 100
wire wire
The compressed header block as a hex string. The compressed header block as a hex string.
@@ -1332,7 +1332,7 @@ are:
* Boost::Thread * Boost::Thread
The server API is designed to build an HTTP/2 server very easily to utilize The server API is designed to build an HTTP/2 server very easily to utilize
C++11 anonymous functions and closures. The bare minimum example of C++14 anonymous functions and closures. The bare minimum example of
an HTTP/2 server looks like this: an HTTP/2 server looks like this:
.. code-block:: cpp .. code-block:: cpp

View File

@@ -40,6 +40,9 @@ if(LIBEVENT_INCLUDE_DIR)
# Libevent 2.0 # Libevent 2.0
file(STRINGS "${LIBEVENT_INCLUDE_DIR}/event2/event-config.h" file(STRINGS "${LIBEVENT_INCLUDE_DIR}/event2/event-config.h"
LIBEVENT_VERSION REGEX "${_version_regex}") LIBEVENT_VERSION REGEX "${_version_regex}")
if("${LIBEVENT_VERSION}" STREQUAL "")
set(LIBEVENT_VERSION ${PC_LIBEVENT_VERSION})
endif()
else() else()
# Libevent 1.4 # Libevent 1.4
file(STRINGS "${LIBEVENT_INCLUDE_DIR}/event-config.h" file(STRINGS "${LIBEVENT_INCLUDE_DIR}/event-config.h"

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 dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
AC_PREREQ(2.61) AC_PREREQ(2.61)
AC_INIT([nghttp2], [1.30.0], [t-tujikawa@users.sourceforge.net]) AC_INIT([nghttp2], [1.35.1], [t-tujikawa@users.sourceforge.net])
AC_CONFIG_AUX_DIR([.]) AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
@@ -44,9 +44,9 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl See versioning rule: dnl See versioning rule:
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 29) AC_SUBST(LT_CURRENT, 31)
AC_SUBST(LT_REVISION, 2) AC_SUBST(LT_REVISION, 1)
AC_SUBST(LT_AGE, 15) AC_SUBST(LT_AGE, 17)
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"` 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"` minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
@@ -180,7 +180,7 @@ fi
save_CXXFLAGS="$CXXFLAGS" save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS= CXXFLAGS=
AX_CXX_COMPILE_STDCXX_11([noext], [optional]) AX_CXX_COMPILE_STDCXX([14], [noext], [optional])
CXX1XCXXFLAGS="$CXXFLAGS" CXX1XCXXFLAGS="$CXXFLAGS"
CXXFLAGS="$save_CXXFLAGS" CXXFLAGS="$save_CXXFLAGS"

View File

@@ -143,6 +143,7 @@ APIDOCS= \
nghttp2_session_set_local_window_size.rst \ nghttp2_session_set_local_window_size.rst \
nghttp2_session_set_next_stream_id.rst \ nghttp2_session_set_next_stream_id.rst \
nghttp2_session_set_stream_user_data.rst \ nghttp2_session_set_stream_user_data.rst \
nghttp2_session_set_user_data.rst \
nghttp2_session_terminate_session.rst \ nghttp2_session_terminate_session.rst \
nghttp2_session_terminate_session2.rst \ nghttp2_session_terminate_session2.rst \
nghttp2_session_upgrade.rst \ nghttp2_session_upgrade.rst \
@@ -163,6 +164,7 @@ APIDOCS= \
nghttp2_submit_extension.rst \ nghttp2_submit_extension.rst \
nghttp2_submit_goaway.rst \ nghttp2_submit_goaway.rst \
nghttp2_submit_headers.rst \ nghttp2_submit_headers.rst \
nghttp2_submit_origin.rst \
nghttp2_submit_ping.rst \ nghttp2_submit_ping.rst \
nghttp2_submit_priority.rst \ nghttp2_submit_priority.rst \
nghttp2_submit_push_promise.rst \ nghttp2_submit_push_promise.rst \

View File

@@ -8,7 +8,7 @@ _nghttpx()
_get_comp_words_by_ref cur prev _get_comp_words_by_ref cur prev
case $cur in 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 --frontend-keep-alive-timeout --backend-request-buffer --max-request-header-fields --fastopen --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 --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 --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 --no-server-push --no-location-rewrite --single-thread --tls-session-cache-memcached --no-ocsp --backend-response-buffer --tls-min-proto-version --workers --add-forwarded --worker-write-rate --add-request-header --backend-http2-settings-timeout --subcert --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 --user --add-x-forwarded-for --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --backend-connections-per-host --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 --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 '--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" ) )
;; ;;
*) *)
_filedir _filedir

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "H2LOAD" "1" "Feb 02, 2018" "1.30.0" "nghttp2" .TH "H2LOAD" "1" "Dec 10, 2018" "1.35.1" "nghttp2"
.SH NAME .SH NAME
h2load \- HTTP/2 benchmarking tool h2load \- HTTP/2 benchmarking tool
. .
@@ -155,7 +155,7 @@ example, with \fI\%\-t\fP2 and \fI\%\-r\fP4, each thread gets 2
connections per period. When the rate is 0, the program connections per period. When the rate is 0, the program
will run as it normally does, creating connections at will run as it normally does, creating connections at
whatever variable rate it wants. The default value for whatever variable rate it wants. The default value for
this option is 0. this option is 0. \fI\%\-r\fP and \fI\%\-D\fP are mutually exclusive.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -170,7 +170,8 @@ option is 1s.
.TP .TP
.B \-D, \-\-duration=<N> .B \-D, \-\-duration=<N>
Specifies the main duration for the measurements in case Specifies the main duration for the measurements in case
of timing\-based benchmarking. of timing\-based benchmarking. \fI\%\-D\fP and \fI\%\-r\fP are mutually
exclusive.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -376,13 +377,16 @@ range (mean +/\- sd) against total number of successful requests.
.INDENT 7.0 .INDENT 7.0
.TP .TP
.B min .B min
The minimum time taken to connect to a server. The minimum time taken to connect to a server including TLS
handshake.
.TP .TP
.B max .B max
The maximum time taken to connect to a server. The maximum time taken to connect to a server including TLS
handshake.
.TP .TP
.B mean .B mean
The mean time taken to connect to a server. The mean time taken to connect to a server including TLS
handshake.
.TP .TP
.B sd .B sd
The standard deviation of the time taken to connect to a server. The standard deviation of the time taken to connect to a server.

View File

@@ -124,7 +124,7 @@ OPTIONS
connections per period. When the rate is 0, the program connections per period. When the rate is 0, the program
will run as it normally does, creating connections at will run as it normally does, creating connections at
whatever variable rate it wants. The default value for whatever variable rate it wants. The default value for
this option is 0. this option is 0. :option:`-r` and :option:`\-D` are mutually exclusive.
.. option:: --rate-period=<DURATION> .. option:: --rate-period=<DURATION>
@@ -137,7 +137,8 @@ OPTIONS
.. option:: -D, --duration=<N> .. option:: -D, --duration=<N>
Specifies the main duration for the measurements in case Specifies the main duration for the measurements in case
of timing-based benchmarking. of timing-based benchmarking. :option:`-D` and :option:`\-r` are mutually
exclusive.
.. option:: --warm-up-time=<DURATION> .. option:: --warm-up-time=<DURATION>
@@ -312,11 +313,14 @@ time for request
time for connect time for connect
min min
The minimum time taken to connect to a server. The minimum time taken to connect to a server including TLS
handshake.
max max
The maximum time taken to connect to a server. The maximum time taken to connect to a server including TLS
handshake.
mean mean
The mean time taken to connect to a server. The mean time taken to connect to a server including TLS
handshake.
sd sd
The standard deviation of the time taken to connect to a server. The standard deviation of the time taken to connect to a server.
+/- sd +/- sd

View File

@@ -60,11 +60,14 @@ time for request
time for connect time for connect
min min
The minimum time taken to connect to a server. The minimum time taken to connect to a server including TLS
handshake.
max max
The maximum time taken to connect to a server. The maximum time taken to connect to a server including TLS
handshake.
mean mean
The mean time taken to connect to a server. The mean time taken to connect to a server including TLS
handshake.
sd sd
The standard deviation of the time taken to connect to a server. The standard deviation of the time taken to connect to a server.
+/- sd +/- sd

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "NGHTTP" "1" "Feb 02, 2018" "1.30.0" "nghttp2" .TH "NGHTTP" "1" "Dec 10, 2018" "1.35.1" "nghttp2"
.SH NAME .SH NAME
nghttp \- HTTP/2 client nghttp \- HTTP/2 client
. .

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "NGHTTPD" "1" "Feb 02, 2018" "1.30.0" "nghttp2" .TH "NGHTTPD" "1" "Dec 10, 2018" "1.35.1" "nghttp2"
.SH NAME .SH NAME
nghttpd \- HTTP/2 server nghttpd \- HTTP/2 server
. .

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "NGHTTPX" "1" "Feb 02, 2018" "1.30.0" "nghttp2" .TH "NGHTTPX" "1" "Dec 10, 2018" "1.35.1" "nghttp2"
.SH NAME .SH NAME
nghttpx \- HTTP/2 proxy nghttpx \- HTTP/2 proxy
. .
@@ -137,12 +137,15 @@ Several parameters <PARAM> are accepted after <PATTERN>.
The parameters are delimited by ";". The available The parameters are delimited by ";". The available
parameters are: "proto=<PROTO>", "tls", parameters are: "proto=<PROTO>", "tls",
"sni=<SNI_HOST>", "fall=<N>", "rise=<N>", "sni=<SNI_HOST>", "fall=<N>", "rise=<N>",
"affinity=<METHOD>", "dns", and "redirect\-if\-not\-tls". "affinity=<METHOD>", "dns", "redirect\-if\-not\-tls",
The parameter consists of keyword, and optionally "upgrade\-scheme", "mruby=<PATH>",
followed by "=" and value. For example, the parameter "read\-timeout=<DURATION>", and
"proto=h2" consists of the keyword "proto" and value "write\-timeout=<DURATION>". The parameter consists of
"h2". The parameter "tls" consists of the keyword "tls" keyword, and optionally followed by "=" and value. For
without value. Each parameter is described as follows. 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 .sp
The backend application protocol can be specified using The backend application protocol can be specified using
optional "proto" parameter, and in the form of optional "proto" parameter, and in the form of
@@ -235,6 +238,19 @@ particular backend. This is a workaround for a backend
server which requires "https" :scheme pseudo header server which requires "https" :scheme pseudo header
field on TLS encrypted connection. field on TLS encrypted connection.
.sp .sp
"mruby=<PATH>" parameter specifies a path to mruby
script file which is invoked when this pattern is
matched. All backends which share the same pattern must
have the same mruby path.
.sp
"read\-timeout=<DURATION>" and "write\-timeout=<DURATION>"
parameters specify the read and write timeout of the
backend connection when this pattern is matched. All
backends which share the same pattern must have the same
timeouts. If these timeouts are entirely omitted for a
pattern, \fI\%\-\-backend\-read\-timeout\fP and
\fI\%\-\-backend\-write\-timeout\fP are used.
.sp
Since ";" and ":" are used as delimiter, <PATTERN> must Since ";" and ":" are used as delimiter, <PATTERN> must
not contain these characters. Since ";" has special not contain these characters. Since ";" has special
meaning in shell, the option value must be quoted. meaning in shell, the option value must be quoted.
@@ -595,19 +611,43 @@ Default: \fB2m\fP
.B \-\-ciphers=<SUITE> .B \-\-ciphers=<SUITE>
Set allowed cipher list for frontend connection. The Set allowed cipher list for frontend connection. The
format of the string is described in OpenSSL ciphers(1). format of the string is described in OpenSSL ciphers(1).
This option sets cipher suites for TLSv1.2 or earlier.
Use \fI\%\-\-tls13\-ciphers\fP for TLSv1.3.
.sp .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 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 .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-tls13\-ciphers=<SUITE>
Set allowed cipher list for frontend connection. The
format of the string is described in OpenSSL ciphers(1).
This option sets cipher suites for TLSv1.3. Use
\fI\%\-\-ciphers\fP for TLSv1.2 or earlier.
.sp
Default: \fBTLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-client\-ciphers=<SUITE> .B \-\-client\-ciphers=<SUITE>
Set allowed cipher list for backend connection. The Set allowed cipher list for backend connection. The
format of the string is described in OpenSSL ciphers(1). format of the string is described in OpenSSL ciphers(1).
This option sets cipher suites for TLSv1.2 or earlier.
Use \fI\%\-\-tls13\-client\-ciphers\fP for TLSv1.3.
.sp .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 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 .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-tls13\-client\-ciphers=<SUITE>
Set allowed cipher list for backend connection. The
format of the string is described in OpenSSL ciphers(1).
This option sets cipher suites for TLSv1.3. Use
\fI\%\-\-tls13\-client\-ciphers\fP for TLSv1.2 or earlier.
.sp
Default: \fBTLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-ecdh\-curves=<LIST> .B \-\-ecdh\-curves=<LIST>
Set supported curve list for frontend connections. Set supported curve list for frontend connections.
<LIST> is a colon separated list of curve NID or names <LIST> is a colon separated list of curve NID or names
@@ -698,6 +738,14 @@ can contain multiple certificates.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-verify\-client\-tolerate\-expired
Accept expired client certificate. Operator should
handle the expired client certificate by some means
(e.g., mruby script). Otherwise, this option might
cause a security risk.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-client\-private\-key\-file=<PATH> .B \-\-client\-private\-key\-file=<PATH>
Path to file that contains client private key used in Path to file that contains client private key used in
backend client authentication. backend client authentication.
@@ -721,7 +769,7 @@ than TLSv1.2 is specified, make sure that the compatible
ciphers are included in \fI\%\-\-ciphers\fP option. The default ciphers are included in \fI\%\-\-ciphers\fP option. The default
cipher list only includes ciphers compatible with cipher list only includes ciphers compatible with
TLSv1.2 or above. The available versions are: TLSv1.2 or above. The available versions are:
TLSv1.2, TLSv1.1, and TLSv1.0 TLSv1.3, TLSv1.2, TLSv1.1, and TLSv1.0
.sp .sp
Default: \fBTLSv1.2\fP Default: \fBTLSv1.2\fP
.UNINDENT .UNINDENT
@@ -734,9 +782,9 @@ done in case\-insensitive manner. The versions between
enabled. If the protocol list advertised by client does enabled. If the protocol list advertised by client does
not overlap this range, you will receive the error not overlap this range, you will receive the error
message "unknown protocol". The available versions are: message "unknown protocol". The available versions are:
TLSv1.2, TLSv1.1, and TLSv1.0 TLSv1.3, TLSv1.2, TLSv1.1, and TLSv1.0
.sp .sp
Default: \fBTLSv1.2\fP Default: \fBTLSv1.3\fP
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -989,6 +1037,24 @@ 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\-black\-list\fP
option. But be aware its implications. option. But be aware its implications.
.UNINDENT .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.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-max\-early\-data=<SIZE>
Sets the maximum amount of 0\-RTT data that server
accepts.
.sp
Default: \fB16K\fP
.UNINDENT
.SS HTTP/2 .SS HTTP/2
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -996,7 +1062,7 @@ option. But be aware its implications.
Set the maximum number of the concurrent streams in one Set the maximum number of the concurrent streams in one
frontend HTTP/2 session. frontend HTTP/2 session.
.sp .sp
Default: \(ga\(ga 100\(ga\(ga Default: \fB100\fP
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -1352,6 +1418,12 @@ is received, it is left unaltered.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-no\-strip\-incoming\-early\-data
Don\(aqt strip Early\-Data header field from inbound client
requests.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-no\-location\-rewrite .B \-\-no\-location\-rewrite
Don\(aqt rewrite location header field in default mode. Don\(aqt rewrite location header field in default mode.
When \fI\%\-\-http2\-proxy\fP is used, location header field will When \fI\%\-\-http2\-proxy\fP is used, location header field will
@@ -1569,6 +1641,13 @@ signal handling feature is disabled.
.B \-\-mruby\-file=<PATH> .B \-\-mruby\-file=<PATH>
Set mruby script file Set mruby script file
.UNINDENT .UNINDENT
.INDENT 0.0
.TP
.B \-\-ignore\-per\-pattern\-mruby\-error
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 Misc .SS Misc
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -1926,9 +2005,28 @@ server. These hooks allows users to modify header fields, or common
HTTP variables, like authority or request path, and even return custom HTTP variables, like authority or request path, and even return custom
response without forwarding request to backend servers. response without forwarding request to backend servers.
.sp .sp
To specify mruby script file, use \fI\%\-\-mruby\-file\fP option. The There are 2 levels of mruby script invocations: global and
script will be evaluated once per thread on startup, and it must per\-pattern. The global mruby script is set by \fI\%\-\-mruby\-file\fP
instantiate object and evaluate it as the return value (e.g., option and is called for all requests. The per\-pattern mruby script
is set by "mruby" parameter in \fI\%\-b\fP option. It is invoked for
a request which matches the particular pattern. The order of hook
invocation is: global request phase hook, per\-pattern request phase
hook, per\-pattern response phase hook, and finally global response
phase hook. If a hook returns a response, any later hooks are not
invoked. The global request hook is invoked before the pattern
matching is made and changing request path may affect the pattern
matching.
.sp
Please note that request and response hooks of per\-pattern mruby
script for a single request might not come from the same script. This
might happen after a request hook is executed, backend failed for some
reason, and at the same time, backend configuration is replaced by API
request, and then the request uses new configuration on retry. The
response hook from new configuration, if it is specified, will be
invoked.
.sp
The all mruby script will be evaluated once per thread on startup, and
it must instantiate object and evaluate it as the return value (e.g.,
\fBApp.new\fP). This object is called app object. If app object \fBApp.new\fP). This object is called app object. If app object
defines \fBon_req\fP method, it is called with \fI\%Nghttpx::Env\fP defines \fBon_req\fP method, it is called with \fI\%Nghttpx::Env\fP
object on request hook. Similarly, if app object defines \fBon_resp\fP object on request hook. Similarly, if app object defines \fBon_resp\fP
@@ -2030,6 +2128,18 @@ Return the serial number of a client certificate.
.UNINDENT .UNINDENT
.INDENT 7.0 .INDENT 7.0
.TP .TP
.B attribute [R] tls_client_not_before
Return the start date of a client certificate in seconds since
the epoch.
.UNINDENT
.INDENT 7.0
.TP
.B attribute [R] tls_client_not_after
Return the end date of a client certificate in seconds since
the epoch.
.UNINDENT
.INDENT 7.0
.TP
.B attribute [R] tls_cipher .B attribute [R] tls_cipher
Return a TLS cipher negotiated in this connection. Return a TLS cipher negotiated in this connection.
.UNINDENT .UNINDENT
@@ -2053,6 +2163,15 @@ Return true if, and only if a SSL/TLS session is reused.
.B attribute [R] alpn .B attribute [R] alpn
Return ALPN identifier negotiated in this connection. Return ALPN identifier negotiated in this connection.
.UNINDENT .UNINDENT
.INDENT 7.0
.TP
.B attribute [R] tls_handshake_finished
Return true if SSL/TLS handshake has finished. If it returns
false in the request phase hook, the request is received in
TLSv1.3 early data (0\-RTT) and might be vulnerable to the
replay attack. nghttpx will send Early\-Data header field to
backend servers to indicate this.
.UNINDENT
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -2204,10 +2323,10 @@ to the backend, and response phase hook for this request will
not be invoked. When this method is called in response phase not be invoked. When this method is called in response phase
hook, response from backend server is canceled and discarded. hook, response from backend server is canceled and discarded.
The status code and response header fields should be set The status code and response header fields should be set
before using this method. To set status code, use :rb:meth To before using this method. To set status code, use
set response header fields, use
\fI\%Nghttpx::Response#status\fP\&. If status code is not \fI\%Nghttpx::Response#status\fP\&. If status code is not
set, 200 is used. \fI\%Nghttpx::Response#add_header\fP and set, 200 is used. To set response header fields,
\fI\%Nghttpx::Response#add_header\fP and
\fI\%Nghttpx::Response#set_header\fP\&. When this method is \fI\%Nghttpx::Response#set_header\fP\&. When this method is
invoked in response phase hook, the response headers are invoked in response phase hook, the response headers are
filled with the ones received from backend server. To send filled with the ones received from backend server. To send

View File

@@ -121,12 +121,15 @@ Connections
The parameters are delimited by ";". The available The parameters are delimited by ";". The available
parameters are: "proto=<PROTO>", "tls", parameters are: "proto=<PROTO>", "tls",
"sni=<SNI_HOST>", "fall=<N>", "rise=<N>", "sni=<SNI_HOST>", "fall=<N>", "rise=<N>",
"affinity=<METHOD>", "dns", and "redirect-if-not-tls". "affinity=<METHOD>", "dns", "redirect-if-not-tls",
The parameter consists of keyword, and optionally "upgrade-scheme", "mruby=<PATH>",
followed by "=" and value. For example, the parameter "read-timeout=<DURATION>", and
"proto=h2" consists of the keyword "proto" and value "write-timeout=<DURATION>". The parameter consists of
"h2". The parameter "tls" consists of the keyword "tls" keyword, and optionally followed by "=" and value. For
without value. Each parameter is described as follows. 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 The backend application protocol can be specified using
optional "proto" parameter, and in the form of optional "proto" parameter, and in the form of
@@ -219,6 +222,19 @@ Connections
server which requires "https" :scheme pseudo header server which requires "https" :scheme pseudo header
field on TLS encrypted connection. field on TLS encrypted connection.
"mruby=<PATH>" parameter specifies a path to mruby
script file which is invoked when this pattern is
matched. All backends which share the same pattern must
have the same mruby path.
"read-timeout=<DURATION>" and "write-timeout=<DURATION>"
parameters specify the read and write timeout of the
backend connection when this pattern is matched. All
backends which share the same pattern must have the same
timeouts. If these timeouts are entirely omitted for a
pattern, :option:`--backend-read-timeout` and
:option:`--backend-write-timeout` are used.
Since ";" and ":" are used as delimiter, <PATTERN> must Since ";" and ":" are used as delimiter, <PATTERN> must
not contain these characters. Since ";" has special not contain these characters. Since ";" has special
meaning in shell, the option value must be quoted. meaning in shell, the option value must be quoted.
@@ -553,16 +569,38 @@ SSL/TLS
Set allowed cipher list for frontend connection. The Set allowed cipher list for frontend connection. The
format of the string is described in OpenSSL ciphers(1). format of the string is described in OpenSSL ciphers(1).
This option sets cipher suites for TLSv1.2 or earlier.
Use :option:`--tls13-ciphers` for TLSv1.3.
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`` 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 frontend connection. The
format of the string is described in OpenSSL ciphers(1).
This option sets cipher suites for TLSv1.3. Use
:option:`--ciphers` for TLSv1.2 or earlier.
Default: ``TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256``
.. option:: --client-ciphers=<SUITE> .. option:: --client-ciphers=<SUITE>
Set allowed cipher list for backend connection. The Set allowed cipher list for backend connection. The
format of the string is described in OpenSSL ciphers(1). format of the string is described in OpenSSL ciphers(1).
This option sets cipher suites for TLSv1.2 or earlier.
Use :option:`--tls13-client-ciphers` for TLSv1.3.
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`` 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-client-ciphers=<SUITE>
Set allowed cipher list for backend connection. The
format of the string is described in OpenSSL ciphers(1).
This option sets cipher suites for TLSv1.3. Use
:option:`--tls13-client-ciphers` for TLSv1.2 or earlier.
Default: ``TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256``
.. option:: --ecdh-curves=<LIST> .. option:: --ecdh-curves=<LIST>
Set supported curve list for frontend connections. Set supported curve list for frontend connections.
@@ -644,6 +682,13 @@ SSL/TLS
client certificate. The file must be in PEM format. It client certificate. The file must be in PEM format. It
can contain multiple certificates. can contain multiple certificates.
.. option:: --verify-client-tolerate-expired
Accept expired client certificate. Operator should
handle the expired client certificate by some means
(e.g., mruby script). Otherwise, this option might
cause a security risk.
.. option:: --client-private-key-file=<PATH> .. option:: --client-private-key-file=<PATH>
Path to file that contains client private key used in Path to file that contains client private key used in
@@ -666,7 +711,7 @@ SSL/TLS
ciphers are included in :option:`--ciphers` option. The default ciphers are included in :option:`--ciphers` option. The default
cipher list only includes ciphers compatible with cipher list only includes ciphers compatible with
TLSv1.2 or above. The available versions are: TLSv1.2 or above. The available versions are:
TLSv1.2, TLSv1.1, and TLSv1.0 TLSv1.3, TLSv1.2, TLSv1.1, and TLSv1.0
Default: ``TLSv1.2`` Default: ``TLSv1.2``
@@ -678,9 +723,9 @@ SSL/TLS
enabled. If the protocol list advertised by client does enabled. If the protocol list advertised by client does
not overlap this range, you will receive the error not overlap this range, you will receive the error
message "unknown protocol". The available versions are: message "unknown protocol". The available versions are:
TLSv1.2, TLSv1.1, and TLSv1.0 TLSv1.3, TLSv1.2, TLSv1.1, and TLSv1.0
Default: ``TLSv1.2`` Default: ``TLSv1.3``
.. option:: --tls-ticket-key-file=<PATH> .. option:: --tls-ticket-key-file=<PATH>
@@ -908,6 +953,22 @@ SSL/TLS
consider to use :option:`--client-no-http2-cipher-black-list` consider to use :option:`--client-no-http2-cipher-black-list`
option. But be aware its implications. 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.
.. option:: --tls-max-early-data=<SIZE>
Sets the maximum amount of 0-RTT data that server
accepts.
Default: ``16K``
HTTP/2 HTTP/2
~~~~~~ ~~~~~~
@@ -917,7 +978,7 @@ HTTP/2
Set the maximum number of the concurrent streams in one Set the maximum number of the concurrent streams in one
frontend HTTP/2 session. frontend HTTP/2 session.
Default: `` 100`` Default: ``100``
.. option:: --backend-http2-max-concurrent-streams=<N> .. option:: --backend-http2-max-concurrent-streams=<N>
@@ -1224,6 +1285,11 @@ HTTP
Don't append to Via header field. If Via header field Don't append to Via header field. If Via header field
is received, it is left unaltered. is received, it is left unaltered.
.. option:: --no-strip-incoming-early-data
Don't strip Early-Data header field from inbound client
requests.
.. option:: --no-location-rewrite .. option:: --no-location-rewrite
Don't rewrite location header field in default mode. Don't rewrite location header field in default mode.
@@ -1432,6 +1498,12 @@ Scripting
Set mruby script file Set mruby script file
.. option:: --ignore-per-pattern-mruby-error
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.
Misc Misc
~~~~ ~~~~
@@ -1770,9 +1842,28 @@ server. These hooks allows users to modify header fields, or common
HTTP variables, like authority or request path, and even return custom HTTP variables, like authority or request path, and even return custom
response without forwarding request to backend servers. response without forwarding request to backend servers.
To specify mruby script file, use :option:`--mruby-file` option. The There are 2 levels of mruby script invocations: global and
script will be evaluated once per thread on startup, and it must per-pattern. The global mruby script is set by :option:`--mruby-file`
instantiate object and evaluate it as the return value (e.g., option and is called for all requests. The per-pattern mruby script
is set by "mruby" parameter in :option:`-b` option. It is invoked for
a request which matches the particular pattern. The order of hook
invocation is: global request phase hook, per-pattern request phase
hook, per-pattern response phase hook, and finally global response
phase hook. If a hook returns a response, any later hooks are not
invoked. The global request hook is invoked before the pattern
matching is made and changing request path may affect the pattern
matching.
Please note that request and response hooks of per-pattern mruby
script for a single request might not come from the same script. This
might happen after a request hook is executed, backend failed for some
reason, and at the same time, backend configuration is replaced by API
request, and then the request uses new configuration on retry. The
response hook from new configuration, if it is specified, will be
invoked.
The all mruby script will be evaluated once per thread on startup, and
it must instantiate object and evaluate it as the return value (e.g.,
``App.new``). This object is called app object. If app object ``App.new``). This object is called app object. If app object
defines ``on_req`` method, it is called with :rb:class:`Nghttpx::Env` defines ``on_req`` method, it is called with :rb:class:`Nghttpx::Env`
object on request hook. Similarly, if app object defines ``on_resp`` object on request hook. Similarly, if app object defines ``on_resp``
@@ -1859,6 +1950,16 @@ respectively.
Return the serial number of a client certificate. Return the serial number of a client certificate.
.. rb:attr_reader:: tls_client_not_before
Return the start date of a client certificate in seconds since
the epoch.
.. rb:attr_reader:: tls_client_not_after
Return the end date of a client certificate in seconds since
the epoch.
.. rb:attr_reader:: tls_cipher .. rb:attr_reader:: tls_cipher
Return a TLS cipher negotiated in this connection. Return a TLS cipher negotiated in this connection.
@@ -1879,6 +1980,14 @@ respectively.
Return ALPN identifier negotiated in this connection. Return ALPN identifier negotiated in this connection.
.. rb:attr_reader:: tls_handshake_finished
Return true if SSL/TLS handshake has finished. If it returns
false in the request phase hook, the request is received in
TLSv1.3 early data (0-RTT) and might be vulnerable to the
replay attack. nghttpx will send Early-Data header field to
backend servers to indicate this.
.. rb:class:: Request .. rb:class:: Request
Object to represent request from client. The modification to Object to represent request from client. The modification to
@@ -2009,10 +2118,10 @@ respectively.
not be invoked. When this method is called in response phase not be invoked. When this method is called in response phase
hook, response from backend server is canceled and discarded. hook, response from backend server is canceled and discarded.
The status code and response header fields should be set The status code and response header fields should be set
before using this method. To set status code, use :rb:meth To before using this method. To set status code, use
set response header fields, use
:rb:attr:`Nghttpx::Response#status`. If status code is not :rb:attr:`Nghttpx::Response#status`. If status code is not
set, 200 is used. :rb:meth:`Nghttpx::Response#add_header` and set, 200 is used. To set response header fields,
:rb:meth:`Nghttpx::Response#add_header` and
:rb:meth:`Nghttpx::Response#set_header`. When this method is :rb:meth:`Nghttpx::Response#set_header`. When this method is
invoked in response phase hook, the response headers are invoked in response phase hook, the response headers are
filled with the ones received from backend server. To send filled with the ones received from backend server. To send

View File

@@ -299,9 +299,28 @@ server. These hooks allows users to modify header fields, or common
HTTP variables, like authority or request path, and even return custom HTTP variables, like authority or request path, and even return custom
response without forwarding request to backend servers. response without forwarding request to backend servers.
To specify mruby script file, use :option:`--mruby-file` option. The There are 2 levels of mruby script invocations: global and
script will be evaluated once per thread on startup, and it must per-pattern. The global mruby script is set by :option:`--mruby-file`
instantiate object and evaluate it as the return value (e.g., option and is called for all requests. The per-pattern mruby script
is set by "mruby" parameter in :option:`-b` option. It is invoked for
a request which matches the particular pattern. The order of hook
invocation is: global request phase hook, per-pattern request phase
hook, per-pattern response phase hook, and finally global response
phase hook. If a hook returns a response, any later hooks are not
invoked. The global request hook is invoked before the pattern
matching is made and changing request path may affect the pattern
matching.
Please note that request and response hooks of per-pattern mruby
script for a single request might not come from the same script. This
might happen after a request hook is executed, backend failed for some
reason, and at the same time, backend configuration is replaced by API
request, and then the request uses new configuration on retry. The
response hook from new configuration, if it is specified, will be
invoked.
The all mruby script will be evaluated once per thread on startup, and
it must instantiate object and evaluate it as the return value (e.g.,
``App.new``). This object is called app object. If app object ``App.new``). This object is called app object. If app object
defines ``on_req`` method, it is called with :rb:class:`Nghttpx::Env` defines ``on_req`` method, it is called with :rb:class:`Nghttpx::Env`
object on request hook. Similarly, if app object defines ``on_resp`` object on request hook. Similarly, if app object defines ``on_resp``
@@ -388,6 +407,16 @@ respectively.
Return the serial number of a client certificate. Return the serial number of a client certificate.
.. rb:attr_reader:: tls_client_not_before
Return the start date of a client certificate in seconds since
the epoch.
.. rb:attr_reader:: tls_client_not_after
Return the end date of a client certificate in seconds since
the epoch.
.. rb:attr_reader:: tls_cipher .. rb:attr_reader:: tls_cipher
Return a TLS cipher negotiated in this connection. Return a TLS cipher negotiated in this connection.
@@ -408,6 +437,14 @@ respectively.
Return ALPN identifier negotiated in this connection. Return ALPN identifier negotiated in this connection.
.. rb:attr_reader:: tls_handshake_finished
Return true if SSL/TLS handshake has finished. If it returns
false in the request phase hook, the request is received in
TLSv1.3 early data (0-RTT) and might be vulnerable to the
replay attack. nghttpx will send Early-Data header field to
backend servers to indicate this.
.. rb:class:: Request .. rb:class:: Request
Object to represent request from client. The modification to Object to represent request from client. The modification to
@@ -538,10 +575,10 @@ respectively.
not be invoked. When this method is called in response phase not be invoked. When this method is called in response phase
hook, response from backend server is canceled and discarded. hook, response from backend server is canceled and discarded.
The status code and response header fields should be set The status code and response header fields should be set
before using this method. To set status code, use :rb:meth To before using this method. To set status code, use
set response header fields, use
:rb:attr:`Nghttpx::Response#status`. If status code is not :rb:attr:`Nghttpx::Response#status`. If status code is not
set, 200 is used. :rb:meth:`Nghttpx::Response#add_header` and set, 200 is used. To set response header fields,
:rb:meth:`Nghttpx::Response#add_header` and
:rb:meth:`Nghttpx::Response#set_header`. When this method is :rb:meth:`Nghttpx::Response#set_header`. When this method is
invoked in response phase hook, the response headers are invoked in response phase hook, the response headers are
filled with the ones received from backend server. To send filled with the ones received from backend server. To send

View File

@@ -110,9 +110,9 @@ HTTP Messaging
By default, nghttp2 library checks HTTP messaging rules described in By default, nghttp2 library checks HTTP messaging rules described in
`HTTP/2 specification, section 8 `HTTP/2 specification, section 8
<https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-8>`_. <https://tools.ietf.org/html/rfc7540#section-8>`_. Everything
Everything described in that section is not validated however. We described in that section is not validated however. We briefly
briefly describe what the library does in this area. In the following describe what the library does in this area. In the following
description, without loss of generality we omit CONTINUATION frame description, without loss of generality we omit CONTINUATION frame
since they must follow HEADERS frame and are processed atomically. In since they must follow HEADERS frame and are processed atomically. In
other words, they are just one big HEADERS frame. To disable these other words, they are just one big HEADERS frame. To disable these
@@ -249,7 +249,7 @@ set to :type:`nghttp2_session_callbacks` using
`nghttp2_session_callbacks_set_pack_extension_callback()`. `nghttp2_session_callbacks_set_pack_extension_callback()`.
For example, we will illustrate how to send `ALTSVC For example, we will illustrate how to send `ALTSVC
<https://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-14>`_ frame. <https://tools.ietf.org/html/rfc7838>`_ frame.
.. code-block:: c .. code-block:: c

View File

@@ -26,7 +26,7 @@ Coding style
We use clang-format to format source code consistently. The We use clang-format to format source code consistently. The
clang-format configuration file .clang-format is located at the root clang-format configuration file .clang-format is located at the root
directory. Since clang-format produces slightly different results directory. Since clang-format produces slightly different results
between versions, we currently use clang-format-5.0. between versions, we currently use clang-format-6.0.
To detect any violation to the coding style, we recommend to setup git 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. pre-commit hook to check coding style of the changes you introduced.
@@ -34,7 +34,7 @@ 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 .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 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., your PATH or it exists under different name (e.g.,
clang-format-diff-5.0 in debian), either add it to PATH variable or clang-format-diff-6.0 in debian), either add it to PATH variable or
add git option ``clangformatdiff.binary`` to point to the script. add git option ``clangformatdiff.binary`` to point to the script.
For emacs users, integrating clang-format to emacs is very easy. For emacs users, integrating clang-format to emacs is very easy.

View File

@@ -471,6 +471,33 @@ 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 using :option:`--client-no-http2-cipher-black-list` option. But you
should understand its implications. should understand its implications.
TLSv1.3
-------
As of nghttpx v1.34.0, if it is built with OpenSSL 1.1.1 or later, it
supports TLSv1.3. 0-RTT data is supported, but by default its
processing is postponed until TLS handshake completes to mitigate
replay attack. This costs extra round trip and reduces effectiveness
of 0-RTT data. :option:`--tls-no-postpone-early-data` makes nghttpx
not wait for handshake to complete before forwarding request included
in 0-RTT to get full potential of 0-RTT data. In this case, nghttpx
adds ``Early-Data: 1`` header field when forwarding a request to a
backend server. All backend servers should recognize this header
field and understand that there is a risk for replay attack. See `RFC
8470 <https://tools.ietf.org/html/rfc8470>`_ for ``Early-Data`` header
field.
nghttpx disables anti replay protection provided by OpenSSL. The anti
replay protection of OpenSSL requires that a resumed request must hit
the same server which generates the session ticket. Therefore it
might not work nicely in a deployment where there are multiple nghttpx
instances sharing ticket encryption keys via memcached.
Because TLSv1.3 completely changes the semantics of cipher suite
naming scheme and structure, nghttpx provides the new option
:option:`--tls13-ciphers` and :option:`--tls13-client-ciphers` to
change preferred cipher list for TLSv1.3.
Migration from nghttpx v1.18.x or earlier Migration from nghttpx v1.18.x or earlier
----------------------------------------- -----------------------------------------

View File

@@ -67,14 +67,14 @@ int main(int argc, char *argv[]) {
return; return;
} }
req->on_response([&sess](const response &res) { req->on_response([](const response &res) {
std::cerr << "HTTP/2 " << res.status_code() << std::endl; std::cerr << "HTTP/2 " << res.status_code() << std::endl;
for (auto &kv : res.header()) { for (auto &kv : res.header()) {
std::cerr << kv.first << ": " << kv.second.value << "\n"; std::cerr << kv.first << ": " << kv.second.value << "\n";
} }
std::cerr << std::endl; std::cerr << std::endl;
res.on_data([&sess](const uint8_t *data, std::size_t len) { res.on_data([](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len); std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl; std::cerr << std::endl;
}); });

View File

@@ -91,17 +91,17 @@ int main(int argc, char *argv[]) {
return; return;
} }
req->on_response([&sess, req](const response &res) { req->on_response([](const response &res) {
std::cerr << "response header was received" << std::endl; std::cerr << "response header was received" << std::endl;
print_header(res); print_header(res);
res.on_data([&sess](const uint8_t *data, std::size_t len) { res.on_data([](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len); std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl; std::cerr << std::endl;
}); });
}); });
req->on_close([&sess](uint32_t error_code) { req->on_close([](uint32_t error_code) {
std::cerr << "request done with error_code=" << error_code << std::endl; std::cerr << "request done with error_code=" << error_code << std::endl;
}); });

View File

@@ -36,10 +36,10 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> # include <unistd.h>
#endif // HAVE_UNISTD_H #endif // HAVE_UNISTD_H
#ifdef HAVE_FCNTL_H #ifdef HAVE_FCNTL_H
#include <fcntl.h> # include <fcntl.h>
#endif // HAVE_FCNTL_H #endif // HAVE_FCNTL_H
#include <iostream> #include <iostream>
#include <string> #include <string>

View File

@@ -27,26 +27,26 @@
* intentionally made simple. * intentionally made simple.
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> # include <unistd.h>
#endif /* HAVE_UNISTD_H */ #endif /* HAVE_UNISTD_H */
#ifdef HAVE_FCNTL_H #ifdef HAVE_FCNTL_H
#include <fcntl.h> # include <fcntl.h>
#endif /* HAVE_FCNTL_H */ #endif /* HAVE_FCNTL_H */
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> # include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */ #endif /* HAVE_SYS_SOCKET_H */
#ifdef HAVE_NETDB_H #ifdef HAVE_NETDB_H
#include <netdb.h> # include <netdb.h>
#endif /* HAVE_NETDB_H */ #endif /* HAVE_NETDB_H */
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> # include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */ #endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <poll.h> #include <poll.h>
@@ -345,6 +345,7 @@ static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {
callbacks, on_data_chunk_recv_callback); callbacks, on_data_chunk_recv_callback);
} }
#ifndef OPENSSL_NO_NEXTPROTONEG
/* /*
* Callback function for TLS NPN. Since this program only supports * Callback function for TLS NPN. Since this program only supports
* HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2 * HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2
@@ -365,6 +366,7 @@ static int select_next_proto_cb(SSL *ssl, unsigned char **out,
} }
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }
#endif /* !OPENSSL_NO_NEXTPROTONEG */
/* /*
* Setup SSL/TLS context. * Setup SSL/TLS context.
@@ -375,7 +377,9 @@ static void init_ssl_ctx(SSL_CTX *ssl_ctx) {
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
/* Set NPN callback */ /* Set NPN callback */
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL); SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
} }
static void ssl_handshake(SSL *ssl, int fd) { static void ssl_handshake(SSL *ssl, int fd) {

View File

@@ -23,7 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* !HAVE_CONFIG_H */ #endif /* !HAVE_CONFIG_H */
#include <stdio.h> #include <stdio.h>

View File

@@ -23,33 +23,33 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifdef __sgi #ifdef __sgi
#include <string.h> # include <string.h>
#define errx(exitcode, format, args...) \ # define errx(exitcode, format, args...) \
{ \ { \
warnx(format, ##args); \ warnx(format, ##args); \
exit(exitcode); \ exit(exitcode); \
} }
#define warnx(format, args...) fprintf(stderr, format "\n", ##args) # define warnx(format, args...) fprintf(stderr, format "\n", ##args)
char *strndup(const char *s, size_t size); char *strndup(const char *s, size_t size);
#endif #endif
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> # include <unistd.h>
#endif /* HAVE_UNISTD_H */ #endif /* HAVE_UNISTD_H */
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> # include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */ #endif /* HAVE_SYS_SOCKET_H */
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> # include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */ #endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h> #include <netinet/tcp.h>
#ifndef __sgi #ifndef __sgi
#include <err.h> # include <err.h>
#endif #endif
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
@@ -308,6 +308,7 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
return 0; return 0;
} }
#ifndef OPENSSL_NO_NEXTPROTONEG
/* NPN TLS extension client callback. We check that server advertised /* NPN TLS extension client callback. We check that server advertised
the HTTP/2 protocol the nghttp2 library supports. If not, exit the HTTP/2 protocol the nghttp2 library supports. If not, exit
the program. */ the program. */
@@ -322,6 +323,7 @@ static int select_next_proto_cb(SSL *ssl, unsigned char **out,
} }
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }
#endif /* !OPENSSL_NO_NEXTPROTONEG */
/* Create SSL_CTX. */ /* Create SSL_CTX. */
static SSL_CTX *create_ssl_ctx(void) { static SSL_CTX *create_ssl_ctx(void) {
@@ -335,11 +337,13 @@ static SSL_CTX *create_ssl_ctx(void) {
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL); SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3); SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
return ssl_ctx; return ssl_ctx;
} }
@@ -504,12 +508,14 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr) {
ssl = bufferevent_openssl_get_ssl(session_data->bev); ssl = bufferevent_openssl_get_ssl(session_data->bev);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen); SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (alpn == NULL) { if (alpn == NULL) {
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen); SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
} }
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) { if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
fprintf(stderr, "h2 is not negotiated\n"); fprintf(stderr, "h2 is not negotiated\n");

View File

@@ -23,41 +23,41 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifdef __sgi #ifdef __sgi
#define errx(exitcode, format, args...) \ # define errx(exitcode, format, args...) \
{ \ { \
warnx(format, ##args); \ warnx(format, ##args); \
exit(exitcode); \ exit(exitcode); \
} }
#define warn(format, args...) warnx(format ": %s", ##args, strerror(errno)) # define warn(format, args...) warnx(format ": %s", ##args, strerror(errno))
#define warnx(format, args...) fprintf(stderr, format "\n", ##args) # define warnx(format, args...) fprintf(stderr, format "\n", ##args)
#endif #endif
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> # include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */ #endif /* HAVE_SYS_SOCKET_H */
#ifdef HAVE_NETDB_H #ifdef HAVE_NETDB_H
#include <netdb.h> # include <netdb.h>
#endif /* HAVE_NETDB_H */ #endif /* HAVE_NETDB_H */
#include <signal.h> #include <signal.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> # include <unistd.h>
#endif /* HAVE_UNISTD_H */ #endif /* HAVE_UNISTD_H */
#include <sys/stat.h> #include <sys/stat.h>
#ifdef HAVE_FCNTL_H #ifdef HAVE_FCNTL_H
#include <fcntl.h> # include <fcntl.h>
#endif /* HAVE_FCNTL_H */ #endif /* HAVE_FCNTL_H */
#include <ctype.h> #include <ctype.h>
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> # include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */ #endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h> #include <netinet/tcp.h>
#ifndef __sgi #ifndef __sgi
#include <err.h> # include <err.h>
#endif #endif
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
@@ -109,6 +109,7 @@ struct app_context {
static unsigned char next_proto_list[256]; static unsigned char next_proto_list[256];
static size_t next_proto_list_len; static size_t next_proto_list_len;
#ifndef OPENSSL_NO_NEXTPROTONEG
static int next_proto_cb(SSL *ssl, const unsigned char **data, static int next_proto_cb(SSL *ssl, const unsigned char **data,
unsigned int *len, void *arg) { unsigned int *len, void *arg) {
(void)ssl; (void)ssl;
@@ -118,6 +119,7 @@ static int next_proto_cb(SSL *ssl, const unsigned char **data,
*len = (unsigned int)next_proto_list_len; *len = (unsigned int)next_proto_list_len;
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out, static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
@@ -135,7 +137,7 @@ static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
/* Create SSL_CTX. */ /* Create SSL_CTX. */
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) { static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
@@ -172,11 +174,13 @@ static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
NGHTTP2_PROTO_VERSION_ID_LEN); NGHTTP2_PROTO_VERSION_ID_LEN);
next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN; next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN;
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL); SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL); SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
return ssl_ctx; return ssl_ctx;
} }
@@ -690,12 +694,14 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr) {
ssl = bufferevent_openssl_get_ssl(session_data->bev); ssl = bufferevent_openssl_get_ssl(session_data->bev);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen); SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (alpn == NULL) { if (alpn == NULL) {
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen); SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
} }
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) { if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr); fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr);

View File

@@ -9,6 +9,7 @@ HEADERS = [
':scheme', ':scheme',
':status', ':status',
':host', # for spdy ':host', # for spdy
':protocol',
'expect', 'expect',
'host', 'host',
'if-modified-since', 'if-modified-since',
@@ -31,6 +32,9 @@ HEADERS = [
"user-agent", "user-agent",
"date", "date",
"content-type", "content-type",
"early-data",
"sec-websocket-accept",
"sec-websocket-key",
# disallowed h1 headers # disallowed h1 headers
'connection', 'connection',
'keep-alive', 'keep-alive',
@@ -40,4 +44,4 @@ HEADERS = [
] ]
if __name__ == '__main__': if __name__ == '__main__':
gentokenlookup(HEADERS, 'HD') gentokenlookup(HEADERS, 'HD_')

View File

@@ -67,6 +67,7 @@ HEADERS = [
('keep-alive',None), ('keep-alive',None),
('proxy-connection', None), ('proxy-connection', None),
('upgrade', None), ('upgrade', None),
(':protocol', None),
] ]
def to_enum_hd(k): def to_enum_hd(k):

View File

@@ -50,4 +50,4 @@ if __name__ == '__main__':
continue continue
_, m, _ = line.split(',', 2) _, m, _ = line.split(',', 2)
methods.append(m.strip()) methods.append(m.strip())
gentokenlookup(methods, 'HTTP') gentokenlookup(methods, 'HTTP_')

View File

@@ -168,6 +168,13 @@ OPTIONS = [
"no-strip-incoming-x-forwarded-proto", "no-strip-incoming-x-forwarded-proto",
"ocsp-startup", "ocsp-startup",
"no-verify-ocsp", "no-verify-ocsp",
"verify-client-tolerate-expired",
"ignore-per-pattern-mruby-error",
"tls-no-postpone-early-data",
"tls-max-early-data",
"tls13-ciphers",
"tls13-client-ciphers",
"no-strip-incoming-early-data",
] ]
LOGVARS = [ LOGVARS = [
@@ -201,5 +208,5 @@ LOGVARS = [
] ]
if __name__ == '__main__': if __name__ == '__main__':
gentokenlookup(OPTIONS, 'SHRPX_OPTID', value_type='char', comp_fun='util::strieq_l') gentokenlookup(OPTIONS, 'SHRPX_OPTID_', value_type='char', comp_fun='util::strieq_l')
gentokenlookup(LOGVARS, 'SHRPX_LOGF', value_type='char', comp_fun='util::strieq_l', return_type='LogFragmentType', fail_value='SHRPX_LOGF_NONE') gentokenlookup(LOGVARS, 'LogFragmentType::', value_type='char', comp_fun='util::strieq_l', return_type='LogFragmentType', fail_value='LogFragmentType::NONE')

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
def to_enum_hd(k, prefix): def to_enum_hd(k, prefix):
res = prefix + '_' res = prefix
for c in k.upper(): for c in k.upper():
if c == ':' or c == '-': if c == ':' or c == '-':
res += '_' res += '_'
@@ -30,7 +30,7 @@ enum {'''
print '''\ print '''\
{},'''.format(to_enum_hd(k, prefix)) {},'''.format(to_enum_hd(k, prefix))
print '''\ print '''\
{}_MAXIDX, {}MAXIDX,
}};'''.format(prefix) }};'''.format(prefix)
def gen_index_header(tokens, prefix, value_type, comp_fun, return_type, fail_value): def gen_index_header(tokens, prefix, value_type, comp_fun, return_type, fail_value):

View File

@@ -1,7 +1,6 @@
set(GO_FILES set(GO_FILES
nghttpx_http1_test.go nghttpx_http1_test.go
nghttpx_http2_test.go nghttpx_http2_test.go
nghttpx_spdy_test.go
server_tester.go server_tester.go
) )
@@ -22,7 +21,6 @@ set(EXTRA_DIST
add_custom_target(itprep add_custom_target(itprep
COMMAND go get -d -v golang.org/x/net/http2 COMMAND go get -d -v golang.org/x/net/http2
COMMAND go get -d -v github.com/tatsuhiro-t/go-nghttp2 COMMAND go get -d -v github.com/tatsuhiro-t/go-nghttp2
COMMAND go get -d -v github.com/tatsuhiro-t/spdy
COMMAND go get -d -v golang.org/x/net/websocket COMMAND go get -d -v golang.org/x/net/websocket
) )

View File

@@ -7,7 +7,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/tatsuhiro-t/go-nghttp2" "github.com/tatsuhiro-t/go-nghttp2"
"github.com/tatsuhiro-t/spdy"
"golang.org/x/net/http2" "golang.org/x/net/http2"
"golang.org/x/net/http2/hpack" "golang.org/x/net/http2/hpack"
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
@@ -53,14 +52,12 @@ type serverTester struct {
h2PrefaceSent bool // HTTP/2 preface was sent in conn h2PrefaceSent bool // HTTP/2 preface was sent in conn
nextStreamID uint32 // next stream ID nextStreamID uint32 // next stream ID
fr *http2.Framer // HTTP/2 framer fr *http2.Framer // HTTP/2 framer
spdyFr *spdy.Framer // SPDY/3.1 framer
headerBlkBuf bytes.Buffer // buffer to store encoded header block headerBlkBuf bytes.Buffer // buffer to store encoded header block
enc *hpack.Encoder // HTTP/2 HPACK encoder enc *hpack.Encoder // HTTP/2 HPACK encoder
header http.Header // received header fields header http.Header // received header fields
dec *hpack.Decoder // HTTP/2 HPACK decoder dec *hpack.Decoder // HTTP/2 HPACK decoder
authority string // server's host:port authority string // server's host:port
frCh chan http2.Frame // used for incoming HTTP/2 frame frCh chan http2.Frame // used for incoming HTTP/2 frame
spdyFrCh chan spdy.Frame // used for incoming SPDY frame
errCh chan error errCh chan error
} }
@@ -201,7 +198,6 @@ func newServerTesterInternal(src_args []string, t *testing.T, handler http.Handl
nextStreamID: 1, nextStreamID: 1,
authority: authority, authority: authority,
frCh: make(chan http2.Frame), frCh: make(chan http2.Frame),
spdyFrCh: make(chan spdy.Frame),
errCh: make(chan error), errCh: make(chan error),
} }
@@ -229,7 +225,7 @@ func newServerTesterInternal(src_args []string, t *testing.T, handler http.Handl
if alpnH1 { if alpnH1 {
tlsConfig.NextProtos = []string{"http/1.1"} tlsConfig.NextProtos = []string{"http/1.1"}
} else { } else {
tlsConfig.NextProtos = []string{"h2", "spdy/3.1"} tlsConfig.NextProtos = []string{"h2"}
} }
conn, err = tls.Dial("tcp", authority, tlsConfig) conn, err = tls.Dial("tcp", authority, tlsConfig)
} else { } else {
@@ -256,12 +252,6 @@ func newServerTesterInternal(src_args []string, t *testing.T, handler http.Handl
} }
st.fr = http2.NewFramer(st.conn, st.conn) st.fr = http2.NewFramer(st.conn, st.conn)
spdyFr, err := spdy.NewFramer(st.conn, st.conn)
if err != nil {
st.Close()
st.t.Fatalf("Error spdy.NewFramer: %v", err)
}
st.spdyFr = spdyFr
st.enc = hpack.NewEncoder(&st.headerBlkBuf) st.enc = hpack.NewEncoder(&st.headerBlkBuf)
st.dec = hpack.NewDecoder(4096, func(f hpack.HeaderField) { st.dec = hpack.NewDecoder(4096, func(f hpack.HeaderField) {
st.header.Add(f.Name, f.Value) st.header.Add(f.Name, f.Value)
@@ -315,26 +305,6 @@ func (st *serverTester) readFrame() (http2.Frame, error) {
} }
} }
func (st *serverTester) readSpdyFrame() (spdy.Frame, error) {
go func() {
f, err := st.spdyFr.ReadFrame()
if err != nil {
st.errCh <- err
return
}
st.spdyFrCh <- f
}()
select {
case f := <-st.spdyFrCh:
return f, nil
case err := <-st.errCh:
return nil, err
case <-time.After(2 * time.Second):
return nil, errors.New("timeout waiting for frame")
}
}
type requestParam struct { type requestParam struct {
name string // name for this request to identify the request in log easily name string // name for this request to identify the request in log easily
streamID uint32 // stream ID, automatically assigned if 0 streamID uint32 // stream ID, automatically assigned if 0
@@ -475,122 +445,6 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
return res, nil return res, nil
} }
func (st *serverTester) spdy(rp requestParam) (*serverResponse, error) {
res := &serverResponse{}
var id spdy.StreamId
if rp.streamID != 0 {
id = spdy.StreamId(rp.streamID)
if id >= spdy.StreamId(st.nextStreamID) && id%2 == 1 {
st.nextStreamID = uint32(id) + 2
}
} else {
id = spdy.StreamId(st.nextStreamID)
st.nextStreamID += 2
}
method := "GET"
if rp.method != "" {
method = rp.method
}
scheme := "http"
if rp.scheme != "" {
scheme = rp.scheme
}
host := st.authority
if rp.authority != "" {
host = rp.authority
}
path := "/"
if rp.path != "" {
path = rp.path
}
header := make(http.Header)
header.Add(":method", method)
header.Add(":scheme", scheme)
header.Add(":host", host)
header.Add(":path", path)
header.Add(":version", "HTTP/1.1")
header.Add("test-case", rp.name)
for _, h := range rp.header {
header.Add(h.Name, h.Value)
}
var synStreamFlags spdy.ControlFlags
if len(rp.body) == 0 && !rp.noEndStream {
synStreamFlags = spdy.ControlFlagFin
}
if err := st.spdyFr.WriteFrame(&spdy.SynStreamFrame{
CFHeader: spdy.ControlFrameHeader{
Flags: synStreamFlags,
},
StreamId: id,
Headers: header,
}); err != nil {
return nil, err
}
if len(rp.body) != 0 {
var dataFlags spdy.DataFlags
if !rp.noEndStream {
dataFlags = spdy.DataFlagFin
}
if err := st.spdyFr.WriteFrame(&spdy.DataFrame{
StreamId: id,
Flags: dataFlags,
Data: rp.body,
}); err != nil {
return nil, err
}
}
loop:
for {
fr, err := st.readSpdyFrame()
if err != nil {
return res, err
}
switch f := fr.(type) {
case *spdy.SynReplyFrame:
if f.StreamId != id {
break
}
res.header = cloneHeader(f.Headers)
if _, err := fmt.Sscan(res.header.Get(":status"), &res.status); err != nil {
return res, fmt.Errorf("Error parsing status code: %v", err)
}
if f.CFHeader.Flags&spdy.ControlFlagFin != 0 {
break loop
}
case *spdy.DataFrame:
if f.StreamId != id {
break
}
res.body = append(res.body, f.Data...)
if f.Flags&spdy.DataFlagFin != 0 {
break loop
}
case *spdy.RstStreamFrame:
if f.StreamId != id {
break
}
res.spdyRstErrCode = f.Status
break loop
case *spdy.GoAwayFrame:
if f.Status == spdy.GoAwayOK {
break
}
res.spdyGoAwayErrCode = f.Status
break loop
}
}
return res, nil
}
func (st *serverTester) http2(rp requestParam) (*serverResponse, error) { func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
st.headerBlkBuf.Reset() st.headerBlkBuf.Reset()
st.header = make(http.Header) st.header = make(http.Header)
@@ -779,8 +633,6 @@ type serverResponse struct {
streamID uint32 // stream ID in HTTP/2 streamID uint32 // stream ID in HTTP/2
errCode http2.ErrCode // error code received in HTTP/2 RST_STREAM or GOAWAY errCode http2.ErrCode // error code received in HTTP/2 RST_STREAM or GOAWAY
connErr bool // true if HTTP/2 connection error connErr bool // true if HTTP/2 connection error
spdyGoAwayErrCode spdy.GoAwayStatus // status code received in SPDY RST_STREAM
spdyRstErrCode spdy.RstStreamStatus // status code received in SPDY GOAWAY
connClose bool // Connection: close is included in response header in HTTP/1 test connClose bool // Connection: close is included in response header in HTTP/1 test
reqHeader http.Header // http request header, currently only sotres pushed request header reqHeader http.Header // http request header, currently only sotres pushed request header
pushResponse []*serverResponse // pushed response pushResponse []*serverResponse // pushed response

View File

@@ -49,7 +49,7 @@ target_include_directories(nghttp2 INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/includes" "${CMAKE_CURRENT_SOURCE_DIR}/includes"
) )
if(HAVE_CUNIT) if(HAVE_CUNIT OR ENABLE_STATIC_LIB)
# Static library (for unittests because of symbol visibility) # Static library (for unittests because of symbol visibility)
add_library(nghttp2_static STATIC ${NGHTTP2_SOURCES}) add_library(nghttp2_static STATIC ${NGHTTP2_SOURCES})
set_target_properties(nghttp2_static PROPERTIES set_target_properties(nghttp2_static PROPERTIES
@@ -58,6 +58,10 @@ if(HAVE_CUNIT)
ARCHIVE_OUTPUT_NAME nghttp2 ARCHIVE_OUTPUT_NAME nghttp2
) )
target_compile_definitions(nghttp2_static PUBLIC "-DNGHTTP2_STATICLIB") target_compile_definitions(nghttp2_static PUBLIC "-DNGHTTP2_STATICLIB")
if(ENABLE_STATIC_LIB)
install(TARGETS nghttp2_static
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
endif()
endif() endif()
install(TARGETS nghttp2 install(TARGETS nghttp2

View File

@@ -28,7 +28,12 @@
/* Define WIN32 when build target is Win32 API (borrowed from /* Define WIN32 when build target is Win32 API (borrowed from
libcurl) */ libcurl) */
#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
#define WIN32 # define WIN32
#endif
/* Compatibility for non-Clang compilers */
#ifndef __has_declspec_attribute
# define __has_declspec_attribute(x) 0
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
@@ -40,9 +45,9 @@ extern "C" {
/* MSVC < 2013 does not have inttypes.h because it is not C99 /* MSVC < 2013 does not have inttypes.h because it is not C99
compliant. See compiler macros and version number in compliant. See compiler macros and version number in
https://sourceforge.net/p/predef/wiki/Compilers/ */ https://sourceforge.net/p/predef/wiki/Compilers/ */
#include <stdint.h> # include <stdint.h>
#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ #else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
#include <inttypes.h> # include <inttypes.h>
#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ #endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
#include <sys/types.h> #include <sys/types.h>
#include <stdarg.h> #include <stdarg.h>
@@ -50,20 +55,21 @@ extern "C" {
#include <nghttp2/nghttp2ver.h> #include <nghttp2/nghttp2ver.h>
#ifdef NGHTTP2_STATICLIB #ifdef NGHTTP2_STATICLIB
#define NGHTTP2_EXTERN # define NGHTTP2_EXTERN
#elif defined(WIN32) #elif defined(WIN32) || (__has_declspec_attribute(dllexport) && \
#ifdef BUILDING_NGHTTP2 __has_declspec_attribute(dllimport))
#define NGHTTP2_EXTERN __declspec(dllexport) # ifdef BUILDING_NGHTTP2
#else /* !BUILDING_NGHTTP2 */ # define NGHTTP2_EXTERN __declspec(dllexport)
#define NGHTTP2_EXTERN __declspec(dllimport) # else /* !BUILDING_NGHTTP2 */
#endif /* !BUILDING_NGHTTP2 */ # define NGHTTP2_EXTERN __declspec(dllimport)
#else /* !defined(WIN32) */ # endif /* !BUILDING_NGHTTP2 */
#ifdef BUILDING_NGHTTP2 #else /* !defined(WIN32) */
#define NGHTTP2_EXTERN __attribute__((visibility("default"))) # ifdef BUILDING_NGHTTP2
#else /* !BUILDING_NGHTTP2 */ # define NGHTTP2_EXTERN __attribute__((visibility("default")))
#define NGHTTP2_EXTERN # else /* !BUILDING_NGHTTP2 */
#endif /* !BUILDING_NGHTTP2 */ # define NGHTTP2_EXTERN
#endif /* !defined(WIN32) */ # endif /* !BUILDING_NGHTTP2 */
#endif /* !defined(WIN32) */
/** /**
* @macro * @macro
@@ -611,7 +617,12 @@ typedef enum {
* The ALTSVC frame, which is defined in `RFC 7383 * The ALTSVC frame, which is defined in `RFC 7383
* <https://tools.ietf.org/html/rfc7838#section-4>`_. * <https://tools.ietf.org/html/rfc7838#section-4>`_.
*/ */
NGHTTP2_ALTSVC = 0x0a NGHTTP2_ALTSVC = 0x0a,
/**
* The ORIGIN frame, which is defined by `RFC 8336
* <https://tools.ietf.org/html/rfc8336>`_.
*/
NGHTTP2_ORIGIN = 0x0c
} nghttp2_frame_type; } nghttp2_frame_type;
/** /**
@@ -675,7 +686,12 @@ typedef enum {
/** /**
* SETTINGS_MAX_HEADER_LIST_SIZE * SETTINGS_MAX_HEADER_LIST_SIZE
*/ */
NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 0x06 NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 0x06,
/**
* SETTINGS_ENABLE_CONNECT_PROTOCOL
* (`RFC 8441 <https://tools.ietf.org/html/rfc8441>`_)
*/
NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08
} nghttp2_settings_id; } nghttp2_settings_id;
/* Note: If we add SETTINGS, update the capacity of /* Note: If we add SETTINGS, update the capacity of
NGHTTP2_INBOUND_NUM_IV as well */ NGHTTP2_INBOUND_NUM_IV as well */
@@ -2473,15 +2489,15 @@ nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val);
* *
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of * This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
* remote endpoint as if it is received in SETTINGS frame. Without * remote endpoint as if it is received in SETTINGS frame. Without
* specifying this option, before the local endpoint receives * specifying this option, the maximum number of outgoing concurrent
* SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote * streams is initially limited to 100 to avoid issues when the local
* endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may * endpoint submits lots of requests before receiving initial SETTINGS
* cause problem if local endpoint submits lots of requests initially * frame from the remote endpoint, since sending them at once to the
* and sending them at once to the remote peer may lead to the * remote endpoint could lead to rejection of some of the requests.
* rejection of some requests. Specifying this option to the sensible * This value will be overwritten when the local endpoint receives
* value, say 100, may avoid this kind of issue. This value will be * initial SETTINGS frame from the remote endpoint, either to the
* overwritten if the local endpoint receives * value advertised in SETTINGS_MAX_CONCURRENT_STREAMS or to the
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint. * default value (unlimited) if none was advertised.
*/ */
NGHTTP2_EXTERN void NGHTTP2_EXTERN void
nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
@@ -3081,6 +3097,16 @@ NGHTTP2_EXTERN int
nghttp2_session_set_stream_user_data(nghttp2_session *session, nghttp2_session_set_stream_user_data(nghttp2_session *session,
int32_t stream_id, void *stream_user_data); int32_t stream_id, void *stream_user_data);
/**
* @function
*
* Sets |user_data| to |session|, overwriting the existing user data
* specified in `nghttp2_session_client_new()`, or
* `nghttp2_session_server_new()`.
*/
NGHTTP2_EXTERN void nghttp2_session_set_user_data(nghttp2_session *session,
void *user_data);
/** /**
* @function * @function
* *
@@ -3787,10 +3813,13 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* .. warning:: * .. warning::
* *
* This function returns assigned stream ID if it succeeds. But * This function returns assigned stream ID if it succeeds. But
* that stream is not opened yet. The application must not submit * that stream is not created yet. The application must not submit
* frame to that stream ID before * frame to that stream ID before
* :type:`nghttp2_before_frame_send_callback` is called for this * :type:`nghttp2_before_frame_send_callback` is called for this
* frame. * frame. This means `nghttp2_session_get_stream_user_data()` does
* not work before the callback. But
* `nghttp2_session_set_stream_user_data()` handles this situation
* specially, and it can set data to a stream during this period.
* *
*/ */
NGHTTP2_EXTERN int32_t nghttp2_submit_request( NGHTTP2_EXTERN int32_t nghttp2_submit_request(
@@ -4506,8 +4535,7 @@ typedef struct {
* Submits ALTSVC frame. * Submits ALTSVC frame.
* *
* ALTSVC frame is a non-critical extension to HTTP/2, and defined in * ALTSVC frame is a non-critical extension to HTTP/2, and defined in
* is defined in `RFC 7383 * `RFC 7383 <https://tools.ietf.org/html/rfc7838#section-4>`_.
* <https://tools.ietf.org/html/rfc7838#section-4>`_.
* *
* The |flags| is currently ignored and should be * The |flags| is currently ignored and should be
* :enum:`NGHTTP2_FLAG_NONE`. * :enum:`NGHTTP2_FLAG_NONE`.
@@ -4541,6 +4569,81 @@ NGHTTP2_EXTERN int nghttp2_submit_altsvc(nghttp2_session *session,
const uint8_t *field_value, const uint8_t *field_value,
size_t field_value_len); size_t field_value_len);
/**
* @struct
*
* The single entry of an origin.
*/
typedef struct {
/**
* The pointer to origin. No validation is made against this field
* by the library. This is not necessarily NULL-terminated.
*/
uint8_t *origin;
/**
* The length of the |origin|.
*/
size_t origin_len;
} nghttp2_origin_entry;
/**
* @struct
*
* The payload of ORIGIN frame. ORIGIN frame is a non-critical
* extension to HTTP/2 and defined by `RFC 8336
* <https://tools.ietf.org/html/rfc8336>`_.
*
* If this frame is received, and
* `nghttp2_option_set_user_recv_extension_type()` is not set, and
* `nghttp2_option_set_builtin_recv_extension_type()` is set for
* :enum:`NGHTTP2_ORIGIN`, ``nghttp2_extension.payload`` will point to
* this struct.
*
* It has the following members:
*/
typedef struct {
/**
* The number of origins contained in |ov|.
*/
size_t nov;
/**
* The pointer to the array of origins contained in ORIGIN frame.
*/
nghttp2_origin_entry *ov;
} nghttp2_ext_origin;
/**
* @function
*
* Submits ORIGIN frame.
*
* ORIGIN frame is a non-critical extension to HTTP/2 and defined by
* `RFC 8336 <https://tools.ietf.org/html/rfc8336>`_.
*
* The |flags| is currently ignored and should be
* :enum:`NGHTTP2_FLAG_NONE`.
*
* The |ov| points to the array of origins. The |nov| specifies the
* number of origins included in |ov|. This function creates copies
* of all elements in |ov|.
*
* The ORIGIN frame is only usable by a server. If this function is
* invoked with client side session, this function returns
* :enum:`NGHTTP2_ERR_INVALID_STATE`.
*
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory
* :enum:`NGHTTP2_ERR_INVALID_STATE`
* The function is called from client side session.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* There are too many origins, or an origin is too large to fit
* into a default frame payload.
*/
NGHTTP2_EXTERN int nghttp2_submit_origin(nghttp2_session *session,
uint8_t flags,
const nghttp2_origin_entry *ov,
size_t nov);
/** /**
* @function * @function
* *

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_BUF_H #define NGHTTP2_BUF_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_CALLBACKS_H #define NGHTTP2_CALLBACKS_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,18 +26,18 @@
#define NGHTTP2_DEBUG_H #define NGHTTP2_DEBUG_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#ifdef DEBUGBUILD #ifdef DEBUGBUILD
#define DEBUGF(...) nghttp2_debug_vprintf(__VA_ARGS__) # define DEBUGF(...) nghttp2_debug_vprintf(__VA_ARGS__)
void nghttp2_debug_vprintf(const char *format, ...); void nghttp2_debug_vprintf(const char *format, ...);
#else #else
#define DEBUGF(...) \ # define DEBUGF(...) \
do { \ do { \
} while (0) } while (0)
#endif #endif
#endif /* NGHTTP2_DEBUG_H */ #endif /* NGHTTP2_DEBUG_H */

View File

@@ -215,11 +215,44 @@ void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem) {
nghttp2_ext_altsvc *altsvc; nghttp2_ext_altsvc *altsvc;
altsvc = frame->payload; altsvc = frame->payload;
if (altsvc == NULL) {
return;
}
/* We use the same buffer for altsvc->origin and /* We use the same buffer for altsvc->origin and
altsvc->field_value. */ altsvc->field_value. */
nghttp2_mem_free(mem, altsvc->origin); nghttp2_mem_free(mem, altsvc->origin);
} }
void nghttp2_frame_origin_init(nghttp2_extension *frame,
nghttp2_origin_entry *ov, size_t nov) {
nghttp2_ext_origin *origin;
size_t payloadlen = 0;
size_t i;
for (i = 0; i < nov; ++i) {
payloadlen += 2 + ov[i].origin_len;
}
nghttp2_frame_hd_init(&frame->hd, payloadlen, NGHTTP2_ORIGIN,
NGHTTP2_FLAG_NONE, 0);
origin = frame->payload;
origin->ov = ov;
origin->nov = nov;
}
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
nghttp2_ext_origin *origin;
origin = frame->payload;
if (origin == NULL) {
return;
}
/* We use the same buffer for all resources pointed by the field of
origin directly or indirectly. */
nghttp2_mem_free(mem, origin->ov);
}
size_t nghttp2_frame_priority_len(uint8_t flags) { size_t nghttp2_frame_priority_len(uint8_t flags) {
if (flags & NGHTTP2_FLAG_PRIORITY) { if (flags & NGHTTP2_FLAG_PRIORITY) {
return NGHTTP2_PRIORITY_SPECLEN; return NGHTTP2_PRIORITY_SPECLEN;
@@ -743,6 +776,106 @@ int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
return 0; return 0;
} }
int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *frame) {
nghttp2_buf *buf;
nghttp2_ext_origin *origin;
nghttp2_origin_entry *orig;
size_t i;
origin = frame->payload;
buf = &bufs->head->buf;
if (nghttp2_buf_avail(buf) < frame->hd.length) {
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
}
buf->pos -= NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
for (i = 0; i < origin->nov; ++i) {
orig = &origin->ov[i];
nghttp2_put_uint16be(buf->last, (uint16_t)orig->origin_len);
buf->last += 2;
buf->last = nghttp2_cpymem(buf->last, orig->origin, orig->origin_len);
}
assert(nghttp2_buf_len(buf) == NGHTTP2_FRAME_HDLEN + frame->hd.length);
return 0;
}
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
const uint8_t *payload,
size_t payloadlen, nghttp2_mem *mem) {
nghttp2_ext_origin *origin;
const uint8_t *p, *end;
uint8_t *dst;
size_t originlen;
nghttp2_origin_entry *ov;
size_t nov = 0;
size_t len = 0;
origin = frame->payload;
p = payload;
end = p + payloadlen;
for (; p != end;) {
if (end - p < 2) {
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
}
originlen = nghttp2_get_uint16(p);
p += 2;
if (originlen == 0) {
continue;
}
if (originlen > (size_t)(end - p)) {
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
}
p += originlen;
/* 1 for terminal NULL */
len += originlen + 1;
++nov;
}
if (nov == 0) {
origin->ov = NULL;
origin->nov = 0;
return 0;
}
len += nov * sizeof(nghttp2_origin_entry);
ov = nghttp2_mem_malloc(mem, len);
if (ov == NULL) {
return NGHTTP2_ERR_NOMEM;
}
origin->ov = ov;
origin->nov = nov;
dst = (uint8_t *)ov + nov * sizeof(nghttp2_origin_entry);
p = payload;
for (; p != end;) {
originlen = nghttp2_get_uint16(p);
p += 2;
if (originlen == 0) {
continue;
}
ov->origin = dst;
ov->origin_len = originlen;
dst = nghttp2_cpymem(dst, p, originlen);
*dst++ = '\0';
p += originlen;
++ov;
}
return 0;
}
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv, nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
size_t niv, nghttp2_mem *mem) { size_t niv, nghttp2_mem *mem) {
nghttp2_settings_entry *iv_copy; nghttp2_settings_entry *iv_copy;
@@ -917,6 +1050,11 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
break; break;
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
break; break;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
if (iv[i].value != 0 && iv[i].value != 1) {
return 0;
}
break;
} }
} }
return 1; return 1;

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_FRAME_H #define NGHTTP2_FRAME_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
@@ -72,6 +72,7 @@
/* Union of extension frame payload */ /* Union of extension frame payload */
typedef union { typedef union {
nghttp2_ext_altsvc altsvc; nghttp2_ext_altsvc altsvc;
nghttp2_ext_origin origin;
} nghttp2_ext_frame_payload; } nghttp2_ext_frame_payload;
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd); void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
@@ -392,6 +393,36 @@ int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
const uint8_t *payload, const uint8_t *payload,
size_t payloadlen, nghttp2_mem *mem); size_t payloadlen, nghttp2_mem *mem);
/*
* Packs ORIGIN frame |frame| in wire frame format and store it in
* |bufs|.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The length of the frame is too large.
*/
int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *ext);
/*
* Unpacks ORIGIN wire format into |frame|. The |payload| of length
* |payloadlen| contains the frame payload.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The payload is too small.
*/
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
const uint8_t *payload,
size_t payloadlen, nghttp2_mem *mem);
/* /*
* Initializes HEADERS frame |frame| with given values. |frame| takes * Initializes HEADERS frame |frame| with given values. |frame| takes
* ownership of |nva|, so caller must not free it. If |stream_id| is * ownership of |nva|, so caller must not free it. If |stream_id| is
@@ -489,6 +520,24 @@ void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
*/ */
void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem); void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem);
/*
* Initializes ORIGIN frame |frame| with given values. This function
* assumes that frame->payload points to nghttp2_ext_origin object.
* Also |ov| and the memory pointed by the field of its elements are
* allocated in single buffer, starting with |ov|. On success, this
* function takes ownership of |ov|, so caller must not free it.
*/
void nghttp2_frame_origin_init(nghttp2_extension *frame,
nghttp2_origin_entry *ov, size_t nov);
/*
* Frees up resources under |frame|. This function does not free
* nghttp2_ext_origin object pointed by frame->payload. This function
* only frees nghttp2_ext_origin.ov. Therefore, other fields must be
* allocated in the same buffer with ov.
*/
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
/* /*
* Returns the number of padding bytes after payload. The total * Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does * padding length is given in the |padlen|. The returned value does

View File

@@ -45,7 +45,7 @@
/* 3rd parameter is nghttp2_token value for header field name. We use /* 3rd parameter is nghttp2_token value for header field name. We use
first enum value if same header names are repeated (e.g., first enum value if same header names are repeated (e.g.,
:status). */ :status). */
static nghttp2_hd_static_entry static_table[] = { static const nghttp2_hd_static_entry static_table[] = {
MAKE_STATIC_ENT(":authority", "", 0, 3153725150u), MAKE_STATIC_ENT(":authority", "", 0, 3153725150u),
MAKE_STATIC_ENT(":method", "GET", 1, 695666056u), MAKE_STATIC_ENT(":method", "GET", 1, 695666056u),
MAKE_STATIC_ENT(":method", "POST", 1, 695666056u), MAKE_STATIC_ENT(":method", "POST", 1, 695666056u),
@@ -271,6 +271,15 @@ static int32_t lookup_token(const uint8_t *name, size_t namelen) {
break; break;
} }
break; break;
case 9:
switch (name[8]) {
case 'l':
if (memeq(":protoco", name, 8)) {
return NGHTTP2_TOKEN__PROTOCOL;
}
break;
}
break;
case 10: case 10:
switch (name[9]) { switch (name[9]) {
case 'e': case 'e':
@@ -1159,7 +1168,7 @@ static search_result search_static_table(const nghttp2_nv *nv, int32_t token,
int name_only) { int name_only) {
search_result res = {token, 0}; search_result res = {token, 0};
int i; int i;
nghttp2_hd_static_entry *ent; const nghttp2_hd_static_entry *ent;
if (name_only) { if (name_only) {
return res; return res;
@@ -1184,7 +1193,7 @@ static search_result search_hd_table(nghttp2_hd_context *context,
int indexing_mode, nghttp2_hd_map *map, int indexing_mode, nghttp2_hd_map *map,
uint32_t hash) { uint32_t hash) {
search_result res = {-1, 0}; search_result res = {-1, 0};
nghttp2_hd_entry *ent; const nghttp2_hd_entry *ent;
int exact_match; int exact_match;
int name_only = indexing_mode == NGHTTP2_HD_NEVER_INDEXING; int name_only = indexing_mode == NGHTTP2_HD_NEVER_INDEXING;
@@ -1289,8 +1298,9 @@ nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) {
return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH) return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH)
->nv; ->nv;
} else { } else {
nghttp2_hd_static_entry *ent = &static_table[idx]; const nghttp2_hd_static_entry *ent = &static_table[idx];
nghttp2_hd_nv nv = {&ent->name, &ent->value, ent->token, nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name,
(nghttp2_rcbuf *)&ent->value, ent->token,
NGHTTP2_NV_FLAG_NONE}; NGHTTP2_NV_FLAG_NONE};
return nv; return nv;
} }

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_HD_H #define NGHTTP2_HD_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
@@ -111,6 +111,7 @@ typedef enum {
NGHTTP2_TOKEN_KEEP_ALIVE, NGHTTP2_TOKEN_KEEP_ALIVE,
NGHTTP2_TOKEN_PROXY_CONNECTION, NGHTTP2_TOKEN_PROXY_CONNECTION,
NGHTTP2_TOKEN_UPGRADE, NGHTTP2_TOKEN_UPGRADE,
NGHTTP2_TOKEN__PROTOCOL,
} nghttp2_token; } nghttp2_token;
struct nghttp2_hd_entry; struct nghttp2_hd_entry;

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_HD_HUFFMAN_H #define NGHTTP2_HD_HUFFMAN_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -340,7 +340,7 @@ const char *nghttp2_strerror(int error_code) {
} }
/* Generated by gennmchartbl.py */ /* Generated by gennmchartbl.py */
static int VALID_HD_NAME_CHARS[] = { static const int VALID_HD_NAME_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
@@ -428,7 +428,7 @@ int nghttp2_check_header_name(const uint8_t *name, size_t len) {
} }
/* Generated by genvchartbl.py */ /* Generated by genvchartbl.py */
static int VALID_HD_VALUE_CHARS[] = { static const int VALID_HD_VALUE_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */, 0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_HELPER_H #define NGHTTP2_HELPER_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <string.h> #include <string.h>

View File

@@ -113,7 +113,7 @@ static int check_path(nghttp2_stream *stream) {
} }
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
int trailer) { int trailer, int connect_protocol) {
if (nv->name->base[0] == ':') { if (nv->name->base[0] == ':') {
if (trailer || if (trailer ||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) { (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
@@ -146,10 +146,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
return NGHTTP2_ERR_HTTP_HEADER; return NGHTTP2_ERR_HTTP_HEADER;
} }
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT; stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
if (stream->http_flags &
(NGHTTP2_HTTP_FLAG__PATH | NGHTTP2_HTTP_FLAG__SCHEME)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
} }
break; break;
case 'S': case 'S':
@@ -162,9 +158,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
} }
break; break;
case NGHTTP2_TOKEN__PATH: case NGHTTP2_TOKEN__PATH:
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) { if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
return NGHTTP2_ERR_HTTP_HEADER; return NGHTTP2_ERR_HTTP_HEADER;
} }
@@ -175,9 +168,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
} }
break; break;
case NGHTTP2_TOKEN__SCHEME: case NGHTTP2_TOKEN__SCHEME:
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) { if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
return NGHTTP2_ERR_HTTP_HEADER; return NGHTTP2_ERR_HTTP_HEADER;
} }
@@ -186,6 +176,15 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP; stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP;
} }
break; break;
case NGHTTP2_TOKEN__PROTOCOL:
if (!connect_protocol) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PROTOCOL)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
break;
case NGHTTP2_TOKEN_HOST: case NGHTTP2_TOKEN_HOST:
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) { if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
return NGHTTP2_ERR_HTTP_HEADER; return NGHTTP2_ERR_HTTP_HEADER;
@@ -244,7 +243,7 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
return NGHTTP2_ERR_HTTP_HEADER; return NGHTTP2_ERR_HTTP_HEADER;
} }
stream->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len); stream->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len);
if (stream->status_code == -1) { if (stream->status_code == -1 || stream->status_code == 101) {
return NGHTTP2_ERR_HTTP_HEADER; return NGHTTP2_ERR_HTTP_HEADER;
} }
break; break;
@@ -265,7 +264,7 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
return NGHTTP2_ERR_REMOVE_HTTP_HEADER; return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
} }
if (stream->status_code / 100 == 1 || if (stream->status_code / 100 == 1 ||
(stream->status_code == 200 && (stream->status_code / 100 == 2 &&
(stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT))) { (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT))) {
return NGHTTP2_ERR_HTTP_HEADER; return NGHTTP2_ERR_HTTP_HEADER;
} }
@@ -458,7 +457,9 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
} }
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) { if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
return http_request_on_header(stream, nv, trailer); return http_request_on_header(stream, nv, trailer,
session->server &&
session->pending_enable_connect_protocol);
} }
return http_response_on_header(stream, nv, trailer); return http_response_on_header(stream, nv, trailer);
@@ -466,8 +467,11 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
int nghttp2_http_on_request_headers(nghttp2_stream *stream, int nghttp2_http_on_request_headers(nghttp2_stream *stream,
nghttp2_frame *frame) { nghttp2_frame *frame) {
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) { if (!(stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
if ((stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) { (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) {
if ((stream->http_flags &
(NGHTTP2_HTTP_FLAG__SCHEME | NGHTTP2_HTTP_FLAG__PATH)) ||
(stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) {
return -1; return -1;
} }
stream->content_length = -1; stream->content_length = -1;
@@ -478,6 +482,11 @@ int nghttp2_http_on_request_headers(nghttp2_stream *stream,
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) { (NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
return -1; return -1;
} }
if ((stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) == 0 ||
(stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0)) {
return -1;
}
if (!check_path(stream)) { if (!check_path(stream)) {
return -1; return -1;
} }

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_HTTP_H #define NGHTTP2_HTTP_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_INT_H #define NGHTTP2_INT_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_MAP_H #define NGHTTP2_MAP_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_MEM_H #define NGHTTP2_MEM_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,15 +26,15 @@
#define NGHTTP2_NET_H #define NGHTTP2_NET_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#ifdef HAVE_ARPA_INET_H #ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h> # include <arpa/inet.h>
#endif /* HAVE_ARPA_INET_H */ #endif /* HAVE_ARPA_INET_H */
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> # include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */ #endif /* HAVE_NETINET_IN_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
@@ -44,11 +44,11 @@
define inline functions for those function so that we don't have define inline functions for those function so that we don't have
dependeny on that lib. */ dependeny on that lib. */
#ifdef _MSC_VER # ifdef _MSC_VER
#define STIN static __inline # define STIN static __inline
#else # else
#define STIN static inline # define STIN static inline
#endif # endif
STIN uint32_t htonl(uint32_t hostlong) { STIN uint32_t htonl(uint32_t hostlong) {
uint32_t res; uint32_t res;

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_NPN_H #define NGHTTP2_NPN_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -86,6 +86,10 @@ void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES; option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ALTSVC; option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ALTSVC;
return; return;
case NGHTTP2_ORIGIN:
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
return;
default: default:
return; return;
} }

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_OPTION_H #define NGHTTP2_OPTION_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -86,6 +86,9 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
case NGHTTP2_ALTSVC: case NGHTTP2_ALTSVC:
nghttp2_frame_altsvc_free(&frame->ext, mem); nghttp2_frame_altsvc_free(&frame->ext, mem);
break; break;
case NGHTTP2_ORIGIN:
nghttp2_frame_origin_free(&frame->ext, mem);
break;
default: default:
assert(0); assert(0);
break; break;

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_OUTBOUND_ITEM_H #define NGHTTP2_OUTBOUND_ITEM_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_PQ_H #define NGHTTP2_PQ_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_PRIORITY_SPEC_H #define NGHTTP2_PRIORITY_SPEC_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_QUEUE_H #define NGHTTP2_QUEUE_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" # include "config.h"
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_RCBUF_H #define NGHTTP2_RCBUF_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -219,6 +219,10 @@ static int session_terminate_session(nghttp2_session *session,
return 0; return 0;
} }
/* Ignore all incoming frames because we are going to tear down the
session. */
session->iframe.state = NGHTTP2_IB_IGN_ALL;
if (reason == NULL) { if (reason == NULL) {
debug_data = NULL; debug_data = NULL;
debug_datalen = 0; debug_datalen = 0;
@@ -344,6 +348,12 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
} }
nghttp2_frame_altsvc_free(&iframe->frame.ext, mem); nghttp2_frame_altsvc_free(&iframe->frame.ext, mem);
break; break;
case NGHTTP2_ORIGIN:
if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ORIGIN) == 0) {
break;
}
nghttp2_frame_origin_free(&iframe->frame.ext, mem);
break;
} }
} }
@@ -1745,6 +1755,13 @@ static int session_predicate_altsvc_send(nghttp2_session *session,
return 0; return 0;
} }
static int session_predicate_origin_send(nghttp2_session *session) {
if (session_is_closing(session)) {
return NGHTTP2_ERR_SESSION_CLOSING;
}
return 0;
}
/* Take into account settings max frame size and both connection-level /* Take into account settings max frame size and both connection-level
flow control here */ flow control here */
static ssize_t static ssize_t
@@ -2276,6 +2293,18 @@ static int session_prep_frame(nghttp2_session *session,
nghttp2_frame_pack_altsvc(&session->aob.framebufs, &frame->ext); nghttp2_frame_pack_altsvc(&session->aob.framebufs, &frame->ext);
return 0;
case NGHTTP2_ORIGIN:
rv = session_predicate_origin_send(session);
if (rv != 0) {
return rv;
}
rv = nghttp2_frame_pack_origin(&session->aob.framebufs, &frame->ext);
if (rv != 0) {
return rv;
}
return 0; return 0;
default: default:
/* Unreachable here */ /* Unreachable here */
@@ -4332,6 +4361,9 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
session->local_settings.max_header_list_size = iv[i].value; session->local_settings.max_header_list_size = iv[i].value;
break; break;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
session->local_settings.enable_connect_protocol = iv[i].value;
break;
} }
} }
@@ -4381,6 +4413,12 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
return session_call_on_frame_received(session, frame); return session_call_on_frame_received(session, frame);
} }
if (!session->remote_settings_received) {
session->remote_settings.max_concurrent_streams =
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
session->remote_settings_received = 1;
}
for (i = 0; i < frame->settings.niv; ++i) { for (i = 0; i < frame->settings.niv; ++i) {
nghttp2_settings_entry *entry = &frame->settings.iv[i]; nghttp2_settings_entry *entry = &frame->settings.iv[i];
@@ -4464,6 +4502,26 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
session->remote_settings.max_header_list_size = entry->value; session->remote_settings.max_header_list_size = entry->value;
break;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
if (entry->value != 0 && entry->value != 1) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_ERR_PROTO,
"SETTINGS: invalid SETTINGS_ENABLE_CONNECT_PROTOCOL");
}
if (!session->server &&
session->remote_settings.enable_connect_protocol &&
entry->value == 0) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_ERR_PROTO,
"SETTINGS: server attempted to disable "
"SETTINGS_ENABLE_CONNECT_PROTOCOL");
}
session->remote_settings.enable_connect_protocol = entry->value;
break; break;
} }
} }
@@ -4817,6 +4875,11 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session,
return session_call_on_frame_received(session, frame); return session_call_on_frame_received(session, frame);
} }
int nghttp2_session_on_origin_received(nghttp2_session *session,
nghttp2_frame *frame) {
return session_call_on_frame_received(session, frame);
}
static int session_process_altsvc_frame(nghttp2_session *session) { static int session_process_altsvc_frame(nghttp2_session *session) {
nghttp2_inbound_frame *iframe = &session->iframe; nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame; nghttp2_frame *frame = &iframe->frame;
@@ -4832,6 +4895,25 @@ static int session_process_altsvc_frame(nghttp2_session *session) {
return nghttp2_session_on_altsvc_received(session, frame); return nghttp2_session_on_altsvc_received(session, frame);
} }
static int session_process_origin_frame(nghttp2_session *session) {
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
nghttp2_mem *mem = &session->mem;
int rv;
rv = nghttp2_frame_unpack_origin_payload(&frame->ext, iframe->lbuf.pos,
nghttp2_buf_len(&iframe->lbuf), mem);
if (rv != 0) {
if (nghttp2_is_fatal(rv)) {
return rv;
}
/* Ignore ORIGIN frame which cannot be parsed. */
return 0;
}
return nghttp2_session_on_origin_received(session, frame);
}
static int session_process_extension_frame(nghttp2_session *session) { static int session_process_extension_frame(nghttp2_session *session) {
int rv; int rv;
nghttp2_inbound_frame *iframe = &session->iframe; nghttp2_inbound_frame *iframe = &session->iframe;
@@ -5191,6 +5273,7 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) {
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
break; break;
default: default:
DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id); DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id);
@@ -5346,9 +5429,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS || if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS ||
(iframe->sbuf.pos[4] & NGHTTP2_FLAG_ACK)) { (iframe->sbuf.pos[4] & NGHTTP2_FLAG_ACK)) {
iframe->state = NGHTTP2_IB_IGN_ALL;
rv = session_call_error_callback( rv = session_call_error_callback(
session, NGHTTP2_ERR_SETTINGS_EXPECTED, session, NGHTTP2_ERR_SETTINGS_EXPECTED,
"Remote peer returned unexpected data while we expected " "Remote peer returned unexpected data while we expected "
@@ -5395,10 +5475,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
DEBUGF("recv: length is too large %zu > %u\n", iframe->frame.hd.length, DEBUGF("recv: length is too large %zu > %u\n", iframe->frame.hd.length,
session->local_settings.max_frame_size); session->local_settings.max_frame_size);
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
rv = nghttp2_session_terminate_session_with_reason( rv = nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_FRAME_SIZE_ERROR, "too large frame size"); session, NGHTTP2_FRAME_SIZE_ERROR, "too large frame size");
@@ -5406,7 +5482,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
break; return (ssize_t)inlen;
} }
switch (iframe->frame.hd.type) { switch (iframe->frame.hd.type) {
@@ -5420,6 +5496,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
busy = 1; busy = 1;
rv = session_on_data_received_fail_fast(session); rv = session_on_data_received_fail_fast(session);
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
if (rv == NGHTTP2_ERR_IGN_PAYLOAD) { if (rv == NGHTTP2_ERR_IGN_PAYLOAD) {
DEBUGF("recv: DATA not allowed stream_id=%d\n", DEBUGF("recv: DATA not allowed stream_id=%d\n",
iframe->frame.hd.stream_id); iframe->frame.hd.stream_id);
@@ -5433,7 +5512,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if (rv < 0) { if (rv < 0) {
iframe->state = NGHTTP2_IB_IGN_DATA;
rv = nghttp2_session_terminate_session_with_reason( rv = nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_PROTOCOL_ERROR, session, NGHTTP2_PROTOCOL_ERROR,
"DATA: insufficient padding space"); "DATA: insufficient padding space");
@@ -5441,7 +5519,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
break; return (ssize_t)inlen;
} }
if (rv == 1) { if (rv == 1) {
@@ -5462,17 +5540,13 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if (rv < 0) { if (rv < 0) {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
rv = nghttp2_session_terminate_session_with_reason( rv = nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_PROTOCOL_ERROR, session, NGHTTP2_PROTOCOL_ERROR,
"HEADERS: insufficient padding space"); "HEADERS: insufficient padding space");
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
break; return (ssize_t)inlen;
} }
if (rv == 1) { if (rv == 1) {
@@ -5514,6 +5588,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
busy = 1; busy = 1;
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
rv = nghttp2_session_add_rst_stream( rv = nghttp2_session_add_rst_stream(
session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR);
@@ -5628,15 +5706,13 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if (rv < 0) { if (rv < 0) {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
rv = nghttp2_session_terminate_session_with_reason( rv = nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_PROTOCOL_ERROR, session, NGHTTP2_PROTOCOL_ERROR,
"PUSH_PROMISE: insufficient padding space"); "PUSH_PROMISE: insufficient padding space");
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
break; return (ssize_t)inlen;
} }
if (rv == 1) { if (rv == 1) {
@@ -5696,11 +5772,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
busy = 1; return (ssize_t)inlen;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break;
default: default:
DEBUGF("recv: extension frame\n"); DEBUGF("recv: extension frame\n");
@@ -5753,6 +5825,42 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_set_mark(iframe, 2); inbound_frame_set_mark(iframe, 2);
break;
case NGHTTP2_ORIGIN:
if (!(session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ORIGIN)) {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break;
}
DEBUGF("recv: ORIGIN\n");
iframe->frame.ext.payload = &iframe->ext_frame_payload.origin;
if (session->server || iframe->frame.hd.stream_id ||
(iframe->frame.hd.flags & 0xf0)) {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break;
}
iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
if (iframe->payloadleft) {
iframe->raw_lbuf = nghttp2_mem_malloc(mem, iframe->payloadleft);
if (iframe->raw_lbuf == NULL) {
return NGHTTP2_ERR_NOMEM;
}
nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf,
iframe->payloadleft);
} else {
busy = 1;
}
iframe->state = NGHTTP2_IB_READ_ORIGIN_PAYLOAD;
break; break;
default: default:
busy = 1; busy = 1;
@@ -5770,6 +5878,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
case NGHTTP2_IB_IGN_PAYLOAD: case NGHTTP2_IB_IGN_PAYLOAD:
case NGHTTP2_IB_FRAME_SIZE_ERROR: case NGHTTP2_IB_FRAME_SIZE_ERROR:
case NGHTTP2_IB_IGN_DATA: case NGHTTP2_IB_IGN_DATA:
case NGHTTP2_IB_IGN_ALL:
break; break;
default: default:
rv = session_call_on_begin_frame(session, &iframe->frame.hd); rv = session_call_on_begin_frame(session, &iframe->frame.hd);
@@ -5800,21 +5909,19 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
case NGHTTP2_HEADERS: case NGHTTP2_HEADERS:
if (iframe->padlen == 0 && if (iframe->padlen == 0 &&
(iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) {
pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags);
padlen = inbound_frame_compute_pad(iframe); padlen = inbound_frame_compute_pad(iframe);
if (padlen < 0) { if (padlen < 0 ||
busy = 1; (size_t)padlen + pri_fieldlen > 1 + iframe->payloadleft) {
rv = nghttp2_session_terminate_session_with_reason( rv = nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: invalid padding"); session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: invalid padding");
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; return (ssize_t)inlen;
break;
} }
iframe->frame.headers.padlen = (size_t)padlen; iframe->frame.headers.padlen = (size_t)padlen;
pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags);
if (pri_fieldlen > 0) { if (pri_fieldlen > 0) {
if (iframe->payloadleft < pri_fieldlen) { if (iframe->payloadleft < pri_fieldlen) {
busy = 1; busy = 1;
@@ -5837,6 +5944,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
busy = 1; busy = 1;
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
rv = nghttp2_session_add_rst_stream( rv = nghttp2_session_add_rst_stream(
session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR);
@@ -5861,6 +5972,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
break; break;
@@ -5870,6 +5985,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
break; break;
@@ -5877,16 +5996,15 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (iframe->padlen == 0 && if (iframe->padlen == 0 &&
(iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) {
padlen = inbound_frame_compute_pad(iframe); padlen = inbound_frame_compute_pad(iframe);
if (padlen < 0) { if (padlen < 0 || (size_t)padlen + 4 /* promised stream id */
busy = 1; > 1 + iframe->payloadleft) {
rv = nghttp2_session_terminate_session_with_reason( rv = nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_PROTOCOL_ERROR, session, NGHTTP2_PROTOCOL_ERROR,
"PUSH_PROMISE: invalid padding"); "PUSH_PROMISE: invalid padding");
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; return (ssize_t)inlen;
break;
} }
iframe->frame.push_promise.padlen = (size_t)padlen; iframe->frame.push_promise.padlen = (size_t)padlen;
@@ -5911,6 +6029,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
busy = 1; busy = 1;
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
rv = nghttp2_session_add_rst_stream( rv = nghttp2_session_add_rst_stream(
session, iframe->frame.push_promise.promised_stream_id, session, iframe->frame.push_promise.promised_stream_id,
@@ -5936,6 +6058,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
break; break;
@@ -5967,6 +6093,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
break; break;
@@ -6028,6 +6158,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
data_readlen = inbound_frame_effective_readlen( data_readlen = inbound_frame_effective_readlen(
iframe, iframe->payloadleft - readlen, readlen); iframe, iframe->payloadleft - readlen, readlen);
if (data_readlen == -1) {
/* everything is padding */
data_readlen = 0;
}
trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen); trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen);
final = (iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) && final = (iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) &&
@@ -6047,6 +6183,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
if (rv == NGHTTP2_ERR_PAUSE) { if (rv == NGHTTP2_ERR_PAUSE) {
in += hd_proclen; in += hd_proclen;
iframe->payloadleft -= hd_proclen; iframe->payloadleft -= hd_proclen;
@@ -6156,11 +6296,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
busy = 1; assert(iframe->state == NGHTTP2_IB_IGN_ALL);
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; return (ssize_t)inlen;
break;
case NGHTTP2_IB_READ_SETTINGS: case NGHTTP2_IB_READ_SETTINGS:
DEBUGF("recv: [IB_READ_SETTINGS]\n"); DEBUGF("recv: [IB_READ_SETTINGS]\n");
@@ -6189,6 +6327,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
break; break;
@@ -6219,6 +6361,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
break; break;
@@ -6258,11 +6404,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
busy = 1; return (ssize_t)inlen;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break;
} }
/* CONTINUATION won't bear NGHTTP2_PADDED flag */ /* CONTINUATION won't bear NGHTTP2_PADDED flag */
@@ -6306,6 +6448,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
/* Pad Length field is consumed immediately */ /* Pad Length field is consumed immediately */
rv = rv =
nghttp2_session_consume(session, iframe->frame.hd.stream_id, readlen); nghttp2_session_consume(session, iframe->frame.hd.stream_id, readlen);
@@ -6314,6 +6460,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id); stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
if (stream) { if (stream) {
rv = session_update_recv_stream_window_size( rv = session_update_recv_stream_window_size(
@@ -6334,8 +6484,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
iframe->state = NGHTTP2_IB_IGN_DATA; return (ssize_t)inlen;
break;
} }
iframe->frame.data.padlen = (size_t)padlen; iframe->frame.data.padlen = (size_t)padlen;
@@ -6369,6 +6518,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
rv = session_update_recv_stream_window_size( rv = session_update_recv_stream_window_size(
session, stream, readlen, session, stream, readlen,
iframe->payloadleft || iframe->payloadleft ||
@@ -6395,6 +6548,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
} }
DEBUGF("recv: data_readlen=%zd\n", data_readlen); DEBUGF("recv: data_readlen=%zd\n", data_readlen);
@@ -6410,6 +6567,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_DATA) {
return (ssize_t)inlen;
}
} }
rv = nghttp2_session_add_rst_stream( rv = nghttp2_session_add_rst_stream(
@@ -6467,6 +6628,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
/* Ignored DATA is considered as "consumed" immediately. */ /* Ignored DATA is considered as "consumed" immediately. */
@@ -6475,6 +6640,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
} }
} }
@@ -6529,7 +6698,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
DEBUGF("recv: [IB_READ_ALTSVC_PAYLOAD]\n"); DEBUGF("recv: [IB_READ_ALTSVC_PAYLOAD]\n");
readlen = inbound_frame_payload_readlen(iframe, in, last); readlen = inbound_frame_payload_readlen(iframe, in, last);
if (readlen > 0) { if (readlen > 0) {
iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen); iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen);
@@ -6547,11 +6715,44 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
rv = session_process_altsvc_frame(session); rv = session_process_altsvc_frame(session);
if (nghttp2_is_fatal(rv)) {
return rv;
}
session_inbound_frame_reset(session);
break;
case NGHTTP2_IB_READ_ORIGIN_PAYLOAD:
DEBUGF("recv: [IB_READ_ORIGIN_PAYLOAD]\n");
readlen = inbound_frame_payload_readlen(iframe, in, last);
if (readlen > 0) {
iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen);
iframe->payloadleft -= readlen;
in += readlen;
}
DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen,
iframe->payloadleft);
if (iframe->payloadleft) {
assert(nghttp2_buf_avail(&iframe->lbuf) > 0);
break;
}
rv = session_process_origin_frame(session);
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen;
}
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
break; break;
@@ -6875,6 +7076,13 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
} }
} }
for (i = niv; i > 0; --i) {
if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL) {
session->pending_enable_connect_protocol = (uint8_t)iv[i - 1].value;
break;
}
}
return 0; return 0;
} }
@@ -7031,12 +7239,42 @@ int nghttp2_session_set_stream_user_data(nghttp2_session *session,
int32_t stream_id, int32_t stream_id,
void *stream_user_data) { void *stream_user_data) {
nghttp2_stream *stream; nghttp2_stream *stream;
nghttp2_frame *frame;
nghttp2_outbound_item *item;
stream = nghttp2_session_get_stream(session, stream_id); stream = nghttp2_session_get_stream(session, stream_id);
if (!stream) { if (stream) {
stream->stream_user_data = stream_user_data;
return 0;
}
if (session->server || !nghttp2_session_is_my_stream_id(session, stream_id) ||
!nghttp2_outbound_queue_top(&session->ob_syn)) {
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
stream->stream_user_data = stream_user_data;
return 0; frame = &nghttp2_outbound_queue_top(&session->ob_syn)->frame;
assert(frame->hd.type == NGHTTP2_HEADERS);
if (frame->hd.stream_id > stream_id ||
(uint32_t)stream_id >= session->next_stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
for (item = session->ob_syn.head; item; item = item->qnext) {
if (item->frame.hd.stream_id < stream_id) {
continue;
}
if (item->frame.hd.stream_id > stream_id) {
break;
}
item->aux_data.headers.stream_user_data = stream_user_data;
return 0;
}
return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) { int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) {
@@ -7153,6 +7391,8 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
return session->remote_settings.max_frame_size; return session->remote_settings.max_frame_size;
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
return session->remote_settings.max_header_list_size; return session->remote_settings.max_header_list_size;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
return session->remote_settings.enable_connect_protocol;
} }
assert(0); assert(0);
@@ -7174,6 +7414,8 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
return session->local_settings.max_frame_size; return session->local_settings.max_frame_size;
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
return session->local_settings.max_header_list_size; return session->local_settings.max_header_list_size;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
return session->local_settings.enable_connect_protocol;
} }
assert(0); assert(0);
@@ -7521,3 +7763,7 @@ size_t
nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) { nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) {
return nghttp2_hd_deflate_get_dynamic_table_size(&session->hd_deflater); return nghttp2_hd_deflate_get_dynamic_table_size(&session->hd_deflater);
} }
void nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) {
session->user_data = user_data;
}

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_SESSION_H #define NGHTTP2_SESSION_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
@@ -61,7 +61,8 @@ typedef enum {
*/ */
typedef enum { typedef enum {
NGHTTP2_TYPEMASK_NONE = 0, NGHTTP2_TYPEMASK_NONE = 0,
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0 NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
NGHTTP2_TYPEMASK_ORIGIN = 1 << 1
} nghttp2_typemask; } nghttp2_typemask;
typedef enum { typedef enum {
@@ -121,6 +122,7 @@ typedef enum {
NGHTTP2_IB_IGN_DATA, NGHTTP2_IB_IGN_DATA,
NGHTTP2_IB_IGN_ALL, NGHTTP2_IB_IGN_ALL,
NGHTTP2_IB_READ_ALTSVC_PAYLOAD, NGHTTP2_IB_READ_ALTSVC_PAYLOAD,
NGHTTP2_IB_READ_ORIGIN_PAYLOAD,
NGHTTP2_IB_READ_EXTENSION_PAYLOAD NGHTTP2_IB_READ_EXTENSION_PAYLOAD
} nghttp2_inbound_state; } nghttp2_inbound_state;
@@ -162,6 +164,7 @@ typedef struct {
uint32_t initial_window_size; uint32_t initial_window_size;
uint32_t max_frame_size; uint32_t max_frame_size;
uint32_t max_header_list_size; uint32_t max_header_list_size;
uint32_t enable_connect_protocol;
} nghttp2_settings_storage; } nghttp2_settings_storage;
typedef enum { typedef enum {
@@ -301,8 +304,10 @@ struct nghttp2_session {
increased/decreased by submitting WINDOW_UPDATE. See increased/decreased by submitting WINDOW_UPDATE. See
nghttp2_submit_window_update(). */ nghttp2_submit_window_update(). */
int32_t local_window_size; int32_t local_window_size;
/* Settings value received from the remote endpoint. We just use ID /* This flag is used to indicate that the local endpoint received initial
as index. The index = 0 is unused. */ SETTINGS frame from the remote endpoint. */
uint8_t remote_settings_received;
/* Settings value received from the remote endpoint. */
nghttp2_settings_storage remote_settings; nghttp2_settings_storage remote_settings;
/* Settings value of the local endpoint. */ /* Settings value of the local endpoint. */
nghttp2_settings_storage local_settings; nghttp2_settings_storage local_settings;
@@ -317,6 +322,9 @@ struct nghttp2_session {
/* Unacked local ENABLE_PUSH value. We use this to refuse /* Unacked local ENABLE_PUSH value. We use this to refuse
PUSH_PROMISE before SETTINGS ACK is received. */ PUSH_PROMISE before SETTINGS ACK is received. */
uint8_t pending_enable_push; uint8_t pending_enable_push;
/* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to
accept :protocol header field before SETTINGS_ACK is received. */
uint8_t pending_enable_connect_protocol;
/* Nonzero if the session is server side. */ /* Nonzero if the session is server side. */
uint8_t server; uint8_t server;
/* Flags indicating GOAWAY is sent and/or received. The flags are /* Flags indicating GOAWAY is sent and/or received. The flags are
@@ -698,7 +706,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE * NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed. * The callback function failed.
* NGHTTP2_ERR_FLOODED * NGHTTP2_ERR_FLOODED
* There are too many items in outbound queue, and this is most * There are too many items in outbound queue, and this is most
* likely caused by misbehaviour of peer. * likely caused by misbehaviour of peer.
@@ -716,7 +724,7 @@ int nghttp2_session_on_ping_received(nghttp2_session *session,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE * NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed. * The callback function failed.
*/ */
int nghttp2_session_on_goaway_received(nghttp2_session *session, int nghttp2_session_on_goaway_received(nghttp2_session *session,
nghttp2_frame *frame); nghttp2_frame *frame);
@@ -731,7 +739,7 @@ int nghttp2_session_on_goaway_received(nghttp2_session *session,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE * NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed. * The callback function failed.
*/ */
int nghttp2_session_on_window_update_received(nghttp2_session *session, int nghttp2_session_on_window_update_received(nghttp2_session *session,
nghttp2_frame *frame); nghttp2_frame *frame);
@@ -744,11 +752,24 @@ int nghttp2_session_on_window_update_received(nghttp2_session *session,
* negative error codes: * negative error codes:
* *
* NGHTTP2_ERR_CALLBACK_FAILURE * NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed. * The callback function failed.
*/ */
int nghttp2_session_on_altsvc_received(nghttp2_session *session, int nghttp2_session_on_altsvc_received(nghttp2_session *session,
nghttp2_frame *frame); nghttp2_frame *frame);
/*
* Called when ORIGIN is received, assuming |frame| is properly
* initialized.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
*/
int nghttp2_session_on_origin_received(nghttp2_session *session,
nghttp2_frame *frame);
/* /*
* Called when DATA is received, assuming |frame| is properly * Called when DATA is received, assuming |frame| is properly
* initialized. * initialized.
@@ -759,7 +780,7 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE * NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed. * The callback function failed.
*/ */
int nghttp2_session_on_data_received(nghttp2_session *session, int nghttp2_session_on_data_received(nghttp2_session *session,
nghttp2_frame *frame); nghttp2_frame *frame);

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_STREAM_H #define NGHTTP2_STREAM_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
@@ -130,7 +130,8 @@ typedef enum {
/* "http" or "https" scheme */ /* "http" or "https" scheme */
NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13, NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13,
/* set if final response is expected */ /* set if final response is expected */
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14 NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15,
} nghttp2_http_flag; } nghttp2_http_flag;
struct nghttp2_stream { struct nghttp2_stream {

View File

@@ -571,6 +571,89 @@ fail_item_malloc:
return rv; return rv;
} }
int nghttp2_submit_origin(nghttp2_session *session, uint8_t flags,
const nghttp2_origin_entry *ov, size_t nov) {
nghttp2_mem *mem;
uint8_t *p;
nghttp2_outbound_item *item;
nghttp2_frame *frame;
nghttp2_ext_origin *origin;
nghttp2_origin_entry *ov_copy;
size_t len = 0;
size_t i;
int rv;
(void)flags;
mem = &session->mem;
if (!session->server) {
return NGHTTP2_ERR_INVALID_STATE;
}
if (nov) {
for (i = 0; i < nov; ++i) {
len += ov[i].origin_len;
}
if (2 * nov + len > NGHTTP2_MAX_PAYLOADLEN) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
/* The last nov is added for terminal NULL character. */
ov_copy =
nghttp2_mem_malloc(mem, nov * sizeof(nghttp2_origin_entry) + len + nov);
if (ov_copy == NULL) {
return NGHTTP2_ERR_NOMEM;
}
p = (uint8_t *)ov_copy + nov * sizeof(nghttp2_origin_entry);
for (i = 0; i < nov; ++i) {
ov_copy[i].origin = p;
ov_copy[i].origin_len = ov[i].origin_len;
p = nghttp2_cpymem(p, ov[i].origin, ov[i].origin_len);
*p++ = '\0';
}
assert((size_t)(p - (uint8_t *)ov_copy) ==
nov * sizeof(nghttp2_origin_entry) + len + nov);
} else {
ov_copy = NULL;
}
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
if (item == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto fail_item_malloc;
}
nghttp2_outbound_item_init(item);
item->aux_data.ext.builtin = 1;
origin = &item->ext_frame_payload.origin;
frame = &item->frame;
frame->ext.payload = origin;
nghttp2_frame_origin_init(&frame->ext, ov_copy, nov);
rv = nghttp2_session_add_item(session, item);
if (rv != 0) {
nghttp2_frame_origin_free(&frame->ext, mem);
nghttp2_mem_free(mem, item);
return rv;
}
return 0;
fail_item_malloc:
free(ov_copy);
return rv;
}
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec, static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
const nghttp2_data_provider *data_prd) { const nghttp2_data_provider *data_prd) {
uint8_t flags = NGHTTP2_FLAG_NONE; uint8_t flags = NGHTTP2_FLAG_NONE;

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_SUBMIT_H #define NGHTTP2_SUBMIT_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

View File

@@ -23,7 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

948
m4/ax_cxx_compile_stdcxx.m4 Normal file
View File

@@ -0,0 +1,948 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXX and
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
# or '14' (for the C++14 standard).
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The third argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline support for the specified C++ standard is
# required and that the macro should error out if no mode with that
# support is found. If specified 'optional', then configuration proceeds
# regardless, after defining HAVE_CXX${VERSION} if and only if a
# supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
[$2], [noext], [],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for alternative in ${ax_cxx_compile_alternatives}; do
switch="-std=gnu++${alternative}"
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
fi])
m4_if([$2], [ext], [], [dnl
if test x$ac_success = xno; then
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
if test x$ac_success = xyes; then
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
fi
fi
if test x$ac_success = xno; then
HAVE_CXX$1=0
AC_MSG_NOTICE([No compiler with C++$1 support was found])
else
HAVE_CXX$1=1
AC_DEFINE(HAVE_CXX$1,1,
[define if the compiler supports basic C++$1 syntax])
fi
AC_SUBST(HAVE_CXX$1)
])
dnl Test body for checking C++11 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
)
dnl Test body for checking C++14 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
dnl Tests for new features in C++11
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
// If the compiler admits that it is not ready for C++11, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#else
namespace cxx11
{
namespace test_static_assert
{
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
}
namespace test_final_override
{
struct Base
{
virtual void f() {}
};
struct Derived : public Base
{
virtual void f() override {}
};
}
namespace test_double_right_angle_brackets
{
template < typename T >
struct check {};
typedef check<void> single_type;
typedef check<check<void>> double_type;
typedef check<check<check<void>>> triple_type;
typedef check<check<check<check<void>>>> quadruple_type;
}
namespace test_decltype
{
int
f()
{
int a = 1;
decltype(a) b = 2;
return a + b;
}
}
namespace test_type_deduction
{
template < typename T1, typename T2 >
struct is_same
{
static const bool value = false;
};
template < typename T >
struct is_same<T, T>
{
static const bool value = true;
};
template < typename T1, typename T2 >
auto
add(T1 a1, T2 a2) -> decltype(a1 + a2)
{
return a1 + a2;
}
int
test(const int c, volatile int v)
{
static_assert(is_same<int, decltype(0)>::value == true, "");
static_assert(is_same<int, decltype(c)>::value == false, "");
static_assert(is_same<int, decltype(v)>::value == false, "");
auto ac = c;
auto av = v;
auto sumi = ac + av + 'x';
auto sumf = ac + av + 1.0;
static_assert(is_same<int, decltype(ac)>::value == true, "");
static_assert(is_same<int, decltype(av)>::value == true, "");
static_assert(is_same<int, decltype(sumi)>::value == true, "");
static_assert(is_same<int, decltype(sumf)>::value == false, "");
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
return (sumf > 0.0) ? sumi : add(c, v);
}
}
namespace test_noexcept
{
int f() { return 0; }
int g() noexcept { return 0; }
static_assert(noexcept(f()) == false, "");
static_assert(noexcept(g()) == true, "");
}
namespace test_constexpr
{
template < typename CharT >
unsigned long constexpr
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
{
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
}
template < typename CharT >
unsigned long constexpr
strlen_c(const CharT *const s) noexcept
{
return strlen_c_r(s, 0UL);
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("1") == 1UL, "");
static_assert(strlen_c("example") == 7UL, "");
static_assert(strlen_c("another\0example") == 7UL, "");
}
namespace test_rvalue_references
{
template < int N >
struct answer
{
static constexpr int value = N;
};
answer<1> f(int&) { return answer<1>(); }
answer<2> f(const int&) { return answer<2>(); }
answer<3> f(int&&) { return answer<3>(); }
void
test()
{
int i = 0;
const int c = 0;
static_assert(decltype(f(i))::value == 1, "");
static_assert(decltype(f(c))::value == 2, "");
static_assert(decltype(f(0))::value == 3, "");
}
}
namespace test_uniform_initialization
{
struct test
{
static const int zero {};
static const int one {1};
};
static_assert(test::zero == 0, "");
static_assert(test::one == 1, "");
}
namespace test_lambdas
{
void
test1()
{
auto lambda1 = [](){};
auto lambda2 = lambda1;
lambda1();
lambda2();
}
int
test2()
{
auto a = [](int i, int j){ return i + j; }(1, 2);
auto b = []() -> int { return '0'; }();
auto c = [=](){ return a + b; }();
auto d = [&](){ return c; }();
auto e = [a, &b](int x) mutable {
const auto identity = [](int y){ return y; };
for (auto i = 0; i < a; ++i)
a += b--;
return x + identity(a + b);
}(0);
return a + b + c + d + e;
}
int
test3()
{
const auto nullary = [](){ return 0; };
const auto unary = [](int x){ return x; };
using nullary_t = decltype(nullary);
using unary_t = decltype(unary);
const auto higher1st = [](nullary_t f){ return f(); };
const auto higher2nd = [unary](nullary_t f1){
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
};
return higher1st(nullary) + higher2nd(nullary)(unary);
}
}
namespace test_variadic_templates
{
template <int...>
struct sum;
template <int N0, int... N1toN>
struct sum<N0, N1toN...>
{
static constexpr auto value = N0 + sum<N1toN...>::value;
};
template <>
struct sum<>
{
static constexpr auto value = 0;
};
static_assert(sum<>::value == 0, "");
static_assert(sum<1>::value == 1, "");
static_assert(sum<23>::value == 23, "");
static_assert(sum<1, 2>::value == 3, "");
static_assert(sum<5, 5, 11>::value == 21, "");
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
}
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
// because of this.
namespace test_template_alias_sfinae
{
struct foo {};
template<typename T>
using member = typename T::member_type;
template<typename T>
void func(...) {}
template<typename T>
void func(member<T>*) {}
void test();
void test() { func<foo>(0); }
}
} // namespace cxx11
#endif // __cplusplus >= 201103L
]])
dnl Tests for new features in C++14
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
// If the compiler admits that it is not ready for C++14, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201402L
#error "This is not a C++14 compiler"
#else
namespace cxx14
{
namespace test_polymorphic_lambdas
{
int
test()
{
const auto lambda = [](auto&&... args){
const auto istiny = [](auto x){
return (sizeof(x) == 1UL) ? 1 : 0;
};
const int aretiny[] = { istiny(args)... };
return aretiny[0];
};
return lambda(1, 1L, 1.0f, '1');
}
}
namespace test_binary_literals
{
constexpr auto ivii = 0b0000000000101010;
static_assert(ivii == 42, "wrong value");
}
namespace test_generalized_constexpr
{
template < typename CharT >
constexpr unsigned long
strlen_c(const CharT *const s) noexcept
{
auto length = 0UL;
for (auto p = s; *p; ++p)
++length;
return length;
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("x") == 1UL, "");
static_assert(strlen_c("test") == 4UL, "");
static_assert(strlen_c("another\0test") == 7UL, "");
}
namespace test_lambda_init_capture
{
int
test()
{
auto x = 0;
const auto lambda1 = [a = x](int b){ return a + b; };
const auto lambda2 = [a = lambda1(x)](){ return a; };
return lambda2();
}
}
namespace test_digit_separators
{
constexpr auto ten_million = 100'000'000;
static_assert(ten_million == 100000000, "");
}
namespace test_return_type_deduction
{
auto f(int& x) { return x; }
decltype(auto) g(int& x) { return x; }
template < typename T1, typename T2 >
struct is_same
{
static constexpr auto value = false;
};
template < typename T >
struct is_same<T, T>
{
static constexpr auto value = true;
};
int
test()
{
auto x = 0;
static_assert(is_same<int, decltype(f(x))>::value, "");
static_assert(is_same<int&, decltype(g(x))>::value, "");
return x;
}
}
} // namespace cxx14
#endif // __cplusplus >= 201402L
]])
dnl Tests for new features in C++17
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201703L
#error "This is not a C++17 compiler"
#else
#include <initializer_list>
#include <utility>
#include <type_traits>
namespace cxx17
{
namespace test_constexpr_lambdas
{
constexpr int foo = [](){return 42;}();
}
namespace test::nested_namespace::definitions
{
}
namespace test_fold_expression
{
template<typename... Args>
int multiply(Args... args)
{
return (args * ... * 1);
}
template<typename... Args>
bool all(Args... args)
{
return (args && ...);
}
}
namespace test_extended_static_assert
{
static_assert (true);
}
namespace test_auto_brace_init_list
{
auto foo = {5};
auto bar {5};
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
static_assert(std::is_same<int, decltype(bar)>::value);
}
namespace test_typename_in_template_template_parameter
{
template<template<typename> typename X> struct D;
}
namespace test_fallthrough_nodiscard_maybe_unused_attributes
{
int f1()
{
return 42;
}
[[nodiscard]] int f2()
{
[[maybe_unused]] auto unused = f1();
switch (f1())
{
case 17:
f1();
[[fallthrough]];
case 42:
f1();
}
return f1();
}
}
namespace test_extended_aggregate_initialization
{
struct base1
{
int b1, b2 = 42;
};
struct base2
{
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1 {{1, 2}, {}, 4}; // full initialization
derived d2 {{}, {}, 4}; // value-initialized bases
}
namespace test_general_range_based_for_loop
{
struct iter
{
int i;
int& operator* ()
{
return i;
}
const int& operator* () const
{
return i;
}
iter& operator++()
{
++i;
return *this;
}
};
struct sentinel
{
int i;
};
bool operator== (const iter& i, const sentinel& s)
{
return i.i == s.i;
}
bool operator!= (const iter& i, const sentinel& s)
{
return !(i == s);
}
struct range
{
iter begin() const
{
return {0};
}
sentinel end() const
{
return {5};
}
};
void f()
{
range r {};
for (auto i : r)
{
[[maybe_unused]] auto v = i;
}
}
}
namespace test_lambda_capture_asterisk_this_by_value
{
struct t
{
int i;
int foo()
{
return [*this]()
{
return i;
}();
}
};
}
namespace test_enum_class_construction
{
enum class byte : unsigned char
{};
byte foo {42};
}
namespace test_constexpr_if
{
template <bool cond>
int f ()
{
if constexpr(cond)
{
return 13;
}
else
{
return 42;
}
}
}
namespace test_selection_statement_with_initializer
{
int f()
{
return 13;
}
int f2()
{
if (auto i = f(); i > 0)
{
return 3;
}
switch (auto i = f(); i + 4)
{
case 17:
return 2;
default:
return 1;
}
}
}
namespace test_template_argument_deduction_for_class_templates
{
template <typename T1, typename T2>
struct pair
{
pair (T1 p1, T2 p2)
: m1 {p1},
m2 {p2}
{}
T1 m1;
T2 m2;
};
void f()
{
[[maybe_unused]] auto p = pair{13, 42u};
}
}
namespace test_non_type_auto_template_parameters
{
template <auto n>
struct B
{};
B<5> b1;
B<'a'> b2;
}
namespace test_structured_bindings
{
int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 };
auto f1() -> int(&)[2]
{
return arr;
}
auto f2() -> std::pair<int, int>&
{
return pr;
}
struct S
{
int x1 : 2;
volatile double y1;
};
S f3()
{
return {};
}
auto [ x1, y1 ] = f1();
auto& [ xr1, yr1 ] = f1();
auto [ x2, y2 ] = f2();
auto& [ xr2, yr2 ] = f2();
const auto [ x3, y3 ] = f3();
}
namespace test_exception_spec_type_system
{
struct Good {};
struct Bad {};
void g1() noexcept;
void g2();
template<typename T>
Bad
f(T*, T*);
template<typename T1, typename T2>
Good
f(T1*, T2*);
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
}
namespace test_inline_variables
{
template<class T> void f(T)
{}
template<class T> inline T g(T)
{
return T{};
}
template<> inline void f<>(int)
{}
template<> int g<>(int)
{
return 5;
}
}
} // namespace cxx17
#endif // __cplusplus < 201703L
]])

View File

@@ -1,133 +0,0 @@
# ============================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
# ============================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the C++11
# standard; if necessary, add switches to CXXFLAGS to enable support.
#
# The first argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The second argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline C++11 support is required and that the macro
# should error out if no mode with that support is found. If specified
# 'optional', then configuration proceeds regardless, after defining
# HAVE_CXX11 if and only if a supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 3
m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
typedef check<check<bool>> right_angle_brackets;
int a;
decltype(a) b;
typedef check<int> check_type;
check_type c;
check_type&& cr = static_cast<check_type&&>(c);
auto d = a;
])
AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
m4_if([$1], [], [],
[$1], [ext], [],
[$1], [noext], [],
[m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
[$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
[$2], [optional], [ax_cxx_compile_cxx11_required=false],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
ax_cv_cxx_compile_cxx11,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[ax_cv_cxx_compile_cxx11=yes],
[ax_cv_cxx_compile_cxx11=no])])
if test x$ax_cv_cxx_compile_cxx11 = xyes; then
ac_success=yes
fi
m4_if([$1], [noext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=gnu++11 -std=gnu++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
m4_if([$1], [ext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=c++11 -std=c++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx11_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
fi
else
if test x$ac_success = xno; then
HAVE_CXX11=0
AC_MSG_NOTICE([No compiler with C++11 support was found])
else
HAVE_CXX11=1
AC_DEFINE(HAVE_CXX11,1,
[define if the compiler supports basic C++11 syntax])
fi
AC_SUBST(HAVE_CXX11)
fi
])

View File

@@ -32,7 +32,7 @@
#ifdef HAVE_LIBXML2 #ifdef HAVE_LIBXML2
#include <libxml/HTMLparser.h> # include <libxml/HTMLparser.h>
#endif // HAVE_LIBXML2 #endif // HAVE_LIBXML2

View File

@@ -26,23 +26,23 @@
#include <sys/stat.h> #include <sys/stat.h>
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> # include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H #endif // HAVE_SYS_SOCKET_H
#ifdef HAVE_NETDB_H #ifdef HAVE_NETDB_H
#include <netdb.h> # include <netdb.h>
#endif // HAVE_NETDB_H #endif // HAVE_NETDB_H
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> # include <unistd.h>
#endif // HAVE_UNISTD_H #endif // HAVE_UNISTD_H
#ifdef HAVE_FCNTL_H #ifdef HAVE_FCNTL_H
#include <fcntl.h> # include <fcntl.h>
#endif // HAVE_FCNTL_H #endif // HAVE_FCNTL_H
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> # include <netinet/in.h>
#endif // HAVE_NETINET_IN_H #endif // HAVE_NETINET_IN_H
#include <netinet/tcp.h> #include <netinet/tcp.h>
#ifdef HAVE_ARPA_INET_H #ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h> # include <arpa/inet.h>
#endif // HAVE_ARPA_INET_H #endif // HAVE_ARPA_INET_H
#include <cassert> #include <cassert>
@@ -64,7 +64,7 @@
#include "template.h" #include "template.h"
#ifndef O_BINARY #ifndef O_BINARY
#define O_BINARY (0) # define O_BINARY (0)
#endif // O_BINARY #endif // O_BINARY
namespace nghttp2 { namespace nghttp2 {
@@ -305,7 +305,7 @@ public:
} }
} }
auto handler = auto handler =
make_unique<Http2Handler>(this, fd, ssl, get_next_session_id()); std::make_unique<Http2Handler>(this, fd, ssl, get_next_session_id());
if (!ssl) { if (!ssl) {
if (handler->connection_made() != 0) { if (handler->connection_made() != 0) {
return; return;
@@ -358,11 +358,11 @@ public:
} }
FileEntry *cache_fd(const std::string &path, const FileEntry &ent) { FileEntry *cache_fd(const std::string &path, const FileEntry &ent) {
#ifdef HAVE_STD_MAP_EMPLACE #ifdef HAVE_STD_MAP_EMPLACE
auto rv = fd_cache_.emplace(path, make_unique<FileEntry>(ent)); auto rv = fd_cache_.emplace(path, std::make_unique<FileEntry>(ent));
#else // !HAVE_STD_MAP_EMPLACE #else // !HAVE_STD_MAP_EMPLACE
// for gcc-4.7 // for gcc-4.7
auto rv = auto rv = fd_cache_.insert(
fd_cache_.insert(std::make_pair(path, make_unique<FileEntry>(ent))); std::make_pair(path, std::make_unique<FileEntry>(ent)));
#endif // !HAVE_STD_MAP_EMPLACE #endif // !HAVE_STD_MAP_EMPLACE
auto &res = (*rv).second; auto &res = (*rv).second;
res->it = rv; res->it = rv;
@@ -888,7 +888,9 @@ int Http2Handler::verify_npn_result() {
const unsigned char *next_proto = nullptr; const unsigned char *next_proto = nullptr;
unsigned int next_proto_len; unsigned int next_proto_len;
// Check the negotiated protocol in NPN or ALPN // Check the negotiated protocol in NPN or ALPN
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len); SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
#endif // !OPENSSL_NO_NEXTPROTONEG
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
if (next_proto) { if (next_proto) {
auto proto = StringRef{next_proto, next_proto_len}; auto proto = StringRef{next_proto, next_proto_len};
@@ -1021,7 +1023,7 @@ int Http2Handler::submit_push_promise(Stream *stream,
return promised_stream_id; return promised_stream_id;
} }
auto promised_stream = make_unique<Stream>(this, promised_stream_id); auto promised_stream = std::make_unique<Stream>(this, promised_stream_id);
auto &promised_header = promised_stream->header; auto &promised_header = promised_stream->header;
promised_header.method = StringRef::from_lit("GET"); promised_header.method = StringRef::from_lit("GET");
@@ -1475,7 +1477,7 @@ int on_begin_headers_callback(nghttp2_session *session,
return 0; return 0;
} }
auto stream = make_unique<Stream>(hd, frame->hd.stream_id); auto stream = std::make_unique<Stream>(hd, frame->hd.stream_id);
add_stream_read_timeout(stream.get()); add_stream_read_timeout(stream.get());
@@ -1830,10 +1832,10 @@ public:
if (config_->verbose) { if (config_->verbose) {
std::cerr << "spawning thread #" << i << std::endl; std::cerr << "spawning thread #" << i << std::endl;
} }
auto worker = make_unique<Worker>(); auto worker = std::make_unique<Worker>();
auto loop = ev_loop_new(get_ev_loop_flags()); auto loop = ev_loop_new(get_ev_loop_flags());
worker->sessions = worker->sessions = std::make_unique<Sessions>(sv, loop, config_,
make_unique<Sessions>(sv, loop, config_, sessions_->get_ssl_ctx()); sessions_->get_ssl_ctx());
ev_async_init(&worker->w, worker_acceptcb); ev_async_init(&worker->w, worker_acceptcb);
worker->w.data = worker.get(); worker->w.data = worker.get();
ev_async_start(loop, &worker->w); ev_async_start(loop, &worker->w);
@@ -1982,6 +1984,7 @@ HttpServer::HttpServer(const Config *config) : config_(config) {
}; };
} }
#ifndef OPENSSL_NO_NEXTPROTONEG
namespace { namespace {
int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len, int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
void *arg) { void *arg) {
@@ -1991,6 +1994,7 @@ int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }
} // namespace } // namespace
#endif // !OPENSSL_NO_NEXTPROTONEG
namespace { namespace {
int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
@@ -2205,7 +2209,9 @@ int HttpServer::run() {
next_proto = util::get_default_alpn(); next_proto = util::get_default_alpn();
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto); SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto);
#endif // !OPENSSL_NO_NEXTPROTONEG
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
// ALPN selection callback // ALPN selection callback
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this); SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this);

View File

@@ -28,10 +28,11 @@
#include "nghttp2_config.h" #include "nghttp2_config.h"
#ifndef _WIN32 #ifndef _WIN32
#include <sys/uio.h> # include <sys/uio.h>
#endif // !_WIN32 #endif // !_WIN32
#include <cassert> #include <cassert>
#include <utility>
#include "template.h" #include "template.h"
@@ -65,25 +66,19 @@ struct BlockAllocator {
~BlockAllocator() { reset(); } ~BlockAllocator() { reset(); }
BlockAllocator(BlockAllocator &&other) noexcept BlockAllocator(BlockAllocator &&other) noexcept
: retain(other.retain), : retain{std::exchange(other.retain, nullptr)},
head(other.head), head{std::exchange(other.head, nullptr)},
block_size(other.block_size), block_size(other.block_size),
isolation_threshold(other.isolation_threshold) { isolation_threshold(other.isolation_threshold) {}
other.retain = nullptr;
other.head = nullptr;
}
BlockAllocator &operator=(BlockAllocator &&other) noexcept { BlockAllocator &operator=(BlockAllocator &&other) noexcept {
reset(); reset();
retain = other.retain; retain = std::exchange(other.retain, nullptr);
head = other.head; head = std::exchange(other.head, nullptr);
block_size = other.block_size; block_size = other.block_size;
isolation_threshold = other.isolation_threshold; isolation_threshold = other.isolation_threshold;
other.retain = nullptr;
other.head = nullptr;
return *this; return *this;
} }

View File

@@ -24,19 +24,19 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> # include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H #endif // HAVE_SYS_SOCKET_H
#ifdef HAVE_NETDB_H #ifdef HAVE_NETDB_H
#include <netdb.h> # include <netdb.h>
#endif // HAVE_NETDB_H #endif // HAVE_NETDB_H
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> # include <unistd.h>
#endif // HAVE_UNISTD_H #endif // HAVE_UNISTD_H
#ifdef HAVE_FCNTL_H #ifdef HAVE_FCNTL_H
#include <fcntl.h> # include <fcntl.h>
#endif // HAVE_FCNTL_H #endif // HAVE_FCNTL_H
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> # include <netinet/in.h>
#endif // HAVE_NETINET_IN_H #endif // HAVE_NETINET_IN_H
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <poll.h> #include <poll.h>
@@ -77,6 +77,8 @@ const char *strsettingsid(int32_t id) {
return "SETTINGS_MAX_FRAME_SIZE"; return "SETTINGS_MAX_FRAME_SIZE";
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
return "SETTINGS_MAX_HEADER_LIST_SIZE"; return "SETTINGS_MAX_HEADER_LIST_SIZE";
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
return "SETTINGS_ENABLE_CONNECT_PROTOCOL";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }
@@ -106,6 +108,8 @@ std::string strframetype(uint8_t type) {
return "WINDOW_UPDATE"; return "WINDOW_UPDATE";
case NGHTTP2_ALTSVC: case NGHTTP2_ALTSVC:
return "ALTSVC"; return "ALTSVC";
case NGHTTP2_ORIGIN:
return "ORIGIN";
} }
std::string s = "extension(0x"; std::string s = "extension(0x";
@@ -351,6 +355,15 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) {
static_cast<int>(altsvc->field_value_len), altsvc->field_value); static_cast<int>(altsvc->field_value_len), altsvc->field_value);
break; break;
} }
case NGHTTP2_ORIGIN: {
auto origin = static_cast<nghttp2_ext_origin *>(frame->ext.payload);
for (size_t i = 0; i < origin->nov; ++i) {
auto ent = &origin->ov[i];
print_frame_attr_indent();
fprintf(outfile, "[%.*s]\n", (int)ent->origin_len, ent->origin);
}
break;
}
default: default:
break; break;
} }

View File

@@ -30,7 +30,7 @@
#include <cinttypes> #include <cinttypes>
#include <cstdlib> #include <cstdlib>
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
#include <sys/time.h> # include <sys/time.h>
#endif // HAVE_SYS_TIME_H #endif // HAVE_SYS_TIME_H
#include <poll.h> #include <poll.h>

View File

@@ -34,7 +34,7 @@ namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
namespace client { namespace client {
request::request() : impl_(make_unique<request_impl>()) {} request::request() : impl_(std::make_unique<request_impl>()) {}
request::~request() {} request::~request() {}

View File

@@ -34,7 +34,7 @@ namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
namespace client { namespace client {
response::response() : impl_(make_unique<response_impl>()) {} response::response() : impl_(std::make_unique<response_impl>()) {}
response::~response() {} response::~response() {}

View File

@@ -44,6 +44,15 @@ session::session(boost::asio::io_service &io_service, const std::string &host,
impl_->start_resolve(host, service); impl_->start_resolve(host, service);
} }
session::session(boost::asio::io_service &io_service,
const boost::asio::ip::tcp::endpoint &local_endpoint,
const std::string &host, const std::string &service)
: impl_(std::make_shared<session_tcp_impl>(
io_service, local_endpoint, host, service,
boost::posix_time::seconds(60))) {
impl_->start_resolve(host, service);
}
session::session(boost::asio::io_service &io_service, const std::string &host, session::session(boost::asio::io_service &io_service, const std::string &host,
const std::string &service, const std::string &service,
const boost::posix_time::time_duration &connect_timeout) const boost::posix_time::time_duration &connect_timeout)
@@ -52,6 +61,15 @@ session::session(boost::asio::io_service &io_service, const std::string &host,
impl_->start_resolve(host, service); impl_->start_resolve(host, service);
} }
session::session(boost::asio::io_service &io_service,
const boost::asio::ip::tcp::endpoint &local_endpoint,
const std::string &host, const std::string &service,
const boost::posix_time::time_duration &connect_timeout)
: impl_(std::make_shared<session_tcp_impl>(io_service, local_endpoint, host,
service, connect_timeout)) {
impl_->start_resolve(host, service);
}
session::session(boost::asio::io_service &io_service, session::session(boost::asio::io_service &io_service,
boost::asio::ssl::context &tls_ctx, const std::string &host, boost::asio::ssl::context &tls_ctx, const std::string &host,
const std::string &service) const std::string &service)

View File

@@ -473,7 +473,7 @@ stream *session_impl::create_push_stream(int32_t stream_id) {
} }
std::unique_ptr<stream> session_impl::create_stream() { std::unique_ptr<stream> session_impl::create_stream() {
return make_unique<stream>(this); return std::make_unique<stream>(this);
} }
const request *session_impl::submit(boost::system::error_code &ec, const request *session_impl::submit(boost::system::error_code &ec,

View File

@@ -34,24 +34,35 @@ session_tcp_impl::session_tcp_impl(
const boost::posix_time::time_duration &connect_timeout) const boost::posix_time::time_duration &connect_timeout)
: session_impl(io_service, connect_timeout), socket_(io_service) {} : session_impl(io_service, connect_timeout), socket_(io_service) {}
session_tcp_impl::session_tcp_impl(
boost::asio::io_service &io_service,
const boost::asio::ip::tcp::endpoint &local_endpoint,
const std::string &host, const std::string &service,
const boost::posix_time::time_duration &connect_timeout)
: session_impl(io_service, connect_timeout), socket_(io_service) {
socket_.open(local_endpoint.protocol());
boost::asio::socket_base::reuse_address option(true);
socket_.set_option(option);
socket_.bind(local_endpoint);
}
session_tcp_impl::~session_tcp_impl() {} session_tcp_impl::~session_tcp_impl() {}
void session_tcp_impl::start_connect(tcp::resolver::iterator endpoint_it) { void session_tcp_impl::start_connect(tcp::resolver::iterator endpoint_it) {
auto self = shared_from_this(); auto self = shared_from_this();
boost::asio::async_connect(socket_, endpoint_it, socket_.async_connect(
[self](const boost::system::error_code &ec, *endpoint_it, [self, endpoint_it](const boost::system::error_code &ec) {
tcp::resolver::iterator endpoint_it) { if (self->stopped()) {
if (self->stopped()) { return;
return; }
}
if (ec) { if (ec) {
self->not_connected(ec); self->not_connected(ec);
return; return;
} }
self->connected(endpoint_it); self->connected(endpoint_it);
}); });
} }
tcp::socket &session_tcp_impl::socket() { return socket_; } tcp::socket &session_tcp_impl::socket() { return socket_; }

View File

@@ -40,6 +40,10 @@ public:
session_tcp_impl(boost::asio::io_service &io_service, const std::string &host, session_tcp_impl(boost::asio::io_service &io_service, const std::string &host,
const std::string &service, const std::string &service,
const boost::posix_time::time_duration &connect_timeout); const boost::posix_time::time_duration &connect_timeout);
session_tcp_impl(boost::asio::io_service &io_service,
const boost::asio::ip::tcp::endpoint &local_endpoint,
const std::string &host, const std::string &service,
const boost::posix_time::time_duration &connect_timeout);
virtual ~session_tcp_impl(); virtual ~session_tcp_impl();
virtual void start_connect(tcp::resolver::iterator endpoint_it); virtual void start_connect(tcp::resolver::iterator endpoint_it);

View File

@@ -38,6 +38,10 @@ session_tls_impl::session_tls_impl(
// ssl::context::set_verify_mode(boost::asio::ssl::verify_peer) is // ssl::context::set_verify_mode(boost::asio::ssl::verify_peer) is
// not used, which is what we want. // not used, which is what we want.
socket_.set_verify_callback(boost::asio::ssl::rfc2818_verification(host)); socket_.set_verify_callback(boost::asio::ssl::rfc2818_verification(host));
auto ssl = socket_.native_handle();
if (!util::numeric_host(host.c_str())) {
SSL_set_tlsext_host_name(ssl, host.c_str());
}
} }
session_tls_impl::~session_tls_impl() {} session_tls_impl::~session_tls_impl() {}

View File

@@ -35,6 +35,7 @@ namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
namespace client { namespace client {
#ifndef OPENSSL_NO_NEXTPROTONEG
namespace { namespace {
int client_select_next_proto_cb(SSL *ssl, unsigned char **out, int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
unsigned char *outlen, const unsigned char *in, unsigned char *outlen, const unsigned char *in,
@@ -46,6 +47,7 @@ int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }
} // namespace } // namespace
#endif // !OPENSSL_NO_NEXTPROTONEG
boost::system::error_code boost::system::error_code
configure_tls_context(boost::system::error_code &ec, configure_tls_context(boost::system::error_code &ec,
@@ -54,7 +56,9 @@ configure_tls_context(boost::system::error_code &ec,
auto ctx = tls_ctx.native_handle(); auto ctx = tls_ctx.native_handle();
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_proto_select_cb(ctx, client_select_next_proto_cb, nullptr); SSL_CTX_set_next_proto_select_cb(ctx, client_select_next_proto_cb, nullptr);
#endif // !OPENSSL_NO_NEXTPROTONEG
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
auto proto_list = util::get_default_alpn(); auto proto_list = util::get_default_alpn();

View File

@@ -177,7 +177,9 @@ bool tls_h2_negotiated(ssl_socket &socket) {
const unsigned char *next_proto = nullptr; const unsigned char *next_proto = nullptr;
unsigned int next_proto_len = 0; unsigned int next_proto_len = 0;
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len); SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
#endif // !OPENSSL_NO_NEXTPROTONEG
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (next_proto == nullptr) { if (next_proto == nullptr) {
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len); SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);

View File

@@ -36,7 +36,7 @@ namespace asio_http2 {
namespace server { namespace server {
http2::http2() : impl_(make_unique<http2_impl>()) {} http2::http2() : impl_(std::make_unique<http2_impl>()) {}
http2::~http2() {} http2::~http2() {}

View File

@@ -305,7 +305,8 @@ int http2_handler::start() {
} }
stream *http2_handler::create_stream(int32_t stream_id) { stream *http2_handler::create_stream(int32_t stream_id) {
auto p = streams_.emplace(stream_id, make_unique<stream>(this, stream_id)); auto p =
streams_.emplace(stream_id, std::make_unique<stream>(this, stream_id));
assert(p.second); assert(p.second);
return (*p.first).second.get(); return (*p.first).second.get();
} }

View File

@@ -34,7 +34,7 @@ namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
namespace server { namespace server {
request::request() : impl_(make_unique<request_impl>()) {} request::request() : impl_(std::make_unique<request_impl>()) {}
request::~request() {} request::~request() {}

View File

@@ -34,7 +34,7 @@ namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
namespace server { namespace server {
response::response() : impl_(make_unique<response_impl>()) {} response::response() : impl_(std::make_unique<response_impl>()) {}
response::~response() {} response::~response() {}

View File

@@ -35,12 +35,14 @@ namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
namespace server { namespace server {
#ifndef OPENSSL_NO_NEXTPROTONEG
namespace { namespace {
std::vector<unsigned char> &get_alpn_token() { std::vector<unsigned char> &get_alpn_token() {
static auto alpn_token = util::get_default_alpn(); static auto alpn_token = util::get_default_alpn();
return alpn_token; return alpn_token;
} }
} // namespace } // namespace
#endif // !OPENSSL_NO_NEXTPROTONEG
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
namespace { namespace {
@@ -82,6 +84,7 @@ configure_tls_context_easy(boost::system::error_code &ec,
} }
#endif /* OPENSSL_NO_EC */ #endif /* OPENSSL_NO_EC */
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_protos_advertised_cb( SSL_CTX_set_next_protos_advertised_cb(
ctx, ctx,
[](SSL *s, const unsigned char **data, unsigned int *len, void *arg) { [](SSL *s, const unsigned char **data, unsigned int *len, void *arg) {
@@ -93,6 +96,7 @@ configure_tls_context_easy(boost::system::error_code &ec,
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
}, },
nullptr); nullptr);
#endif // !OPENSSL_NO_NEXTPROTONEG
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
// ALPN selection callback // ALPN selection callback

View File

@@ -36,14 +36,17 @@ namespace nghttp2 {
namespace base64 { namespace base64 {
namespace {
constexpr char B64_CHARS[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
};
} // namespace
template <typename InputIt> std::string encode(InputIt first, InputIt last) { template <typename InputIt> std::string encode(InputIt first, InputIt last) {
static constexpr char CHAR_TABLE[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
};
std::string res; std::string res;
size_t len = last - first; size_t len = last - first;
if (len == 0) { if (len == 0) {
@@ -57,29 +60,72 @@ template <typename InputIt> std::string encode(InputIt first, InputIt last) {
uint32_t n = static_cast<uint8_t>(*first++) << 16; uint32_t n = static_cast<uint8_t>(*first++) << 16;
n += static_cast<uint8_t>(*first++) << 8; n += static_cast<uint8_t>(*first++) << 8;
n += static_cast<uint8_t>(*first++); n += static_cast<uint8_t>(*first++);
*p++ = CHAR_TABLE[n >> 18]; *p++ = B64_CHARS[n >> 18];
*p++ = CHAR_TABLE[(n >> 12) & 0x3fu]; *p++ = B64_CHARS[(n >> 12) & 0x3fu];
*p++ = CHAR_TABLE[(n >> 6) & 0x3fu]; *p++ = B64_CHARS[(n >> 6) & 0x3fu];
*p++ = CHAR_TABLE[n & 0x3fu]; *p++ = B64_CHARS[n & 0x3fu];
} }
if (r == 2) { if (r == 2) {
uint32_t n = static_cast<uint8_t>(*first++) << 16; uint32_t n = static_cast<uint8_t>(*first++) << 16;
n += static_cast<uint8_t>(*first++) << 8; n += static_cast<uint8_t>(*first++) << 8;
*p++ = CHAR_TABLE[n >> 18]; *p++ = B64_CHARS[n >> 18];
*p++ = CHAR_TABLE[(n >> 12) & 0x3fu]; *p++ = B64_CHARS[(n >> 12) & 0x3fu];
*p++ = CHAR_TABLE[(n >> 6) & 0x3fu]; *p++ = B64_CHARS[(n >> 6) & 0x3fu];
*p++ = '='; *p++ = '=';
} else if (r == 1) { } else if (r == 1) {
uint32_t n = static_cast<uint8_t>(*first++) << 16; uint32_t n = static_cast<uint8_t>(*first++) << 16;
*p++ = CHAR_TABLE[n >> 18]; *p++ = B64_CHARS[n >> 18];
*p++ = CHAR_TABLE[(n >> 12) & 0x3fu]; *p++ = B64_CHARS[(n >> 12) & 0x3fu];
*p++ = '='; *p++ = '=';
*p++ = '='; *p++ = '=';
} }
return res; return res;
} }
constexpr size_t encode_length(size_t n) { return (n + 2) / 3 * 4; }
template <typename InputIt, typename OutputIt>
OutputIt encode(InputIt first, InputIt last, OutputIt d_first) {
size_t len = last - first;
if (len == 0) {
return d_first;
}
auto r = len % 3;
auto j = last - r;
auto p = d_first;
while (first != j) {
uint32_t n = static_cast<uint8_t>(*first++) << 16;
n += static_cast<uint8_t>(*first++) << 8;
n += static_cast<uint8_t>(*first++);
*p++ = B64_CHARS[n >> 18];
*p++ = B64_CHARS[(n >> 12) & 0x3fu];
*p++ = B64_CHARS[(n >> 6) & 0x3fu];
*p++ = B64_CHARS[n & 0x3fu];
}
switch (r) {
case 2: {
uint32_t n = static_cast<uint8_t>(*first++) << 16;
n += static_cast<uint8_t>(*first++) << 8;
*p++ = B64_CHARS[n >> 18];
*p++ = B64_CHARS[(n >> 12) & 0x3fu];
*p++ = B64_CHARS[(n >> 6) & 0x3fu];
*p++ = '=';
break;
}
case 1: {
uint32_t n = static_cast<uint8_t>(*first++) << 16;
*p++ = B64_CHARS[n >> 18];
*p++ = B64_CHARS[(n >> 12) & 0x3fu];
*p++ = '=';
*p++ = '=';
break;
}
}
return p;
}
template <typename InputIt> template <typename InputIt>
InputIt next_decode_input(InputIt first, InputIt last, const int *tbl) { InputIt next_decode_input(InputIt first, InputIt last, const int *tbl) {
for (; first != last; ++first) { for (; first != last; ++first) {

View File

@@ -26,7 +26,7 @@
#define BASE64_TEST_H #define BASE64_TEST_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
namespace nghttp2 { namespace nghttp2 {

View File

@@ -26,7 +26,7 @@
#define BUFFER_TEST_H #define BUFFER_TEST_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
namespace nghttp2 { namespace nghttp2 {

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_COMP_HELPER_H #define NGHTTP2_COMP_HELPER_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <jansson.h> #include <jansson.h>

View File

@@ -23,11 +23,11 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> # include <unistd.h>
#endif // HAVE_UNISTD_H #endif // HAVE_UNISTD_H
#include <getopt.h> #include <getopt.h>

View File

@@ -27,12 +27,12 @@
#include <getopt.h> #include <getopt.h>
#include <signal.h> #include <signal.h>
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> # include <netinet/in.h>
#endif // HAVE_NETINET_IN_H #endif // HAVE_NETINET_IN_H
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef HAVE_FCNTL_H #ifdef HAVE_FCNTL_H
#include <fcntl.h> # include <fcntl.h>
#endif // HAVE_FCNTL_H #endif // HAVE_FCNTL_H
#include <cstdio> #include <cstdio>
@@ -58,7 +58,7 @@
#include "template.h" #include "template.h"
#ifndef O_BINARY #ifndef O_BINARY
#define O_BINARY (0) # define O_BINARY (0)
#endif // O_BINARY #endif // O_BINARY
using namespace nghttp2; using namespace nghttp2;
@@ -211,7 +211,7 @@ void rate_period_timeout_w_cb(struct ev_loop *loop, ev_timer *w, int revents) {
--worker->nreqs_rem; --worker->nreqs_rem;
} }
auto client = auto client =
make_unique<Client>(worker->next_client_id++, worker, req_todo); std::make_unique<Client>(worker->next_client_id++, worker, req_todo);
++worker->nconns_made; ++worker->nconns_made;
@@ -857,7 +857,9 @@ int Client::connection_made() {
const unsigned char *next_proto = nullptr; const unsigned char *next_proto = nullptr;
unsigned int next_proto_len; unsigned int next_proto_len;
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len); SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
#endif // !OPENSSL_NO_NEXTPROTONEG
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (next_proto == nullptr) { if (next_proto == nullptr) {
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len); SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
@@ -867,9 +869,9 @@ int Client::connection_made() {
if (next_proto) { if (next_proto) {
auto proto = StringRef{next_proto, next_proto_len}; auto proto = StringRef{next_proto, next_proto_len};
if (util::check_h2_is_selected(proto)) { if (util::check_h2_is_selected(proto)) {
session = make_unique<Http2Session>(this); session = std::make_unique<Http2Session>(this);
} else if (util::streq(NGHTTP2_H1_1, proto)) { } else if (util::streq(NGHTTP2_H1_1, proto)) {
session = make_unique<Http1Session>(this); session = std::make_unique<Http1Session>(this);
} }
// Just assign next_proto to selected_proto anyway to show the // Just assign next_proto to selected_proto anyway to show the
@@ -884,7 +886,7 @@ int Client::connection_made() {
std::cout std::cout
<< "Server does not support NPN/ALPN. Falling back to HTTP/1.1." << "Server does not support NPN/ALPN. Falling back to HTTP/1.1."
<< std::endl; << std::endl;
session = make_unique<Http1Session>(this); session = std::make_unique<Http1Session>(this);
selected_proto = NGHTTP2_H1_1.str(); selected_proto = NGHTTP2_H1_1.str();
break; break;
} }
@@ -908,11 +910,11 @@ int Client::connection_made() {
} else { } else {
switch (config.no_tls_proto) { switch (config.no_tls_proto) {
case Config::PROTO_HTTP2: case Config::PROTO_HTTP2:
session = make_unique<Http2Session>(this); session = std::make_unique<Http2Session>(this);
selected_proto = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID; selected_proto = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
break; break;
case Config::PROTO_HTTP1_1: case Config::PROTO_HTTP1_1:
session = make_unique<Http1Session>(this); session = std::make_unique<Http1Session>(this);
selected_proto = NGHTTP2_H1_1.str(); selected_proto = NGHTTP2_H1_1.str();
break; break;
default: default:
@@ -1317,7 +1319,7 @@ void Worker::run() {
--nreqs_rem; --nreqs_rem;
} }
auto client = make_unique<Client>(next_client_id++, this, req_todo); auto client = std::make_unique<Client>(next_client_id++, this, req_todo);
if (client->connect() != 0) { if (client->connect() != 0) {
std::cerr << "client could not connect to host" << std::endl; std::cerr << "client could not connect to host" << std::endl;
client->fail(); client->fail();
@@ -1511,7 +1513,7 @@ process_time_stats(const std::vector<std::unique_ptr<Worker>> &workers) {
namespace { namespace {
void resolve_host() { void resolve_host() {
if (config.base_uri_unix) { if (config.base_uri_unix) {
auto res = make_unique<addrinfo>(); auto res = std::make_unique<addrinfo>();
res->ai_family = config.unix_addr.sun_family; res->ai_family = config.unix_addr.sun_family;
res->ai_socktype = SOCK_STREAM; res->ai_socktype = SOCK_STREAM;
res->ai_addrlen = sizeof(config.unix_addr); res->ai_addrlen = sizeof(config.unix_addr);
@@ -1563,6 +1565,7 @@ std::string get_reqline(const char *uri, const http_parser_url &u) {
} }
} // namespace } // namespace
#ifndef OPENSSL_NO_NEXTPROTONEG
namespace { namespace {
int client_select_next_proto_cb(SSL *ssl, unsigned char **out, int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
unsigned char *outlen, const unsigned char *in, unsigned char *outlen, const unsigned char *in,
@@ -1577,6 +1580,7 @@ int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
return SSL_TLSEXT_ERR_NOACK; return SSL_TLSEXT_ERR_NOACK;
} }
} // namespace } // namespace
#endif // !OPENSSL_NO_NEXTPROTONEG
namespace { namespace {
constexpr char UNIX_PATH_PREFIX[] = "unix:"; constexpr char UNIX_PATH_PREFIX[] = "unix:";
@@ -1718,13 +1722,13 @@ std::unique_ptr<Worker> create_worker(uint32_t id, SSL_CTX *ssl_ctx,
} }
if (config.is_rate_mode()) { if (config.is_rate_mode()) {
return make_unique<Worker>(id, ssl_ctx, nreqs, nclients, rate, max_samples, return std::make_unique<Worker>(id, ssl_ctx, nreqs, nclients, rate,
&config); max_samples, &config);
} else { } else {
// Here rate is same as client because the rate_timeout callback // Here rate is same as client because the rate_timeout callback
// will be called only once // will be called only once
return make_unique<Worker>(id, ssl_ctx, nreqs, nclients, nclients, return std::make_unique<Worker>(id, ssl_ctx, nreqs, nclients, nclients,
max_samples, &config); max_samples, &config);
} }
} }
} // namespace } // namespace
@@ -1795,10 +1799,12 @@ Options:
-c, --clients=<N> -c, --clients=<N>
Number of concurrent clients. With -r option, this Number of concurrent clients. With -r option, this
specifies the maximum number of connections to be made. specifies the maximum number of connections to be made.
Default: )" << config.nclients << R"( Default: )"
<< config.nclients << R"(
-t, --threads=<N> -t, --threads=<N>
Number of native threads. Number of native threads.
Default: )" << config.nthreads << R"( Default: )"
<< config.nthreads << R"(
-i, --input-file=<PATH> -i, --input-file=<PATH>
Path of a file with multiple URIs are separated by EOLs. Path of a file with multiple URIs are separated by EOLs.
This option will disable URIs getting from command-line. This option will disable URIs getting from command-line.
@@ -1821,7 +1827,8 @@ Options:
-W, --connection-window-bits=<N> -W, --connection-window-bits=<N>
Sets the connection level initial window size to Sets the connection level initial window size to
(2**<N>)-1. (2**<N>)-1.
Default: )" << config.connection_window_bits << R"( Default: )"
<< config.connection_window_bits << R"(
-H, --header=<HEADER> -H, --header=<HEADER>
Add/Override a header to the requests. Add/Override a header to the requests.
--ciphers=<SUITE> --ciphers=<SUITE>
@@ -1832,8 +1839,8 @@ Options:
-p, --no-tls-proto=<PROTOID> -p, --no-tls-proto=<PROTOID>
Specify ALPN identifier of the protocol to be used when Specify ALPN identifier of the protocol to be used when
accessing http URI without SSL/TLS. accessing http URI without SSL/TLS.
Available protocols: )" << NGHTTP2_CLEARTEXT_PROTO_VERSION_ID Available protocols: )"
<< R"( and )" << NGHTTP2_H1_1 << R"( << NGHTTP2_CLEARTEXT_PROTO_VERSION_ID << R"( and )" << NGHTTP2_H1_1 << R"(
Default: )" Default: )"
<< NGHTTP2_CLEARTEXT_PROTO_VERSION_ID << R"( << NGHTTP2_CLEARTEXT_PROTO_VERSION_ID << R"(
-d, --data=<PATH> -d, --data=<PATH>
@@ -1852,7 +1859,7 @@ Options:
connections per period. When the rate is 0, the program connections per period. When the rate is 0, the program
will run as it normally does, creating connections at will run as it normally does, creating connections at
whatever variable rate it wants. The default value for whatever variable rate it wants. The default value for
this option is 0. this option is 0. -r and -D are mutually exclusive.
--rate-period=<DURATION> --rate-period=<DURATION>
Specifies the time period between creating connections. Specifies the time period between creating connections.
The period must be a positive number, representing the The period must be a positive number, representing the
@@ -1861,7 +1868,8 @@ Options:
option is 1s. option is 1s.
-D, --duration=<N> -D, --duration=<N>
Specifies the main duration for the measurements in case Specifies the main duration for the measurements in case
of timing-based benchmarking. of timing-based benchmarking. -D and -r are mutually
exclusive.
--warm-up-time=<DURATION> --warm-up-time=<DURATION>
Specifies the time period before starting the actual Specifies the time period before starting the actual
measurements, in case of timing-based benchmarking. measurements, in case of timing-based benchmarking.
@@ -1916,7 +1924,8 @@ Options:
NPN. The parameter must be delimited by a single comma NPN. The parameter must be delimited by a single comma
only and any white spaces are treated as a part of only and any white spaces are treated as a part of
protocol string. protocol string.
Default: )" << DEFAULT_NPN_LIST << R"( Default: )"
<< DEFAULT_NPN_LIST << R"(
--h1 Short hand for --npn-list=http/1.1 --h1 Short hand for --npn-list=http/1.1
--no-tls-proto=http/1.1, which effectively force --no-tls-proto=http/1.1, which effectively force
http/1.1 for both http and https URI. http/1.1 for both http and https URI.
@@ -1944,7 +1953,8 @@ Options:
The <DURATION> argument is an integer and an optional unit (e.g., 1s The <DURATION> argument is an integer and an optional unit (e.g., 1s
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit (hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit.)" << std::endl; is omitted, a second is used as unit.)"
<< std::endl;
} }
} // namespace } // namespace
@@ -2294,6 +2304,11 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (config.is_timing_based_mode() && config.is_rate_mode()) {
std::cerr << "-r, -D: they are mutually exclusive." << std::endl;
exit(EXIT_FAILURE);
}
if (config.nreqs == 0 && !config.is_timing_based_mode()) { if (config.nreqs == 0 && !config.is_timing_based_mode()) {
std::cerr << "-n: the number of requests must be strictly greater than 0 " std::cerr << "-n: the number of requests must be strictly greater than 0 "
"if timing-based test is not being run." "if timing-based test is not being run."
@@ -2399,8 +2414,10 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb, SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
nullptr); nullptr);
#endif // !OPENSSL_NO_NEXTPROTONEG
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
std::vector<unsigned char> proto_list; std::vector<unsigned char> proto_list;
@@ -2674,14 +2691,14 @@ int main(int argc, char **argv) {
finished in )" finished in )"
<< util::format_duration(duration) << ", " << rps << " req/s, " << util::format_duration(duration) << ", " << rps << " req/s, "
<< util::utos_funit(bps) << R"(B/s << util::utos_funit(bps) << R"(B/s
requests: )" << stats.req_todo << " total, " requests: )" << stats.req_todo
<< stats.req_started << " started, " << stats.req_done << " done, " << " total, " << stats.req_started << " started, " << stats.req_done
<< stats.req_status_success << " succeeded, " << stats.req_failed << " done, " << stats.req_status_success << " succeeded, "
<< " failed, " << stats.req_error << " errored, " << stats.req_failed << " failed, " << stats.req_error
<< stats.req_timedout << R"( timeout << " errored, " << stats.req_timedout << R"( timeout
status codes: )" << stats.status[2] << " 2xx, " status codes: )"
<< stats.status[3] << " 3xx, " << stats.status[4] << " 4xx, " << stats.status[2] << " 2xx, " << stats.status[3] << " 3xx, "
<< stats.status[5] << R"( 5xx << stats.status[4] << " 4xx, " << stats.status[5] << R"( 5xx
traffic: )" << util::utos_funit(stats.bytes_total) traffic: )" << util::utos_funit(stats.bytes_total)
<< "B (" << stats.bytes_total << ") total, " << "B (" << stats.bytes_total << ") total, "
<< util::utos_funit(stats.bytes_head) << "B (" << stats.bytes_head << util::utos_funit(stats.bytes_head) << "B (" << stats.bytes_head
@@ -2689,12 +2706,12 @@ traffic: )" << util::utos_funit(stats.bytes_total)
<< "%), " << util::utos_funit(stats.bytes_body) << "B (" << "%), " << util::utos_funit(stats.bytes_body) << "B ("
<< stats.bytes_body << R"() data << stats.bytes_body << R"() data
min max mean sd +/- sd min max mean sd +/- sd
time for request: )" << std::setw(10) time for request: )"
<< util::format_duration(ts.request.min) << " " << std::setw(10) << std::setw(10) << util::format_duration(ts.request.min) << " "
<< util::format_duration(ts.request.max) << " " << std::setw(10) << std::setw(10) << util::format_duration(ts.request.max) << " "
<< util::format_duration(ts.request.mean) << " " << std::setw(10) << std::setw(10) << util::format_duration(ts.request.mean) << " "
<< util::format_duration(ts.request.sd) << std::setw(9) << std::setw(10) << util::format_duration(ts.request.sd)
<< util::dtos(ts.request.within_sd) << "%" << std::setw(9) << util::dtos(ts.request.within_sd) << "%"
<< "\ntime for connect: " << std::setw(10) << "\ntime for connect: " << std::setw(10)
<< util::format_duration(ts.connect.min) << " " << 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.max) << " " << std::setw(10)

View File

@@ -29,10 +29,10 @@
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> # include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H #endif // HAVE_SYS_SOCKET_H
#ifdef HAVE_NETDB_H #ifdef HAVE_NETDB_H
#include <netdb.h> # include <netdb.h>
#endif // HAVE_NETDB_H #endif // HAVE_NETDB_H
#include <sys/un.h> #include <sys/un.h>

View File

@@ -70,6 +70,11 @@ namespace {
int htp_statuscb(http_parser *htp, const char *at, size_t length) { int htp_statuscb(http_parser *htp, const char *at, size_t length) {
auto session = static_cast<Http1Session *>(htp->data); auto session = static_cast<Http1Session *>(htp->data);
auto client = session->get_client(); auto client = session->get_client();
if (htp->status_code / 100 == 1) {
return 0;
}
client->on_status_code(session->stream_resp_counter_, htp->status_code); client->on_status_code(session->stream_resp_counter_, htp->status_code);
return 0; return 0;
@@ -82,6 +87,10 @@ int htp_msg_completecb(http_parser *htp) {
auto session = static_cast<Http1Session *>(htp->data); auto session = static_cast<Http1Session *>(htp->data);
auto client = session->get_client(); auto client = session->get_client();
if (htp->status_code / 100 == 1) {
return 0;
}
client->final = http_should_keep_alive(htp) == 0; client->final = http_should_keep_alive(htp) == 0;
auto req_stat = client->get_req_stat(session->stream_resp_counter_); auto req_stat = client->get_req_stat(session->stream_resp_counter_);
@@ -133,6 +142,12 @@ int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
} }
} // namespace } // namespace
namespace {
int htp_hdrs_completecb(http_parser *htp) {
return !http2::expect_response_body(htp->status_code);
}
} // namespace
namespace { namespace {
int htp_body_cb(http_parser *htp, const char *data, size_t len) { int htp_body_cb(http_parser *htp, const char *data, size_t len) {
auto session = static_cast<Http1Session *>(htp->data); auto session = static_cast<Http1Session *>(htp->data);
@@ -147,14 +162,14 @@ int htp_body_cb(http_parser *htp, const char *data, size_t len) {
namespace { namespace {
constexpr http_parser_settings htp_hooks = { constexpr http_parser_settings htp_hooks = {
htp_msg_begincb, // http_cb on_message_begin; htp_msg_begincb, // http_cb on_message_begin;
nullptr, // http_data_cb on_url; nullptr, // http_data_cb on_url;
htp_statuscb, // http_data_cb on_status; htp_statuscb, // http_data_cb on_status;
htp_hdr_keycb, // http_data_cb on_header_field; htp_hdr_keycb, // http_data_cb on_header_field;
htp_hdr_valcb, // http_data_cb on_header_value; htp_hdr_valcb, // http_data_cb on_header_value;
nullptr, // http_cb on_headers_complete; htp_hdrs_completecb, // http_cb on_headers_complete;
htp_body_cb, // http_data_cb on_body; htp_body_cb, // http_data_cb on_body;
htp_msg_completecb // http_cb on_message_complete; htp_msg_completecb // http_cb on_message_complete;
}; };
} // namespace } // namespace

View File

@@ -107,6 +107,9 @@ StringRef get_reason_phrase(unsigned int status_code) {
return StringRef::from_lit("Expectation Failed"); return StringRef::from_lit("Expectation Failed");
case 421: case 421:
return StringRef::from_lit("Misdirected Request"); return StringRef::from_lit("Misdirected Request");
case 425:
// https://tools.ietf.org/html/rfc8470
return StringRef::from_lit("Too Early");
case 426: case 426:
return StringRef::from_lit("Upgrade Required"); return StringRef::from_lit("Upgrade Required");
case 428: case 428:
@@ -386,6 +389,21 @@ void copy_headers_to_nva_internal(std::vector<nghttp2_nv> &nva,
case HD_TRANSFER_ENCODING: case HD_TRANSFER_ENCODING:
case HD_UPGRADE: case HD_UPGRADE:
continue; continue;
case HD_EARLY_DATA:
if (flags & HDOP_STRIP_EARLY_DATA) {
continue;
}
break;
case HD_SEC_WEBSOCKET_ACCEPT:
if (flags & HDOP_STRIP_SEC_WEBSOCKET_ACCEPT) {
continue;
}
break;
case HD_SEC_WEBSOCKET_KEY:
if (flags & HDOP_STRIP_SEC_WEBSOCKET_KEY) {
continue;
}
break;
case HD_FORWARDED: case HD_FORWARDED:
if (flags & HDOP_STRIP_FORWARDED) { if (flags & HDOP_STRIP_FORWARDED) {
continue; continue;
@@ -480,6 +498,16 @@ void build_http1_headers_from_headers(DefaultMemchunks *buf,
case HD_SERVER: case HD_SERVER:
case HD_UPGRADE: case HD_UPGRADE:
continue; continue;
case HD_EARLY_DATA:
if (flags & HDOP_STRIP_EARLY_DATA) {
continue;
}
break;
case HD_TRANSFER_ENCODING:
if (flags & HDOP_STRIP_TRANSFER_ENCODING) {
continue;
}
break;
case HD_FORWARDED: case HD_FORWARDED:
if (flags & HDOP_STRIP_FORWARDED) { if (flags & HDOP_STRIP_FORWARDED) {
continue; continue;
@@ -821,10 +849,20 @@ int lookup_token(const uint8_t *name, size_t namelen) {
return HD_FORWARDED; return HD_FORWARDED;
} }
break; break;
case 'l':
if (util::streq_l(":protoco", name, 8)) {
return HD__PROTOCOL;
}
break;
} }
break; break;
case 10: case 10:
switch (name[9]) { switch (name[9]) {
case 'a':
if (util::streq_l("early-dat", name, 9)) {
return HD_EARLY_DATA;
}
break;
case 'e': case 'e':
if (util::streq_l("keep-aliv", name, 9)) { if (util::streq_l("keep-aliv", name, 9)) {
return HD_KEEP_ALIVE; return HD_KEEP_ALIVE;
@@ -924,6 +962,20 @@ int lookup_token(const uint8_t *name, size_t namelen) {
return HD_X_FORWARDED_PROTO; return HD_X_FORWARDED_PROTO;
} }
break; break;
case 'y':
if (util::streq_l("sec-websocket-ke", name, 16)) {
return HD_SEC_WEBSOCKET_KEY;
}
break;
}
break;
case 20:
switch (name[19]) {
case 't':
if (util::streq_l("sec-websocket-accep", name, 19)) {
return HD_SEC_WEBSOCKET_ACCEPT;
}
break;
} }
break; break;
} }
@@ -1313,7 +1365,8 @@ std::string path_join(const StringRef &base_path, const StringRef &base_query,
} }
bool expect_response_body(int status_code) { bool expect_response_body(int status_code) {
return status_code / 100 != 1 && status_code != 304 && status_code != 204; return status_code == 101 ||
(status_code / 100 != 1 && status_code != 304 && status_code != 204);
} }
bool expect_response_body(const std::string &method, int status_code) { bool expect_response_body(const std::string &method, int status_code) {
@@ -1811,6 +1864,25 @@ bool contains_trailers(const StringRef &s) {
} }
} }
StringRef make_websocket_accept_token(uint8_t *dest, const StringRef &key) {
static constexpr uint8_t magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
std::array<uint8_t, base64::encode_length(16) + str_size(magic)> s;
auto p = std::copy(std::begin(key), std::end(key), std::begin(s));
std::copy_n(magic, str_size(magic), p);
std::array<uint8_t, 20> h;
if (util::sha1(h.data(), StringRef{std::begin(s), std::end(s)}) != 0) {
return StringRef{};
}
auto end = base64::encode(std::begin(h), std::end(h), dest);
return StringRef{dest, end};
}
bool legacy_http1(int major, int minor) {
return major <= 0 || (major == 1 && minor == 0);
}
} // namespace http2 } // namespace http2
} // namespace nghttp2 } // namespace nghttp2

View File

@@ -41,6 +41,7 @@
#include "memchunk.h" #include "memchunk.h"
#include "template.h" #include "template.h"
#include "allocator.h" #include "allocator.h"
#include "base64.h"
namespace nghttp2 { namespace nghttp2 {
@@ -203,9 +204,22 @@ enum HeaderBuildOp {
// Via header fields must be stripped. If this flag is not set, all // Via header fields must be stripped. If this flag is not set, all
// Via header fields other than last one are added. // Via header fields other than last one are added.
HDOP_STRIP_VIA = 1 << 3, HDOP_STRIP_VIA = 1 << 3,
// Early-Data header fields must be stripped. If this flag is not
// set, all Early-Data header fields are added.
HDOP_STRIP_EARLY_DATA = 1 << 4,
// Strip above all header fields. // Strip above all header fields.
HDOP_STRIP_ALL = HDOP_STRIP_FORWARDED | HDOP_STRIP_X_FORWARDED_FOR | HDOP_STRIP_ALL = HDOP_STRIP_FORWARDED | HDOP_STRIP_X_FORWARDED_FOR |
HDOP_STRIP_X_FORWARDED_PROTO | HDOP_STRIP_VIA, HDOP_STRIP_X_FORWARDED_PROTO | HDOP_STRIP_VIA |
HDOP_STRIP_EARLY_DATA,
// Sec-WebSocket-Accept header field must be stripped. If this flag
// is not set, all Sec-WebSocket-Accept header fields are added.
HDOP_STRIP_SEC_WEBSOCKET_ACCEPT = 1 << 5,
// Sec-WebSocket-Key header field must be stripped. If this flag is
// not set, all Sec-WebSocket-Key header fields are added.
HDOP_STRIP_SEC_WEBSOCKET_KEY = 1 << 6,
// Transfer-Encoding header field must be stripped. If this flag is
// not set, all Transfer-Encoding header fields are added.
HDOP_STRIP_TRANSFER_ENCODING = 1 << 7,
}; };
// Appends headers in |headers| to |nv|. |headers| must be indexed // Appends headers in |headers| to |nv|. |headers| must be indexed
@@ -293,6 +307,7 @@ enum {
HD__HOST, HD__HOST,
HD__METHOD, HD__METHOD,
HD__PATH, HD__PATH,
HD__PROTOCOL,
HD__SCHEME, HD__SCHEME,
HD__STATUS, HD__STATUS,
HD_ACCEPT_ENCODING, HD_ACCEPT_ENCODING,
@@ -304,6 +319,7 @@ enum {
HD_CONTENT_TYPE, HD_CONTENT_TYPE,
HD_COOKIE, HD_COOKIE,
HD_DATE, HD_DATE,
HD_EARLY_DATA,
HD_EXPECT, HD_EXPECT,
HD_FORWARDED, HD_FORWARDED,
HD_HOST, HD_HOST,
@@ -313,6 +329,8 @@ enum {
HD_LINK, HD_LINK,
HD_LOCATION, HD_LOCATION,
HD_PROXY_CONNECTION, HD_PROXY_CONNECTION,
HD_SEC_WEBSOCKET_ACCEPT,
HD_SEC_WEBSOCKET_KEY,
HD_SERVER, HD_SERVER,
HD_TE, HD_TE,
HD_TRAILER, HD_TRAILER,
@@ -416,6 +434,16 @@ StringRef copy_lower(BlockAllocator &balloc, const StringRef &src);
// Returns true if te header field value |s| contains "trailers". // Returns true if te header field value |s| contains "trailers".
bool contains_trailers(const StringRef &s); bool contains_trailers(const StringRef &s);
// Creates Sec-WebSocket-Accept value for |key|. The capacity of
// buffer pointed by |dest| must have at least 24 bytes (base64
// encoded length of 16 bytes data). It returns empty string in case
// of error.
StringRef make_websocket_accept_token(uint8_t *dest, const StringRef &key);
// Returns true if HTTP version represents pre-HTTP/1.1 (e.g.,
// HTTP/0.9 or HTTP/1.0).
bool legacy_http1(int major, int minor);
} // namespace http2 } // namespace http2
} // namespace nghttp2 } // namespace nghttp2

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