Compare commits

...

179 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
d1f9f9a3aa makerelease.sh: Add autoreconf 2016-02-26 00:00:52 +09:00
Tatsuhiro Tsujikawa
2415a22757 h2load: Fix uninitialized fields 2016-02-26 00:00:24 +09:00
Tatsuhiro Tsujikawa
887d4d2a41 Update bash_completion 2016-02-25 23:35:44 +09:00
Tatsuhiro Tsujikawa
1c8e625045 Update man pages 2016-02-25 23:35:23 +09:00
Tatsuhiro Tsujikawa
36e931e0d7 Bump up version number to 1.8.0, LT revision to 19:0:5 2016-02-25 23:33:16 +09:00
Tatsuhiro Tsujikawa
31d4077638 Remove files copied in the rule for apiref.rst target 2016-02-25 23:18:21 +09:00
Tatsuhiro Tsujikawa
c098b4ac70 nghttpx: Remove --backend-tls-session-cache-per-worker option 2016-02-25 22:46:25 +09:00
Tatsuhiro Tsujikawa
32446a5197 Revert "Update doc"
This reverts commit 8aac5d6af2.
2016-02-25 21:19:38 +09:00
Tatsuhiro Tsujikawa
40c1b29f36 Handle extension frame in session_inbound_frame_reset 2016-02-25 21:18:59 +09:00
Tatsuhiro Tsujikawa
bc933e9981 src: Use lowercase to show it is not the name of frame 2016-02-25 21:18:09 +09:00
Tatsuhiro Tsujikawa
ba34e911e1 Merge branch 'simple-extensions' 2016-02-25 01:00:35 +09:00
Tatsuhiro Tsujikawa
8aac5d6af2 Update doc 2016-02-25 00:58:50 +09:00
Tatsuhiro Tsujikawa
56bdfd1df2 Revert "Handle extension frame in session_inbound_frame_reset"
This reverts commit dbffb8995b.
2016-02-25 00:58:24 +09:00
Tatsuhiro Tsujikawa
dbffb8995b Handle extension frame in session_inbound_frame_reset 2016-02-25 00:45:24 +09:00
Tatsuhiro Tsujikawa
ebfae904ab Fix typo 2016-02-25 00:32:17 +09:00
Tatsuhiro Tsujikawa
827abb57e9 Simplified bitfield calculation of extension frame 2016-02-24 23:59:01 +09:00
Tatsuhiro Tsujikawa
9aee43f7d8 Update doc for extension frames 2016-02-24 23:51:00 +09:00
Tatsuhiro Tsujikawa
34bf153653 Merge branch 'master' into simple-extensions 2016-02-24 23:21:03 +09:00
Tatsuhiro Tsujikawa
2782ef67de nghttpd: Remove unused function 2016-02-23 01:18:52 +09:00
Tatsuhiro Tsujikawa
9d15f9b00d nghttpd: Start SETTINGS timer after it is written to output buffer 2016-02-23 01:18:07 +09:00
Tatsuhiro Tsujikawa
3e72711e23 Cap 100 limit for remembering idle streams 2016-02-23 01:09:45 +09:00
Tatsuhiro Tsujikawa
f4bb8776d0 mruby: Clean up mrbgems as well 2016-02-23 01:06:23 +09:00
Tatsuhiro Tsujikawa
95ffb4565f Update nghttpx documentation 2016-02-21 18:20:53 +09:00
Tatsuhiro Tsujikawa
f3a415f623 Update nghttpx documentation 2016-02-21 17:47:27 +09:00
Tatsuhiro Tsujikawa
936d4aca1a Update h2load documentation 2016-02-21 17:46:48 +09:00
Tatsuhiro Tsujikawa
216ae0a328 Update nghttpx documentation 2016-02-21 17:36:10 +09:00
Tatsuhiro Tsujikawa
9672bc322f src: Remove unused functions 2016-02-21 16:51:46 +09:00
Tatsuhiro Tsujikawa
b68be1e1fb src: Make token of type int32_t; we have no reason to use int16_t 2016-02-21 16:44:00 +09:00
Tatsuhiro Tsujikawa
f2a7275700 nghttpx: Cache TLS session inside DownstreamAddr object 2016-02-21 16:35:43 +09:00
Tatsuhiro Tsujikawa
177d0a513f nghttpx: More logging for backend connection initiation 2016-02-21 16:11:50 +09:00
Tatsuhiro Tsujikawa
dfc02843b6 src: Rename and rewrite numeric_hostport as to_numeric_addr and support AF_UNIX path 2016-02-21 15:28:11 +09:00
Tatsuhiro Tsujikawa
11c8803b92 nghttpx: Worker wide blocker which is used when socket(2) is failed 2016-02-21 15:27:19 +09:00
Tatsuhiro Tsujikawa
c9a4f293a1 nghttpx: ConnectBlocker per backend address 2016-02-21 14:53:06 +09:00
Tatsuhiro Tsujikawa
61579ad20f nghttpx: Use StringRef for shrpx::add_header 2016-02-20 23:30:02 +09:00
Tatsuhiro Tsujikawa
9678daa46a nghttpx: Rename index_headers() as parse_content_length() 2016-02-20 23:30:02 +09:00
Tatsuhiro Tsujikawa
23ecfd412d nghttpx: Fix mruby compile error, clean up add_header interface 2016-02-20 23:30:02 +09:00
Tatsuhiro Tsujikawa
3ff148811b nghttpx: Use StringRef for add_hedeader 2016-02-20 23:30:02 +09:00
Tatsuhiro Tsujikawa
6f1347fc8b nghttpx: Tokenize trailer field as well so that we can ditch prohibited headers in HTTP/2 2016-02-20 23:30:02 +09:00
Tatsuhiro Tsujikawa
1703201084 nghttpx: Get rid of hdidx 2016-02-20 23:30:02 +09:00
Tatsuhiro Tsujikawa
7921029e33 Tokenize extra HTTP header fields
The extra HTTP header fields are compiled from
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers,
https://en.wikipedia.org/wiki/List_of_HTTP_header_fields, and
https://www.owasp.org/index.php/List_of_useful_HTTP_headers.
2016-02-20 23:30:02 +09:00
Tatsuhiro Tsujikawa
b7159f80b2 Eliminate the possibility of nghttp2_stream.cycle overflow 2016-02-18 23:56:29 +09:00
Tatsuhiro Tsujikawa
f0b5a8db8c Add unistd.h to test initgroups() declaration 2016-02-17 00:26:34 +09:00
Tatsuhiro Tsujikawa
094168a58f Merge branch 'Lekensteyn-tests-fixes' 2016-02-16 00:08:08 +09:00
Peter Wu
63e43bff99 tests: remove unused macros
Since v0.6.2-7-g1d138ac ("Unify DATA and other frames in
nghttp2_outbound_item and save malloc()"), the macros are unused and the
builds fails on -Werror=unused-macros.
2016-02-15 10:20:13 +01:00
Tatsuhiro Tsujikawa
02b7116d42 Merge branch 'nghttpx-replace-unique-ptr-char-with-immutable-string' 2016-02-14 22:36:48 +09:00
Tatsuhiro Tsujikawa
aa3373a107 nghttpx: Use ImmutableString for mruby_file 2016-02-14 22:27:59 +09:00
Tatsuhiro Tsujikawa
7aabc6b125 nghttpx: Use ImmutableString for user 2016-02-14 22:21:55 +09:00
Tatsuhiro Tsujikawa
466e4b7a1e nghttpx: Use ImmutableString for conf_path 2016-02-14 22:20:10 +09:00
Tatsuhiro Tsujikawa
76a425226f nghttpx: Use ImmutableString for pid_file 2016-02-14 22:17:10 +09:00
Tatsuhiro Tsujikawa
2b707bff27 nghttpx: Use ImmutableString for log file 2016-02-14 22:17:10 +09:00
Tatsuhiro Tsujikawa
9055323b67 nghttpx: Use ImmutableString for request_header_file and response_header_file 2016-02-14 22:17:10 +09:00
Tatsuhiro Tsujikawa
67804cfc8c nghttpx: Use ImmutableString for ciphers 2016-02-14 22:17:10 +09:00
Tatsuhiro Tsujikawa
2344932b45 nghttpx: Use ImmutableString for dh_param_file 2016-02-14 22:17:10 +09:00
Tatsuhiro Tsujikawa
35ebdd35bc nghttpx: Use ImmutableString for private_key_file 2016-02-14 22:17:10 +09:00
Tatsuhiro Tsujikawa
ac81003669 nghttpx: Use ImmutableString for cert_file 2016-02-14 22:17:10 +09:00
Tatsuhiro Tsujikawa
c999987baf nghttpx: Use ImmutableString for private_key_file 2016-02-14 22:17:10 +09:00
Tatsuhiro Tsujikawa
529a59d309 nghttpx: Use ImmutableString for tls.client_verify.cacert 2016-02-14 22:17:10 +09:00
Tatsuhiro Tsujikawa
52f6417813 nghttpx: Use ImmutableString for tls.cacert 2016-02-14 22:17:00 +09:00
Tatsuhiro Tsujikawa
660bc389e6 nghttpx: Use ImmutableString for fetch_ocsp_response_file 2016-02-14 21:01:54 +09:00
Tatsuhiro Tsujikawa
bfc26e8299 nghttpx: Use ImmutableString to store memcached server host 2016-02-14 20:59:10 +09:00
Tatsuhiro Tsujikawa
47106c0756 Merge branch 'nghttpx-refactor-downstream-addr-group' 2016-02-14 20:49:30 +09:00
Tatsuhiro Tsujikawa
49fa914db5 nghttpx: Use StringRef for string parameters in match_downstream_addr_group 2016-02-14 20:48:06 +09:00
Tatsuhiro Tsujikawa
93eabc642b nghttpx: Use StringRef for parameter in Router::match 2016-02-14 19:07:22 +09:00
Tatsuhiro Tsujikawa
2d273f8237 nghttpx: Use StringRef for pattern paramter in Router::add_route 2016-02-14 18:55:53 +09:00
Tatsuhiro Tsujikawa
a53f0f0a17 nghttpx: Refactor DownstreamAddrGroup and router API 2016-02-14 18:47:24 +09:00
Tatsuhiro Tsujikawa
1bd98dcf4f nghttpx: Remove user defined ctor/assignment op from DownstreamAddr 2016-02-14 18:31:08 +09:00
Tatsuhiro Tsujikawa
eebed206c9 Add Architecture doc 2016-02-14 18:23:28 +09:00
Tatsuhiro Tsujikawa
fe74600a5f List all contributors in AUTHORS 2016-02-14 17:40:58 +09:00
Tatsuhiro Tsujikawa
08e2d7cdb3 Merge branch 'Lekensteyn-build-fixes' 2016-02-14 16:59:30 +09:00
Peter Wu
2593036053 integration-tests: support out-of-tree tests
`go test` requires both config.go and the test files in the same
directory. For out-of-tree builds, config.go is normally not placed next
to the source files, so copy the tests to the build directory as a
workaround.
2016-02-13 20:11:50 +01:00
Peter Wu
a6effb4d23 doc: fix out-of-tree doc builds
Fixes multiple errors while making docs:

    Could not import extension sphinxcontrib.rubydomain (exception: No module named 'sphinxcontrib')

and

    ../../doc/sources/index.rst:15: WARNING: toctree contains reference to nonexisting document 'nghttp.1'
    ../../doc/sources/index.rst:15: WARNING: toctree contains reference to nonexisting document 'nghttpd.1'
    ../../doc/sources/index.rst:15: WARNING: toctree contains reference to nonexisting document 'nghttpx.1'
    ../../doc/sources/index.rst:15: WARNING: toctree contains reference to nonexisting document 'h2load.1'
    ../../doc/sources/index.rst:15: WARNING: toctree contains reference to nonexisting document 'programmers-guide'
2016-02-13 20:11:50 +01:00
Peter Wu
17215002a1 examples: fix compile warnings
Fixes the following two warnings:

    examples/client.c:292:0: error: macro "MAX_OUTLEN" is not used [-Werror=unused-macros]
    examples/tiny-nghttpd.c:298:13: error: function declaration isn’t a prototype [-Werror=strict-prototypes]

Caught using cmake as the autoconf check fails due to unused macros
(HAVE_xxx in conftest.c) and a main function without parameters
respectively.
2016-02-13 20:11:50 +01:00
Peter Wu
0e469ed221 Fix typo in HAVE_CONFIG_H name
Only used by lib/nghttp2_npn.c where the presence of config.h does not
seem to make a difference though.
2016-02-13 20:11:50 +01:00
Tatsuhiro Tsujikawa
093eb51f8c Update default cipher list 2016-02-14 00:44:50 +09:00
Tatsuhiro Tsujikawa
5f1866fd6b Update man pages 2016-02-14 00:29:07 +09:00
Tatsuhiro Tsujikawa
d8c8a4631d nghttpx: Interleave text/html pushed resources with associated resource 2016-02-14 00:28:08 +09:00
Tatsuhiro Tsujikawa
6b12f17f44 Wrap AM_PATH_XML2 by m4_ifdef to handle the case when AM_PATH_XML2 is not found 2016-02-14 00:05:12 +09:00
Tatsuhiro Tsujikawa
eb0c82d91f nghttpx: More log output when resolving addresses for better debugging 2016-02-13 23:21:32 +09:00
Tatsuhiro Tsujikawa
7adfa5dea7 Add note about --enable-app automatic behaviour 2016-02-13 22:39:24 +09:00
Tatsuhiro Tsujikawa
17758126fa nghttpx: Add headers given in add-response-headers for mruby response 2016-02-13 22:31:38 +09:00
Tatsuhiro Tsujikawa
b440f585bc nghttpx: Use Header to store custom request/response header fields 2016-02-13 22:19:05 +09:00
Tatsuhiro Tsujikawa
63a13ccb18 src: Add constexpr to StringRef ctors 2016-02-13 19:15:14 +09:00
Tatsuhiro Tsujikawa
72877379ec nghttpx: Deprecate --backend-ipv4 and --backend-ipv6 in favor of --backend-address-family 2016-02-13 19:09:39 +09:00
Tatsuhiro Tsujikawa
8449958425 doc: Mention encryption for memcached connections 2016-02-13 18:50:15 +09:00
Tatsuhiro Tsujikawa
9037641592 Merge branch 'nghttpx-memcached-tls' 2016-02-13 18:47:06 +09:00
Tatsuhiro Tsujikawa
c0078ab45a nghttpx: Add options to specify address family of memcached connections 2016-02-13 18:46:07 +09:00
Tatsuhiro Tsujikawa
3a41e4dd1a nghttpx: Add encryption support for TLS ticket key retrieval 2016-02-13 18:46:07 +09:00
Tatsuhiro Tsujikawa
3297a303bf nghttpx: Add client auth options for session cache memcached TLS connection 2016-02-13 18:46:07 +09:00
Tatsuhiro Tsujikawa
f1580f95d4 nghttpx: Add TLS support for session cache memcached connection 2016-02-13 18:46:07 +09:00
Tatsuhiro Tsujikawa
1e150bcf61 Merge branch 'jay-refactor-blacklist' 2016-02-13 17:46:11 +09:00
Jay Satiro
ca371e3ba9 nghttpx: Refactor blacklisted cipher suite check 2016-02-12 21:46:29 -05:00
Tatsuhiro Tsujikawa
61dda40b44 Don't pass NULL to memcpy 2016-02-12 22:31:47 +09:00
Tatsuhiro Tsujikawa
5ad753b90c Merge branch 'limit-incoming-headers' 2016-02-11 23:21:02 +09:00
Tatsuhiro Tsujikawa
0a1beea13a asio: client: Limit incoming response header field buffer size 2016-02-11 23:20:31 +09:00
Tatsuhiro Tsujikawa
00e722f02c Add warning 2016-02-11 23:20:31 +09:00
Tatsuhiro Tsujikawa
ff22862b9d nghttp: Limit incoming header field buffer 2016-02-11 23:20:31 +09:00
Tatsuhiro Tsujikawa
b2264ad57e asio: server: Limit incoming request header field buffer size 2016-02-11 23:20:31 +09:00
Tatsuhiro Tsujikawa
b0227d4051 nghttpd: Limit request header buffer 2016-02-11 23:20:31 +09:00
Tatsuhiro Tsujikawa
28b643e531 Fix configure script for non-gcc, clang build 2016-02-11 23:05:16 +09:00
Tatsuhiro Tsujikawa
82f942c3a3 nghttpx: Parameterize configuration values for client side TLS context 2016-02-11 18:34:31 +09:00
Tatsuhiro Tsujikawa
e4a727f86c nghttpx: Cache TLS client session after initial handshake was done 2016-02-11 17:56:20 +09:00
Tatsuhiro Tsujikawa
b624ca6dcd nghttpx: Rename client TLS session cache field 2016-02-11 17:12:57 +09:00
Tatsuhiro Tsujikawa
ba4c268172 nghttpx: Single SSL_SESSION cache entry for each address 2016-02-11 17:07:48 +09:00
Tatsuhiro Tsujikawa
00175eac33 nghttpx: Use Address* as a key for client side session cache 2016-02-11 12:40:15 +09:00
Tatsuhiro Tsujikawa
396dde1347 Mention libspdylay-dev package availability 2016-02-10 21:42:32 +09:00
Tatsuhiro Tsujikawa
042a59117d Merge pull request #504 from davidjb/master
Document compiling apps and include h2load in configure
2016-02-10 21:35:54 +09:00
David Beitey
b8717208c7 Document compiling apps and include h2load in configure 2016-02-10 08:37:43 +10:00
Tatsuhiro Tsujikawa
c3a5fe7185 Update bash_completion 2016-02-07 21:24:29 +09:00
Tatsuhiro Tsujikawa
c8b6a79225 Update man pages 2016-02-07 21:24:11 +09:00
Tatsuhiro Tsujikawa
92e66fc167 Bump up version number to 1.8.0-DEV 2016-02-07 21:20:44 +09:00
Tatsuhiro Tsujikawa
64ffc1fc73 Update README.rst 2016-02-07 21:20:05 +09:00
Tatsuhiro Tsujikawa
304ff6a6f9 Don't send extension frame in closing state 2016-02-07 21:12:36 +09:00
Tatsuhiro Tsujikawa
fc39f2d9d2 Merge branch 'master' into simple-extensions 2016-02-07 21:09:08 +09:00
Tatsuhiro Tsujikawa
0d806978e6 nghttpx: Set HTTP/1 backend read buffer to 16k 2016-02-07 21:07:27 +09:00
Tatsuhiro Tsujikawa
62c43ce2be nghttpx: Remove rb_ from HTTP/2 backend session 2016-02-07 19:20:17 +09:00
Tatsuhiro Tsujikawa
88eaeb5d1c nghttpx: Use memchunks for HTTP/2 backend 2016-02-07 18:54:44 +09:00
Tatsuhiro Tsujikawa
60c0c2dd56 src: Code cleanup 2016-02-07 18:41:38 +09:00
Tatsuhiro Tsujikawa
6c147aa1c5 nghttpx: Remove unnecessary condition 2016-02-07 18:39:06 +09:00
Tatsuhiro Tsujikawa
2a9b23bfab nghttpx: Store pointer to DownstreamAddr 2016-02-07 18:38:06 +09:00
Tatsuhiro Tsujikawa
4fb4617d20 src: Parameterize CharT 2016-02-07 18:16:47 +09:00
Tatsuhiro Tsujikawa
ede0f6aa32 src: Remove verbose const 2016-02-07 18:12:57 +09:00
Tatsuhiro Tsujikawa
4e7271a88f nghttpx: Fix regression which breaks WebSocket upgrade 2016-02-07 17:59:38 +09:00
Tatsuhiro Tsujikawa
6d49110a33 Rename FrontendAddr as UpstreamAddr 2016-02-07 17:51:53 +09:00
Tatsuhiro Tsujikawa
b540aa34d0 Merge branch 'nghttpx-backend-h1-tls' 2016-02-07 17:43:40 +09:00
Tatsuhiro Tsujikawa
15fa38c72f nghttpx: Rename backend_session_cache_per_worker as downstream_session_cache_per_worker 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
e7de5e9f6c nghttpx: Rename cl_tls_session as downstream_tls_session 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
5c10534b88 nghttpx: Fix crash when reusing cached SSL session 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
b3e5d49a3e Update doc 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
6806196404 nghttpx: Update doc for HTTP/1 TLS backend connections 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
2e38208d74 nghttpx: Fixups for HTTP/1 backend TLS support 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
cde79052dd nghttpx: Slightly faster version of HTTP/1 backend 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
e763770f3e nghttpx: Add option to specify maximum number of session cache 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
26d49c1dc3 nghttpx: Cache client session 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
bb4e2f6a24 nghttpx: Add TLS support for HTTP/1 backend 2016-02-07 17:43:30 +09:00
Tatsuhiro Tsujikawa
344cc1b5c3 Merge branch 'Sp1l-master' 2016-02-07 17:41:04 +09:00
Tatsuhiro Tsujikawa
21f9b6d8bb Merge branch 'master' of https://github.com/Sp1l/nghttp2 into Sp1l-master 2016-02-07 17:35:57 +09:00
Tatsuhiro Tsujikawa
024d0d09ee nghttpx: Fix unexpected failure due to missing address family 2016-02-06 23:28:04 +09:00
Bernard Spil
e4b2847d31 Don't check for dlopen/libdl on *BSD
This makes linking fail on -ldl as there is no libdl on in /usr/lib or /usr/local/lib on *BSD
Tested (and part of the proposed nghttp2 1.7.0) on [https://reviews.freebsd.org/D5218|FreeBSD]
2016-02-06 14:36:27 +01:00
Tatsuhiro Tsujikawa
ee07694783 nghttpx: Add request-header-field-buffer and max-request-header-fields options
This commit adds request-header-field-buffer and
max-request-header-fields, and deprecates header-field-buffer and
max-header-fields options.
2016-02-06 17:22:23 +09:00
Tatsuhiro Tsujikawa
8741503db1 nghttpx: Add --no-http2-cipher-black-list to allow black listed cipher suite 2016-02-06 17:05:14 +09:00
Tatsuhiro Tsujikawa
eec409dba7 nghttpx: Limit header fields from backend 2016-02-06 12:27:01 +09:00
Tatsuhiro Tsujikawa
95ca4f55d5 asio: client: Fix connect timeout does not work, return from cb if session stopped
This change removed client::session::connect_timeout() functon, and
connect timeout should be given to client::session constructor.  This
is required since async operation starts in the constructor.
2016-02-06 11:05:13 +09:00
Tatsuhiro Tsujikawa
231665d67b Don't use ac_save_* since they are overwritten by macro 2016-02-03 00:48:47 +09:00
Tatsuhiro Tsujikawa
4c05558273 Evaluate nghttp2_session_want_read and nghttp2_session_want_write when determining session is about to close 2016-02-03 00:25:11 +09:00
Tatsuhiro Tsujikawa
35c3b36549 nghttpx: Document special value localhost in Forwarded "by" and "for" params 2016-02-01 23:34:07 +09:00
Tatsuhiro Tsujikawa
03872bfacd nghttpx: Don't quote Forwarded "by" parameter if it is special value "localhost" 2016-02-01 23:31:21 +09:00
Tatsuhiro Tsujikawa
5e9bcbec9a nghttpx: Fix bug that IPv6 address in Forwarded "for" is not quoted-string 2016-02-01 23:29:17 +09:00
Tatsuhiro Tsujikawa
aa07fe7fa6 nghttpx: Support multiple frontend addresses
This commit allows nghttpx to listen to multiple address and port pair
by specifying -f option multiple times.
2016-02-01 23:10:29 +09:00
Tatsuhiro Tsujikawa
1d99b425ca Use ac_save_LIBS instead of LIBS_OLD 2016-01-30 18:46:17 +09:00
Tatsuhiro Tsujikawa
7a6a59178a Don't taint CXXFLAGS from AX_CXX_COMPILE_STDCXX_11 2016-01-30 18:42:48 +09:00
Tatsuhiro Tsujikawa
4e44fccdcf Fix compile error with gcc-6 which enables C++14 by default 2016-01-30 18:41:27 +09:00
Tatsuhiro Tsujikawa
703c77ec89 Fix markdown style linking 2016-01-29 12:36:15 +09:00
Tatsuhiro Tsujikawa
a06af3fa85 Add doc about release scheduling and versioning scheme 2016-01-29 12:35:09 +09:00
Tatsuhiro Tsujikawa
686a303cb5 Add script to ensure that packaging is good 2016-01-27 23:12:38 +09:00
Tatsuhiro Tsujikawa
b95df43384 Add genauthoritychartbl.py 2016-01-27 23:06:10 +09:00
Tatsuhiro Tsujikawa
5659e295b3 nghttpd: Add trailer header field to status responses 2016-01-27 22:47:30 +09:00
Tatsuhiro Tsujikawa
5b195092e1 nghttpd: Add -w and -W options to change window size 2016-01-27 22:34:17 +09:00
Tatsuhiro Tsujikawa
85bb37ab7c Enable ConstructorInitializerAllOnOneLineOrOnePerLine for better diff 2016-01-27 21:14:07 +09:00
Tatsuhiro Tsujikawa
c5f3eee3be Update http-parser to 4e382f96e6d3321538a78f2c7f9506d4e79b08d6 2016-01-27 20:50:08 +09:00
Tatsuhiro Tsujikawa
1cfdf386ff src: Faster base64 2016-01-27 15:31:09 +09:00
Tatsuhiro Tsujikawa
6d8fe72174 src: Faster percent encode/deocde 2016-01-27 15:31:09 +09:00
Tatsuhiro Tsujikawa
98253b1d0d nghttpx: Use DefaultMemchunks as HTTP/2 and SPDY frontend response buffer 2016-01-27 15:28:01 +09:00
Tatsuhiro Tsujikawa
ad93cea544 nghttpx: Fix possible data loss on backend connection upgrade 2016-01-27 15:26:46 +09:00
Tatsuhiro Tsujikawa
1739b5a0e6 nghttpx: Don't read frontend socket if read watcher is stopped 2016-01-27 15:26:06 +09:00
Tatsuhiro Tsujikawa
9ef8e24049 Merge pull request #490 from tavrez/master
Fixed Windows makefile version detection
2016-01-26 19:53:24 +09:00
Reza Tavakoli
7fbbaf01a9 Merge pull request #1 from tavrez/patch-1
Fixing window makefile version detection
2016-01-26 14:00:21 +03:30
Reza Tavakoli
5a6f312182 Fixing window makefile version detection 2016-01-26 13:57:21 +03:30
Tatsuhiro Tsujikawa
2b441ef9af Bump up version number to 1.7.1-DEV 2016-01-25 19:56:59 +09:00
Tatsuhiro Tsujikawa
e14da859b6 Merge branch 'master' into simple-extensions 2016-01-11 16:39:35 +09:00
Tatsuhiro Tsujikawa
0248d979fe Add missing nghttp2_option_set_user_recv_extension_type.rst 2016-01-10 17:08:03 +09:00
Tatsuhiro Tsujikawa
0caefe20ef Merge branch 'master' into simple-extensions 2016-01-09 19:08:28 +09:00
Tatsuhiro Tsujikawa
9c84f60ba0 Merge branch 'master' into simple-extensions 2015-12-04 23:48:40 +09:00
Tatsuhiro Tsujikawa
83cc2511e3 Remove flags parameter from nghttp2_pack_extension_callback
It has no usecase at the moment.  It is most likely that applications
know the flags when it submitted extension frame, no need to modify it
later.  Possibly feature bloat.
2015-11-17 21:29:21 +09:00
Tatsuhiro Tsujikawa
eb4e402aae Merge branch 'master' into simple-extensions 2015-11-14 22:31:52 +09:00
Tatsuhiro Tsujikawa
5d611d2e24 Merge branch 'master' into simple-extensions 2015-10-29 23:24:34 +09:00
Tatsuhiro Tsujikawa
837e716306 Fix compile error with gcc 2015-10-15 00:30:42 +09:00
Tatsuhiro Tsujikawa
061a557839 Add nghttp2_option_set_user_recv_extension_type to opt-in incoming extension type 2015-10-15 00:17:07 +09:00
Tatsuhiro Tsujikawa
d9893d014c Add tests 2015-10-11 17:46:23 +09:00
Tatsuhiro Tsujikawa
3785cf07ba Add simple HTTP/2 extension framework
Application can utilize this framework to send/receive user defined
extension frames.  These frames are expected not to change existing
protocol behaviour.
2015-10-11 17:46:23 +09:00
150 changed files with 5868 additions and 2807 deletions

View File

@@ -17,7 +17,7 @@ BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: false

81
AUTHORS
View File

@@ -1 +1,80 @@
Tatsuhiro Tsujikawa <t-tujikawa at users dot sourceforge dot net>
nghttp2 project was started as a fork of spdylay project [1]. Both
projects were started by Tatsuhiro Tsujikawa, who is still the main
author of these projects. Meanwhile, we have many contributions, and
we are not here without them. We sincerely thank you to all who made
a contribution. Here is the all individuals/organizations who
contributed to nghttp2 and spdylay project at which we forked. These
names are retrieved from git commit log. If you have made a
contribution, but you are missing in the list, please let us know via
github issues [2].
[1] https://github.com/tatsuhiro-t/spdylay
[2] https://github.com/tatsuhiro-t/nghttp2/issues
--------
187j3x1
Alek Storm
Alex Nalivko
Alexis La Goutte
Anders Bakken
Andreas Pohl
Andy Davies
Ant Bryan
Bernard Spil
Brian Card
Daniel Stenberg
Dave Reisner
David Beitey
David Weekly
Etienne Cimon
Fabian Möller
Fabian Wiesel
Gabi Davar
Janusz Dziemidowicz
Jay Satiro
Jim Morrison
José F. Calcerrada
Kamil Dudka
Kazuho Oku
Kenny (kang-yen) Peng
Kenny Peng
Kit Chan
Kyle Schomp
Lucas Pardue
MATSUMOTO Ryosuke
Mike Frysinger
Nicholas Hurley
Nora Shoemaker
Peeyush Aggarwal
Peter Wu
Piotr Sikora
Raul Gutierrez Segales
Remo E
Reza Tavakoli
Ross Smith II
Scott Mitchell
Stefan Eissing
Stephen Ludin
Sunpoet Po-Chuan Hsieh
Svante Signell
Syohei YOSHIDA
Tatsuhiko Kubo
Tatsuhiro Tsujikawa
Tom Harwood
Tomasz Buchert
Vernon Tang
Viacheslav Biriukov
Viktor Szépe
Xiaoguang Sun
Zhuoyun Wei
acesso
ayanamist
bxshi
es
fangdingjun
kumagi
mod-h2-dev
moparisthebest
snnn
yuuki-kodama

View File

@@ -1,6 +1,7 @@
The MIT License
Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -58,9 +58,9 @@ To build the documentation, you need to install:
* sphinx (http://sphinx-doc.org/)
To build and run the application programs (``nghttp``, ``nghttpd`` and
``nghttpx``) in the ``src`` directory, the following packages are
required:
To build and run the application programs (``nghttp``, ``nghttpd``,
``nghttpx`` and ``h2load``) in the ``src`` directory, the following packages
are required:
* OpenSSL >= 1.0.1
* libev >= 4.15
@@ -110,8 +110,9 @@ If you are using Ubuntu 14.04 LTS (trusty) or Debian 7.0 (wheezy) and above run
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \
libjemalloc-dev cython python3-dev python-setuptools
spdylay is not packaged in Ubuntu, so you need to build it yourself:
http://tatsuhiro-t.github.io/spdylay/
From Ubuntu 15.10, spdylay has been available as a package named
`libspdylay-dev`. For the earlier Ubuntu release, you need to build
it yourself: http://tatsuhiro-t.github.io/spdylay/
To enable mruby support for nghttpx, `mruby
<https://github.com/mruby/mruby>`_ is required. We need to build
@@ -160,6 +161,17 @@ To compile the source code, gcc >= 4.8.3 or clang >= 3.4 is required.
them from crashing. A patch is welcome to make multi threading work
on Mac OS X platform.
.. note::
To compile the associated applications (nghttp, nghttpd, nghttpx
and h2load), you must use the ``--enable-app`` configure option and
ensure that the specified requirements above are met. Normally,
configure script checks required dependencies to build these
applications, and enable ``--enable-app`` automatically, so you
don't have to use it explicitly. But if you found that
applications were not built, then using ``--enable-app`` may find
that cause, such as the missing dependency.
Notes for building on Windows (Mingw/Cygwin)
--------------------------------------------
@@ -639,7 +651,9 @@ push.
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
session IDs, session tickets (with automatic key rotation), OCSP
stapling, dynamic record sizing, ALPN/NPN, forward secrecy and SPDY &
HTTP/2.
HTTP/2. ``nghttpx`` also offers the functionality to share session
cache and ticket keys among multiple ``nghttpx`` instances via
memcached.
``nghttpx`` has several operational modes:
@@ -661,7 +675,9 @@ The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
SSL/TLS in the frontend connection by default. To disable SSL/TLS,
use the ``--frontend-no-tls`` option. If that option is used, SPDY is
disabled in the frontend and incoming HTTP/1.1 connections can be
upgraded to HTTP/2 through HTTP Upgrade.
upgraded to HTTP/2 through HTTP Upgrade. In these modes, HTTP/1
backend connections are cleartext by default. To enable TLS, use
``--backend-http1-tls`` opiton.
The ``--http2-bridge``, ``--client`` and ``--client-proxy`` modes use
SSL/TLS in the backend connection by default. To disable SSL/TLS, use
@@ -1462,3 +1478,16 @@ full real name when contributing!
See `Contribution Guidelines
<https://nghttp2.org/documentation/contribute.html>`_ for more
details.
Release schedule
----------------
In general, we follow `Semantic Versioning <http://semver.org/>`_. We
release MINOR version update every month, and usually we ship it
around 25th day of every month.
We may release PATCH releases between the regular releases, mainly for
severe security bug fixes.
We have no plan to break API compatibility changes involving soname
bump, so MAJOR version will stay 1 for the foreseeable future.

View File

@@ -25,7 +25,7 @@ dnl Do not change user variables!
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
AC_PREREQ(2.61)
AC_INIT([nghttp2], [1.7.0], [t-tujikawa@users.sourceforge.net])
AC_INIT([nghttp2], [1.8.0], [t-tujikawa@users.sourceforge.net])
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
@@ -46,9 +46,9 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl See versioning rule:
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 18)
AC_SUBST(LT_REVISION, 1)
AC_SUBST(LT_AGE, 4)
AC_SUBST(LT_CURRENT, 19)
AC_SUBST(LT_REVISION, 0)
AC_SUBST(LT_AGE, 5)
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"`
@@ -76,7 +76,7 @@ AC_ARG_ENABLE([threads],
AC_ARG_ENABLE([app],
[AS_HELP_STRING([--enable-app],
[Build applications (nghttp, nghttpd and nghttpx) [default=check]])],
[Build applications (nghttp, nghttpd, nghttpx and h2load) [default=check]])],
[request_app=$enableval], [request_app=check])
AC_ARG_ENABLE([hpack-tools],
@@ -185,14 +185,24 @@ if test "x$GCC" = "xyes" -o "x$CC" = "xclang" ; then
AC_DEFINE([_U_], [__attribute__((unused))], [Hint to the compiler that a function parameters is not used])
AC_DEFINE([NGHTTP2_NORETURN], [__attribute__((noreturn))], [Hint to the compiler that a function never return])
else
AC_DEFINE([_U_], , [Hint to the compiler that a function parameters is not use AC_DEFINE([NGHTTP2_NORETURN], , [Hint to the compiler that a function never return])
d])
AC_DEFINE([_U_], , [Hint to the compiler that a function parameter is not used])
AC_DEFINE([NGHTTP2_NORETURN], , [Hint to the compiler that a function never return])
fi
save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS=
AX_CXX_COMPILE_STDCXX_11([noext], [optional])
CXX1XCXXFLAGS="$CXXFLAGS"
CXXFLAGS="$save_CXXFLAGS"
AC_SUBST([CXX1XCXXFLAGS])
AC_LANG_PUSH(C++)
save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $CXX1XCXXFLAGS"
# Check that std::future is available.
AC_MSG_CHECKING([whether std::future is available])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
@@ -226,6 +236,8 @@ std::map<int, int>().emplace(1, 2);
[have_std_map_emplace=no
AC_MSG_RESULT([no])])
CXXFLAGS=$save_CXXFLAGS
AC_LANG_POP()
# Checks for libraries.
@@ -256,9 +268,16 @@ if test "x${have_zlib}" = "xno"; then
fi
# dl: openssl requires libdl when it is statically linked.
LIBS_OLD=$LIBS
AC_SEARCH_LIBS([dlopen], [dl], [APPLDFLAGS="-ldl $APPLDFLAGS"], [], [])
LIBS=$LIBS_OLD
case "${host_os}" in
*bsd*)
# dlopen is in libc on *BSD
;;
*)
save_LIBS=$LIBS
AC_SEARCH_LIBS([dlopen], [dl], [APPLDFLAGS="-ldl $APPLDFLAGS"], [], [])
LIBS=$save_LIBS
;;
esac
# cunit
PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes], [have_cunit=no])
@@ -291,7 +310,7 @@ AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ])
# libev (for src)
# libev does not have pkg-config file. Check it in an old way.
LIBS_OLD=$LIBS
save_LIBS=$LIBS
# android requires -lm for floor
AC_CHECK_LIB([ev], [ev_time], [have_libev=yes], [have_libev=no], [-lm])
if test "x${have_libev}" = "xyes"; then
@@ -303,7 +322,7 @@ if test "x${have_libev}" = "xyes"; then
AC_SUBST([LIBEV_CFLAGS])
fi
fi
LIBS=$LIBS_OLD
LIBS=$save_LIBS
# openssl (for src)
PKG_CHECK_MODULES([OPENSSL], [openssl >= 1.0.1],
@@ -333,7 +352,10 @@ fi
# libxml2 (for src/nghttp)
have_libxml2=no
if test "x${request_libxml2}" != "xno"; then
AM_PATH_XML2(2.7.7, [have_libxml2=yes], [have_libxml2=no])
m4_ifdef([AM_PATH_XML2],
[AM_PATH_XML2(2.7.7, [have_libxml2=yes], [have_libxml2=no])],
[AC_MSG_WARN([configure was created without libxml2 detection macro; libxml2 detection is disabled])])
if test "x${have_libxml2}" = "xyes"; then
AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have `libxml2` library.])
fi
@@ -349,7 +371,7 @@ AM_CONDITIONAL([HAVE_LIBXML2], [ test "x${have_libxml2}" = "xyes" ])
# jemalloc
have_jemalloc=no
if test "x${request_jemalloc}" != "xno"; then
LIBS_OLD=$LIBS
save_LIBS=$LIBS
AC_SEARCH_LIBS([malloc_stats_print], [jemalloc], [have_jemalloc=yes], [],
[$PTHREAD_LDFLAGS])
@@ -365,7 +387,7 @@ if test "x${request_jemalloc}" != "xno"; then
fi
fi
LIBS=$LIBS_OLD
LIBS=$save_LIBS
if test "x${have_jemalloc}" = "xyes" &&
test "x${jemalloc_libs}" != "xnone required"; then
@@ -632,8 +654,13 @@ AC_CHECK_FUNC([timerfd_create],
# For cygwin: we can link initgroups, so AC_CHECK_FUNCS succeeds, but
# cygwin disables initgroups due to feature test macro magic with our
# configuration.
AC_CHECK_DECLS([initgroups], [], [], [[#include <grp.h>]])
# configuration. FreeBSD declares initgroups() in unistd.h.
AC_CHECK_DECLS([initgroups], [], [], [[
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <grp.h>
]])
# Checks for epoll availability, primarily for examples/tiny-nghttpd
AX_HAVE_EPOLL([have_epoll=yes], [have_epoll=no])
@@ -642,8 +669,8 @@ AM_CONDITIONAL([ENABLE_TINY_NGHTTPD],
[ test "x${have_epoll}" = "xyes" &&
test "x${have_timerfd_create}" = "xyes"])
ac_save_CFLAGS=$CFLAGS
ac_save_CXXFLAGS=$CXXFLAGS
save_CFLAGS=$CFLAGS
save_CXXFLAGS=$CXXFLAGS
CFLAGS=
CXXFLAGS=
@@ -707,8 +734,8 @@ fi
WARNCFLAGS=$CFLAGS
WARNCXXFLAGS=$CXXFLAGS
CFLAGS=$ac_save_CFLAGS
CXXFLAGS=$ac_save_CXXFLAGS
CFLAGS=$save_CFLAGS
CXXFLAGS=$save_CXXFLAGS
AC_SUBST([WARNCFLAGS])
AC_SUBST([WARNCXXFLAGS])
@@ -797,6 +824,7 @@ AC_MSG_NOTICE([summary of build options:
C preprocessor: ${CPP}
CPPFLAGS: ${CPPFLAGS}
WARNCFLAGS: ${WARNCFLAGS}
CXX1XCXXFLAGS: ${CXX1XCXXFLAGS}
EXTRACFLAG: ${EXTRACFLAG}
LIBS: ${LIBS}
Library:

View File

@@ -58,6 +58,7 @@ APIDOCS= \
nghttp2_option_set_no_http_messaging.rst \
nghttp2_option_set_no_recv_client_magic.rst \
nghttp2_option_set_peer_max_concurrent_streams.rst \
nghttp2_option_set_user_recv_extension_type.rst \
nghttp2_pack_settings_payload.rst \
nghttp2_priority_spec_check_default.rst \
nghttp2_priority_spec_default_init.rst \
@@ -70,16 +71,19 @@ APIDOCS= \
nghttp2_session_callbacks_set_on_begin_frame_callback.rst \
nghttp2_session_callbacks_set_on_begin_headers_callback.rst \
nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst \
nghttp2_session_callbacks_set_on_extension_chunk_recv_callback.rst \
nghttp2_session_callbacks_set_on_frame_not_send_callback.rst \
nghttp2_session_callbacks_set_on_frame_recv_callback.rst \
nghttp2_session_callbacks_set_on_frame_send_callback.rst \
nghttp2_session_callbacks_set_on_header_callback.rst \
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback.rst \
nghttp2_session_callbacks_set_on_stream_close_callback.rst \
nghttp2_session_callbacks_set_pack_extension_callback.rst \
nghttp2_session_callbacks_set_recv_callback.rst \
nghttp2_session_callbacks_set_select_padding_callback.rst \
nghttp2_session_callbacks_set_send_callback.rst \
nghttp2_session_callbacks_set_send_data_callback.rst \
nghttp2_session_callbacks_set_unpack_extension_callback.rst \
nghttp2_session_client_new.rst \
nghttp2_session_client_new2.rst \
nghttp2_session_client_new3.rst \
@@ -131,6 +135,7 @@ APIDOCS= \
nghttp2_stream_get_weight.rst \
nghttp2_strerror.rst \
nghttp2_submit_data.rst \
nghttp2_submit_extension.rst \
nghttp2_submit_goaway.rst \
nghttp2_submit_headers.rst \
nghttp2_submit_ping.rst \
@@ -145,15 +150,18 @@ APIDOCS= \
nghttp2_submit_window_update.rst \
nghttp2_version.rst
EXTRA_DIST = \
mkapiref.py \
RST_FILES = \
README.rst \
programmers-guide.rst \
$(APIDOCS) \
nghttp.1.rst \
nghttpd.1.rst \
nghttpx.1.rst \
h2load.1.rst \
h2load.1.rst
EXTRA_DIST = \
mkapiref.py \
$(RST_FILES) \
$(APIDOCS) \
sources/index.rst \
sources/tutorial-client.rst \
sources/tutorial-server.rst \
@@ -227,13 +235,15 @@ help:
apiref.rst: \
$(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
$(top_srcdir)/lib/includes/nghttp2/nghttp2.h
for i in $(RST_FILES); do [ -e $(builddir)/$$i ] || cp $(srcdir)/$$i $(builddir); done
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
apiref.rst macros.rst enums.rst types.rst . $^
$(APIDOCS): apiref.rst
clean-local:
[ $(srcdir) = $(builddir) ] || for i in $(RST_FILES); do [ -e $(builddir)/$$i ] && rm $(builddir)/$$i; done
-rm -f apiref.rst
-rm -f $(APIDOCS)
-rm -rf $(BUILDDIR)/*

View File

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

View File

@@ -8,7 +8,7 @@ _nghttpx()
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--worker-read-rate --frontend-no-tls --frontend-http2-dump-response-header --backend-http1-connections-per-frontend --tls-ticket-key-file --verify-client-cacert --include --backend-request-buffer --backend-http2-connection-window-bits --conf --worker-write-burst --npn-list --fetch-ocsp-response-file --mruby-file --stream-read-timeout --tls-ticket-key-memcached --forwarded-for --accesslog-syslog --frontend-http2-read-timeout --listener-disable-timeout --frontend-http2-connection-window-bits --ciphers --strip-incoming-x-forwarded-for --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --backend-http1-connections-per-host --rlimit-nofile --tls-dyn-rec-warmup-threshold --no-via --ocsp-update-interval --backend-write-timeout --client --tls-ticket-key-memcached-max-retry --http2-no-cookie-crumbling --worker-read-burst --client-proxy --http2-bridge --accesslog-format --errorlog-syslog --errorlog-file --http2-max-concurrent-streams --frontend-write-timeout --tls-ticket-key-cipher --read-burst --backend-ipv4 --backend-ipv6 --backend --insecure --log-level --host-rewrite --tls-proto-list --backend-http2-connections-per-worker --tls-ticket-key-memcached-interval --dh-param-file --worker-frontend-connections --syslog-facility --fastopen --no-location-rewrite --tls-session-cache-memcached --no-ocsp --backend-response-buffer --workers --add-forwarded --frontend-http2-window-bits --worker-write-rate --add-request-header --backend-tls-sni-field --subcert --help --frontend-frame-debug --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --user --add-x-forwarded-for --header-field-buffer --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --no-server-push --backend-http2-window-bits --padding --stream-write-timeout --cacert --forwarded-by --version --add-response-header --backend-read-timeout --frontend --accesslog-file --http2-proxy --max-header-fields --backend-no-tls --client-private-key-file --client-cert-file --accept-proxy-protocol --tls-dyn-rec-idle-timeout --verify-client --read-rate --strip-incoming-forwarded ' -- "$cur" ) )
COMPREPLY=( $( compgen -W '--worker-read-rate --frontend-no-tls --frontend-http2-dump-response-header --backend-http1-connections-per-frontend --tls-ticket-key-file --verify-client-cacert --include --max-response-header-fields --backend-request-buffer --max-request-header-fields --backend-http2-connection-window-bits --conf --worker-write-burst --npn-list --fetch-ocsp-response-file --no-via --tls-session-cache-memcached-cert-file --no-http2-cipher-black-list --mruby-file --stream-read-timeout --tls-ticket-key-memcached --forwarded-for --accesslog-syslog --frontend-http2-read-timeout --listener-disable-timeout --frontend-http2-connection-window-bits --ciphers --strip-incoming-x-forwarded-for --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --backend-http1-connections-per-host --rlimit-nofile --tls-dyn-rec-warmup-threshold --tls-ticket-key-memcached-cert-file --ocsp-update-interval --forwarded-by --tls-session-cache-memcached-private-key-file --backend-write-timeout --client --tls-ticket-key-memcached-max-retry --http2-no-cookie-crumbling --worker-read-burst --client-proxy --http2-bridge --accesslog-format --errorlog-syslog --request-header-field-buffer --errorlog-file --http2-max-concurrent-streams --frontend-write-timeout --tls-ticket-key-cipher --read-burst --backend --insecure --log-level --host-rewrite --tls-session-cache-memcached-tls --tls-proto-list --backend-http2-connections-per-worker --tls-ticket-key-memcached-interval --dh-param-file --worker-frontend-connections --backend-http1-tls --syslog-facility --fastopen --no-location-rewrite --tls-ticket-key-memcached-tls --tls-session-cache-memcached --no-ocsp --backend-response-buffer --workers --add-forwarded --frontend-http2-window-bits --worker-write-rate --add-request-header --backend-tls-sni-field --subcert --help --frontend-frame-debug --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --user --add-x-forwarded-for --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --no-server-push --backend-http2-window-bits --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 --backend-address-family --version --add-response-header --backend-read-timeout --frontend --accesslog-file --http2-proxy --backend-no-tls --client-private-key-file --client-cert-file --accept-proxy-protocol --tls-dyn-rec-idle-timeout --verify-client --read-rate --strip-incoming-forwarded ' -- "$cur" ) )
;;
*)
_filedir

View File

@@ -41,7 +41,7 @@ import sys, os
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
sys.path.append(os.path.abspath('_exts'))
sys.path.append(os.path.abspath('@top_srcdir@/doc/_exts'))
# -- General configuration -----------------------------------------------------

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "H2LOAD" "1" "January 25, 2016" "1.7.0" "nghttp2"
.TH "H2LOAD" "1" "February 25, 2016" "1.8.0" "nghttp2"
.SH NAME
h2load \- HTTP/2 benchmarking tool
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTP" "1" "January 25, 2016" "1.7.0" "nghttp2"
.TH "NGHTTP" "1" "February 25, 2016" "1.8.0" "nghttp2"
.SH NAME
nghttp \- HTTP/2 client
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPD" "1" "January 25, 2016" "1.7.0" "nghttp2"
.TH "NGHTTPD" "1" "February 25, 2016" "1.8.0" "nghttp2"
.SH NAME
nghttpd \- HTTP/2 server
.
@@ -139,6 +139,17 @@ Make error response gzipped.
.UNINDENT
.INDENT 0.0
.TP
.B \-w, \-\-window\-bits=<N>
Sets the stream level initial window size to 2**<N>\-1.
.UNINDENT
.INDENT 0.0
.TP
.B \-W, \-\-connection\-window\-bits=<N>
Sets the connection level initial window size to
2**<N>\-1.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-dh\-param\-file=<PATH>
Path to file that contains DH parameters in PEM format.
Without this option, DHE cipher suites are not

View File

@@ -104,6 +104,15 @@ OPTIONS
Make error response gzipped.
.. option:: -w, --window-bits=<N>
Sets the stream level initial window size to 2\*\*<N>-1.
.. option:: -W, --connection-window-bits=<N>
Sets the connection level initial window size to
2\*\*<N>-1.
.. option:: --dh-param-file=<PATH>
Path to file that contains DH parameters in PEM format.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPX" "1" "January 25, 2016" "1.7.0" "nghttp2"
.TH "NGHTTPX" "1" "February 25, 2016" "1.8.0" "nghttp2"
.SH NAME
nghttpx \- HTTP/2 proxy
.
@@ -121,7 +121,9 @@ Default: \fB127.0.0.1,80\fP
Set frontend host and port. If <HOST> is \(aq*\(aq, it
assumes all addresses including both IPv4 and IPv6.
UNIX domain socket can be specified by prefixing path
name with "unix:" (e.g., unix:/var/run/nghttpx.sock)
name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
This option can be used multiple times to listen to
multiple addresses.
.sp
Default: \fB*,3000\fP
.UNINDENT
@@ -134,13 +136,13 @@ Default: \fB512\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-backend\-ipv4
Resolve backend hostname to IPv4 address only.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-backend\-ipv6
Resolve backend hostname to IPv6 address only.
.B \-\-backend\-address\-family=(auto|IPv4|IPv6)
Specify address family of backend connections. If
"auto" is given, both IPv4 and IPv6 are considered. If
"IPv4" is given, only IPv4 address is considered. If
"IPv6" is given, only IPv6 address is considered.
.sp
Default: \fBauto\fP
.UNINDENT
.INDENT 0.0
.TP
@@ -163,6 +165,22 @@ be specified by \fI\%\-\-backend\-read\-timeout\fP and
.B \-\-accept\-proxy\-protocol
Accept PROXY protocol version 1 on frontend connection.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-backend\-no\-tls
Disable SSL/TLS on backend connections. For HTTP/2
backend connections, TLS is enabled by default. For
HTTP/1 backend connections, TLS is disabled by default,
and can be enabled by \fI\%\-\-backend\-http1\-tls\fP option. If
both \fI\%\-\-backend\-no\-tls\fP and \fI\%\-\-backend\-http1\-tls\fP options
are used, \fI\%\-\-backend\-no\-tls\fP has the precedence.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-backend\-http1\-tls
Enable SSL/TLS on backend HTTP/1 connections. See also
\fI\%\-\-backend\-no\-tls\fP option.
.UNINDENT
.SS Performance
.INDENT 0.0
.TP
@@ -396,19 +414,17 @@ described in OpenSSL ciphers(1).
.INDENT 0.0
.TP
.B \-k, \-\-insecure
Don\(aqt verify backend server\(aqs certificate if \fI\%\-p\fP,
\fI\%\-\-client\fP or \fI\%\-\-http2\-bridge\fP are given and
\fI\%\-\-backend\-no\-tls\fP is not given.
Don\(aqt verify backend server\(aqs certificate if TLS is
enabled for backend connections.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-cacert=<PATH>
Set path to trusted CA certificate file if \fI\%\-p\fP, \fI\%\-\-client\fP
or \fI\%\-\-http2\-bridge\fP are given and \fI\%\-\-backend\-no\-tls\fP is not
given. The file must be in PEM format. It can contain
multiple certificates. If the linked OpenSSL is
configured to load system wide certificates, they are
loaded at startup regardless of this option.
Set path to trusted CA certificate file used in backend
TLS connections. The file must be in PEM format. It
can contain multiple certificates. If the linked
OpenSSL is configured to load system wide certificates,
they are loaded at startup regardless of this option.
.UNINDENT
.INDENT 0.0
.TP
@@ -518,16 +534,27 @@ required.
.INDENT 0.0
.TP
.B \-\-tls\-ticket\-key\-memcached=<HOST>,<PORT>
Specify address of memcached server to store session
cache. This enables shared TLS ticket key between
multiple nghttpx instances. nghttpx does not set TLS
ticket key to memcached. The external ticket key
generator is required. nghttpx just gets TLS ticket
keys from memcached, and use them, possibly replacing
current set of keys. It is up to extern TLS ticket key
generator to rotate keys frequently. See "TLS SESSION
TICKET RESUMPTION" section in manual page to know the
data format in memcached entry.
Specify address of memcached server to get TLS ticket
keys for session resumption. This enables shared TLS
ticket key between multiple nghttpx instances. nghttpx
does not set TLS ticket key to memcached. The external
ticket key generator is required. nghttpx just gets TLS
ticket keys from memcached, and use them, possibly
replacing current set of keys. It is up to extern TLS
ticket key generator to rotate keys frequently. See
"TLS SESSION TICKET RESUMPTION" section in manual page
to know the data format in memcached entry.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-ticket\-key\-memcached\-address\-family=(auto|IPv4|IPv6)
Specify address family of memcached connections to get
TLS ticket keys. If "auto" is given, both IPv4 and IPv6
are considered. If "IPv4" is given, only IPv4 address
is considered. If "IPv6" is given, only IPv6 address is
considered.
.sp
Default: \fBauto\fP
.UNINDENT
.INDENT 0.0
.TP
@@ -565,6 +592,24 @@ aes\-128\-cbc is used.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-ticket\-key\-memcached\-tls
Enable SSL/TLS on memcached connections to get TLS
ticket keys.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-ticket\-key\-memcached\-cert\-file=<PATH>
Path to client certificate for memcached connections to
get TLS ticket keys.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-ticket\-key\-memcached\-private\-key\-file=<PATH>
Path to client private key for memcached connections to
get TLS ticket keys.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-fetch\-ocsp\-response\-file=<PATH>
Path to fetch\-ocsp\-response script file. It should be
absolute path.
@@ -592,6 +637,35 @@ multiple nghttpx instances.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-session\-cache\-memcached\-address\-family=(auto|IPv4|IPv6)
Specify address family of memcached connections to store
session cache. If "auto" is given, both IPv4 and IPv6
are considered. If "IPv4" is given, only IPv4 address
is considered. If "IPv6" is given, only IPv6 address is
considered.
.sp
Default: \fBauto\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-session\-cache\-memcached\-tls
Enable SSL/TLS on memcached connections to store session
cache.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-session\-cache\-memcached\-cert\-file=<PATH>
Path to client certificate for memcached connections to
store session cache.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-session\-cache\-memcached\-private\-key\-file=<PATH>
Path to client private key for memcached connections to
store session cache.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-dyn\-rec\-warmup\-threshold=<SIZE>
Specify the threshold size for TLS dynamic record size
behaviour. During a TLS session, after the threshold
@@ -616,6 +690,13 @@ TLS HTTP/2 backends.
.sp
Default: \fB1s\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-no\-http2\-cipher\-black\-list
Allow black listed cipher suite on HTTP/2 connection.
See \fI\%https://tools.ietf.org/html/rfc7540#appendix\-A\fP for
the complete HTTP/2 cipher suites black list.
.UNINDENT
.SS HTTP/2 and SPDY
.INDENT 0.0
.TP
@@ -666,11 +747,6 @@ Default: \fB16\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-backend\-no\-tls
Disable SSL/TLS on backend connections.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-http2\-no\-cookie\-crumbling
Don\(aqt crumble cookie header field.
.UNINDENT
@@ -868,11 +944,12 @@ Specify the parameter value sent out with "by" parameter
of Forwarded header field. If "obfuscated" is given,
the string is randomly generated at startup. If "ip" is
given, the interface address of the connection,
including port number, is sent with "by" parameter.
User can also specify the static obfuscated string. The
limitation is that it must start with "_", and only
consists of character set [A\-Za\-z0\-9._\-], as described
in RFC 7239.
including port number, is sent with "by" parameter. In
case of UNIX domain socket, "localhost" is used instead
of address and port. User can also specify the static
obfuscated string. The limitation is that it must start
with "_", and only consists of character set
[A\-Za\-z0\-9._\-], as described in RFC 7239.
.sp
Default: \fBobfuscated\fP
.UNINDENT
@@ -884,7 +961,8 @@ parameter of Forwarded header field. If "obfuscated" is
given, the string is randomly generated for each client
connection. If "ip" is given, the remote client address
of the connection, without port number, is sent with
"for" parameter.
"for" parameter. In case of UNIX domain socket,
"localhost" is used instead of address.
.sp
Default: \fBobfuscated\fP
.UNINDENT
@@ -940,22 +1018,42 @@ Example: \fI\%\-\-add\-response\-header\fP="foo: bar"
.UNINDENT
.INDENT 0.0
.TP
.B \-\-header\-field\-buffer=<SIZE>
.B \-\-request\-header\-field\-buffer=<SIZE>
Set maximum buffer size for incoming HTTP request header
field list. This is the sum of header name and value in
bytes.
bytes. If trailer fields exist, they are counted
towards this number.
.sp
Default: \fB64K\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-max\-header\-fields=<N>
.B \-\-max\-request\-header\-fields=<N>
Set maximum number of incoming HTTP request header
fields, which appear in one request or response header
field list.
fields. If trailer fields exist, they are counted
towards this number.
.sp
Default: \fB100\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-response\-header\-field\-buffer=<SIZE>
Set maximum buffer size for incoming HTTP response
header field list. This is the sum of header name and
value in bytes. If trailer fields exist, they are
counted towards this number.
.sp
Default: \fB64K\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-max\-response\-header\-fields=<N>
Set maximum number of incoming HTTP response header
fields. If trailer fields exist, they are counted
towards this number.
.sp
Default: \fB500\fP
.UNINDENT
.SS Debug
.INDENT 0.0
.TP
@@ -1203,6 +1301,10 @@ insert serialized session data to memcached with
\fBnghttpx:tls\-session\-cache:\fP + lowercased hex string of session ID
as a memcached entry key, with expiry time 12 hours. Session timeout
is set to 12 hours.
.sp
By default, connections to memcached server are not encrypted. To
enable encryption, use \fI\%\-\-tls\-session\-cache\-memcached\-tls\fP
option.
.SS TLS SESSION TICKET RESUMPTION
.sp
By default, session ticket is shared by all worker threads. The
@@ -1247,6 +1349,10 @@ used, LEN must be 48. If
keys. The key appeared first is used as encryption key. All the
remaining keys are used as decryption only.
.sp
By default, connections to memcached server are not encrypted. To
enable encryption, use \fI\%\-\-tls\-ticket\-key\-memcached\-tls\fP
option.
.sp
If \fI\%\-\-tls\-ticket\-key\-file\fP is given, encryption key is read
from the given file. In this case, nghttpx does not rotate key
automatically. To rotate key, one has to restart nghttpx (see

View File

@@ -104,7 +104,9 @@ Connections
Set frontend host and port. If <HOST> is '\*', it
assumes all addresses including both IPv4 and IPv6.
UNIX domain socket can be specified by prefixing path
name with "unix:" (e.g., unix:/var/run/nghttpx.sock)
name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
This option can be used multiple times to listen to
multiple addresses.
Default: ``*,3000``
@@ -114,13 +116,14 @@ Connections
Default: ``512``
.. option:: --backend-ipv4
.. option:: --backend-address-family=(auto|IPv4|IPv6)
Resolve backend hostname to IPv4 address only.
Specify address family of backend connections. If
"auto" is given, both IPv4 and IPv6 are considered. If
"IPv4" is given, only IPv4 address is considered. If
"IPv6" is given, only IPv6 address is considered.
.. option:: --backend-ipv6
Resolve backend hostname to IPv6 address only.
Default: ``auto``
.. option:: --backend-http-proxy-uri=<URI>
@@ -141,6 +144,20 @@ Connections
Accept PROXY protocol version 1 on frontend connection.
.. option:: --backend-no-tls
Disable SSL/TLS on backend connections. For HTTP/2
backend connections, TLS is enabled by default. For
HTTP/1 backend connections, TLS is disabled by default,
and can be enabled by :option:`--backend-http1-tls` option. If
both :option:`--backend-no-tls` and :option:`\--backend-http1-tls` options
are used, :option:`--backend-no-tls` has the precedence.
.. option:: --backend-http1-tls
Enable SSL/TLS on backend HTTP/1 connections. See also
:option:`--backend-no-tls` option.
Performance
~~~~~~~~~~~
@@ -354,18 +371,16 @@ SSL/TLS
.. option:: -k, --insecure
Don't verify backend server's certificate if :option:`-p`\,
:option:`--client` or :option:`\--http2-bridge` are given and
:option:`--backend-no-tls` is not given.
Don't verify backend server's certificate if TLS is
enabled for backend connections.
.. option:: --cacert=<PATH>
Set path to trusted CA certificate file if :option:`-p`\, :option:`--client`
or :option:`--http2-bridge` are given and :option:`\--backend-no-tls` is not
given. The file must be in PEM format. It can contain
multiple certificates. If the linked OpenSSL is
configured to load system wide certificates, they are
loaded at startup regardless of this option.
Set path to trusted CA certificate file used in backend
TLS connections. The file must be in PEM format. It
can contain multiple certificates. If the linked
OpenSSL is configured to load system wide certificates,
they are loaded at startup regardless of this option.
.. option:: --private-key-passwd-file=<PATH>
@@ -463,16 +478,26 @@ SSL/TLS
.. option:: --tls-ticket-key-memcached=<HOST>,<PORT>
Specify address of memcached server to store session
cache. This enables shared TLS ticket key between
multiple nghttpx instances. nghttpx does not set TLS
ticket key to memcached. The external ticket key
generator is required. nghttpx just gets TLS ticket
keys from memcached, and use them, possibly replacing
current set of keys. It is up to extern TLS ticket key
generator to rotate keys frequently. See "TLS SESSION
TICKET RESUMPTION" section in manual page to know the
data format in memcached entry.
Specify address of memcached server to get TLS ticket
keys for session resumption. This enables shared TLS
ticket key between multiple nghttpx instances. nghttpx
does not set TLS ticket key to memcached. The external
ticket key generator is required. nghttpx just gets TLS
ticket keys from memcached, and use them, possibly
replacing current set of keys. It is up to extern TLS
ticket key generator to rotate keys frequently. See
"TLS SESSION TICKET RESUMPTION" section in manual page
to know the data format in memcached entry.
.. option:: --tls-ticket-key-memcached-address-family=(auto|IPv4|IPv6)
Specify address family of memcached connections to get
TLS ticket keys. If "auto" is given, both IPv4 and IPv6
are considered. If "IPv4" is given, only IPv4 address
is considered. If "IPv6" is given, only IPv6 address is
considered.
Default: ``auto``
.. option:: --tls-ticket-key-memcached-interval=<DURATION>
@@ -504,6 +529,21 @@ SSL/TLS
either aes-128-cbc or aes-256-cbc. By default,
aes-128-cbc is used.
.. option:: --tls-ticket-key-memcached-tls
Enable SSL/TLS on memcached connections to get TLS
ticket keys.
.. option:: --tls-ticket-key-memcached-cert-file=<PATH>
Path to client certificate for memcached connections to
get TLS ticket keys.
.. option:: --tls-ticket-key-memcached-private-key-file=<PATH>
Path to client private key for memcached connections to
get TLS ticket keys.
.. option:: --fetch-ocsp-response-file=<PATH>
Path to fetch-ocsp-response script file. It should be
@@ -527,6 +567,31 @@ SSL/TLS
cache. This enables shared session cache between
multiple nghttpx instances.
.. option:: --tls-session-cache-memcached-address-family=(auto|IPv4|IPv6)
Specify address family of memcached connections to store
session cache. If "auto" is given, both IPv4 and IPv6
are considered. If "IPv4" is given, only IPv4 address
is considered. If "IPv6" is given, only IPv6 address is
considered.
Default: ``auto``
.. option:: --tls-session-cache-memcached-tls
Enable SSL/TLS on memcached connections to store session
cache.
.. option:: --tls-session-cache-memcached-cert-file=<PATH>
Path to client certificate for memcached connections to
store session cache.
.. option:: --tls-session-cache-memcached-private-key-file=<PATH>
Path to client private key for memcached connections to
store session cache.
.. option:: --tls-dyn-rec-warmup-threshold=<SIZE>
Specify the threshold size for TLS dynamic record size
@@ -551,6 +616,12 @@ SSL/TLS
Default: ``1s``
.. option:: --no-http2-cipher-black-list
Allow black listed cipher suite on HTTP/2 connection.
See https://tools.ietf.org/html/rfc7540#appendix-A for
the complete HTTP/2 cipher suites black list.
HTTP/2 and SPDY
~~~~~~~~~~~~~~~
@@ -596,10 +667,6 @@ HTTP/2 and SPDY
Default: ``16``
.. option:: --backend-no-tls
Disable SSL/TLS on backend connections.
.. option:: --http2-no-cookie-crumbling
Don't crumble cookie header field.
@@ -773,11 +840,12 @@ HTTP
of Forwarded header field. If "obfuscated" is given,
the string is randomly generated at startup. If "ip" is
given, the interface address of the connection,
including port number, is sent with "by" parameter.
User can also specify the static obfuscated string. The
limitation is that it must start with "_", and only
consists of character set [A-Za-z0-9._-], as described
in RFC 7239.
including port number, is sent with "by" parameter. In
case of UNIX domain socket, "localhost" is used instead
of address and port. User can also specify the static
obfuscated string. The limitation is that it must start
with "_", and only consists of character set
[A-Za-z0-9._-], as described in RFC 7239.
Default: ``obfuscated``
@@ -788,7 +856,8 @@ HTTP
given, the string is randomly generated for each client
connection. If "ip" is given, the remote client address
of the connection, without port number, is sent with
"for" parameter.
"for" parameter. In case of UNIX domain socket,
"localhost" is used instead of address.
Default: ``obfuscated``
@@ -836,22 +905,40 @@ HTTP
used several times to specify multiple header fields.
Example: :option:`--add-response-header`\="foo: bar"
.. option:: --header-field-buffer=<SIZE>
.. option:: --request-header-field-buffer=<SIZE>
Set maximum buffer size for incoming HTTP request header
field list. This is the sum of header name and value in
bytes.
bytes. If trailer fields exist, they are counted
towards this number.
Default: ``64K``
.. option:: --max-header-fields=<N>
.. option:: --max-request-header-fields=<N>
Set maximum number of incoming HTTP request header
fields, which appear in one request or response header
field list.
fields. If trailer fields exist, they are counted
towards this number.
Default: ``100``
.. option:: --response-header-field-buffer=<SIZE>
Set maximum buffer size for incoming HTTP response
header field list. This is the sum of header name and
value in bytes. If trailer fields exist, they are
counted towards this number.
Default: ``64K``
.. option:: --max-response-header-fields=<N>
Set maximum number of incoming HTTP response header
fields. If trailer fields exist, they are counted
towards this number.
Default: ``500``
Debug
~~~~~
@@ -1091,6 +1178,10 @@ insert serialized session data to memcached with
as a memcached entry key, with expiry time 12 hours. Session timeout
is set to 12 hours.
By default, connections to memcached server are not encrypted. To
enable encryption, use :option:`--tls-session-cache-memcached-tls`
option.
TLS SESSION TICKET RESUMPTION
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1130,6 +1221,10 @@ used, LEN must be 48. If
keys. The key appeared first is used as encryption key. All the
remaining keys are used as decryption only.
By default, connections to memcached server are not encrypted. To
enable encryption, use :option:`--tls-ticket-key-memcached-tls`
option.
If :option:`--tls-ticket-key-file` is given, encryption key is read
from the given file. In this case, nghttpx does not rotate key
automatically. To rotate key, one has to restart nghttpx (see

View File

@@ -150,6 +150,10 @@ insert serialized session data to memcached with
as a memcached entry key, with expiry time 12 hours. Session timeout
is set to 12 hours.
By default, connections to memcached server are not encrypted. To
enable encryption, use :option:`--tls-session-cache-memcached-tls`
option.
TLS SESSION TICKET RESUMPTION
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -189,6 +193,10 @@ used, LEN must be 48. If
keys. The key appeared first is used as encryption key. All the
remaining keys are used as decryption only.
By default, connections to memcached server are not encrypted. To
enable encryption, use :option:`--tls-ticket-key-memcached-tls`
option.
If :option:`--tls-ticket-key-file` is given, encryption key is read
from the given file. In this case, nghttpx does not rotate key
automatically. To rotate key, one has to restart nghttpx (see

View File

@@ -1,6 +1,62 @@
Programmers' Guide
==================
Architecture
------------
The most notable point in nghttp2 library architecture is it does not
perform any I/O. nghttp2 only performs HTTP/2 protocol stuff based on
input byte strings. It will calls callback functions set by
applications while processing input. The output of nghttp2 is just
byte string. An application is responsible to send these output to
the remote peer. The callback functions may be called while producing
output.
Not doing I/O makes embedding nghttp2 library in the existing code
base very easy. Usually, the existing applications have its own I/O
event loops. It is very hard to use nghttp2 in that situation if
nghttp2 does its own I/O. It also makes light weight language wrapper
for nghttp2 easy with the same reason. The down side is that an
application author has to write more code to write complete
application using nghttp2. This is especially true for simple "toy"
application. For the real applications, however, this is not the
case. This is because you probably want to support HTTP/1 which
nghttp2 does not provide, and to do that, you will need to write your
own HTTP/1 stack or use existing third-party library, and bind them
together with nghttp2 and I/O event loop. In this point, not
performing I/O in nghttp2 has more point than doing it.
The primary object that an application uses is :type:`nghttp2_session`
object, which is opaque struct and its details are hidden in order to
ensure the upgrading its internal architecture without breaking the
backward compatibility. An application can set callbacks to
:type:`nghttp2_session` object through the dedicated object and
functions, and it also interacts with it via many API function calls.
An application can create as many :type:`nghttp2_session` object as it
wants. But single :type:`nghttp2_session` object must be used by a
single thread at the same time. This is not so hard to enforce since
most event-based architecture applicatons use is single thread per
core, and handling one connection I/O is done by single thread.
To feed input to :type:`nghttp2_session` object, one can use
`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` functions.
They behave similarly, and the difference is that
`nghttp2_session_recv()` will use :type:`nghttp2_read_callback` to get
input. On the other hand, `nghttp2_session_mem_recv()` will take
input as its parameter. If in doubt, use `nghttp2_session_mem_recv()`
since it is simpler, and could be faster since it avoids calling
callback function.
To get output from :type:`nghttp2_session` object, one can use
`nghttp2_session_send()` or `nghttp2_session_mem_send()`. The
difference between them is that the former uses
:type:`nghttp2_send_callback` to pass output to an application. On
the other hand, the latter returns the output to the caller. If in
doubt, use `nghttp2_session_mem_send()` since it is simpler. But
`nghttp2_session_send()` might be easier to use if the output buffer
an application has is fixed sized.
Includes
--------

View File

@@ -1,33 +1,43 @@
.. program:: h2load
h2load - HTTP/2 benchmarking tool - HOW-TO
==========================================
h2load is benchmarking tool for HTTP/2 and HTTP/1.1. If built with
spdylay (http://tatsuhiro-t.github.io/spdylay/) library, it also
supports SPDY protocol. It supports SSL/TLS and clear text for all
supported protocols.
:doc:`h2load.1` is benchmarking tool for HTTP/2 and HTTP/1.1. If
built with spdylay (http://tatsuhiro-t.github.io/spdylay/) library, it
also supports SPDY protocol. It supports SSL/TLS and clear text for
all supported protocols.
Compiling from source
---------------------
h2load is compiled alongside nghttp2 and requires that the
``--enable-apps`` flag is passed to ``./configure`` and `required
dependencies <https://github.com/tatsuhiro-t/nghttp2#requirements>`_
are available during compilation. For details on compiling, see
`nghttp2: Building from Git
<https://github.com/tatsuhiro-t/nghttp2#building-from-git>`_.
Basic Usage
-----------
In order to set benchmark settings, specify following 3 options.
``-n``
:option:`-n`
The number of total requests. Default: 1
``-c``
:option:`-c`
The number of concurrent clients. Default: 1
``-m``
The max concurrent streams to issue per client.
If ``auto`` is given, the number of given URIs is used.
Default: ``auto``
:option:`-m`
The max concurrent streams to issue per client. Default: 1
For SSL/TLS connection, the protocol will be negotiated via ALPN/NPN.
You can set specific protocols in ``--npn-list`` option. For
You can set specific protocols in :option:`--npn-list` option. For
cleartext connection, the default protocol is HTTP/2. To change the
protocol in cleartext connection, use ``--no-tls-proto`` option. For
convenience, ``--h1`` option forces HTTP/1.1 for both cleartext and
SSL/TLS connections.
protocol in cleartext connection, use :option:`--no-tls-proto` option.
For convenience, :option:`--h1` option forces HTTP/1.1 for both
cleartext and SSL/TLS connections.
Here is a command-line to perform benchmark to URI \https://localhost
using total 100000 requests, 100 concurrent clients and 10 max
@@ -62,11 +72,11 @@ benchmarking results. By default, h2load uses large enough flow
control window, which effectively disables flow control. To adjust
receiver flow control window size, there are following options:
``-w``
:option:`-w`
Sets the stream level initial window size to
(2**<N>)-1. For SPDY, 2**<N> is used instead.
``-W``
:option:`-W`
Sets the connection level initial window size to
(2**<N>)-1. For SPDY, if <N> is strictly less
than 16, this option is ignored. Otherwise
@@ -76,17 +86,17 @@ Multi-Threading
---------------
Sometimes benchmarking client itself becomes a bottleneck. To remedy
this situation, use ``-t`` option to specify the number of native
this situation, use :option:`-t` option to specify the number of native
thread to use.
``-t``
:option:`-t`
The number of native threads. Default: 1
Selecting protocol for clear text
---------------------------------
By default, if \http:// URI is given, HTTP/2 protocol is used. To
change the protocol to use for clear text, use ``-p`` option.
change the protocol to use for clear text, use :option:`-p` option.
Multiple URIs
-------------
@@ -97,3 +107,12 @@ If multiple URIs are specified, they are used in round robin manner.
Please note that h2load uses scheme, host and port in the first URI
and ignores those parts in the rest of the URIs.
UNIX domain socket
------------------
To request against UNIX domain socket, use :option:`--base-uri`, and
specify ``unix:`` followed by the path to UNIX domain socket. For
example, if UNIX domain socket is ``/tmp/nghttpx.sock``, use
``--base-uri=unix:/tmp/nghttpx.sock``. h2load uses scheme, host and
port in the first URI in command-line or input file.

View File

@@ -1,35 +1,44 @@
.. program:: nghttpx
nghttpx - HTTP/2 proxy - HOW-TO
===============================
nghttpx is a proxy translating protocols between HTTP/2 and other
protocols (e.g., HTTP/1, SPDY). It operates in several modes and each
mode may require additional programs to work with. This article
describes each operation mode and explains the intended use-cases. It
also covers some useful options later.
:doc:`nghttpx.1` is a proxy translating protocols between HTTP/2 and
other protocols (e.g., HTTP/1, SPDY). It operates in several modes
and each mode may require additional programs to work with. This
article describes each operation mode and explains the intended
use-cases. It also covers some useful options later.
Default mode
------------
If nghttpx is invoked without any ``-s``, ``-p`` and ``--client``, it
operates in default mode. In this mode, nghttpx frontend listens for
HTTP/2 requests and translates them to HTTP/1 requests. Thus it works
as reverse proxy (gateway) for HTTP/2 clients to HTTP/1 web server.
HTTP/1 requests are also supported in frontend as a fallback. If
nghttpx is linked with spdylay library and frontend connection is
SSL/TLS, the frontend also supports SPDY protocol.
If nghttpx is invoked without any :option:`--http2-proxy`,
:option:`--client`, and :option:`--client-proxy`, it operates in
default mode. In this mode, nghttpx frontend listens for HTTP/2
requests and translates them to HTTP/1 requests. Thus it works as
reverse proxy (gateway) for HTTP/2 clients to HTTP/1 web server. This
is also known as "HTTP/2 router". HTTP/1 requests are also supported
in frontend as a fallback. If nghttpx is linked with spdylay library
and frontend connection is SSL/TLS, the frontend also supports SPDY
protocol.
By default, this mode's frontend connection is encrypted using
SSL/TLS. So server's private key and certificate must be supplied to
the command line (or through configuration file). In this case, the
frontend protocol selection will be done via ALPN or NPN.
With ``--frontend-no-tls`` option, user can turn off SSL/TLS in
With :option:`--frontend-no-tls` option, user can turn off SSL/TLS in
frontend connection. In this case, SPDY protocol is not available
even if spdylay library is liked to nghttpx. HTTP/2 and HTTP/1 are
available on the frontend and a HTTP/1 connection can be upgraded to
HTTP/2 using HTTP Upgrade. Starting HTTP/2 connection by sending
HTTP/2 connection preface is also supported.
By default, backend HTTP/1 connections are not encrypted. To enable
TLS on HTTP/1 backend connections, use :option:`--backend-http1-tls`
option. This applies to all mode whose backend connections are
HTTP/1.
The backend is supposed to be HTTP/1 Web server. For example, to make
nghttpx listen to encrypted HTTP/2 requests at port 8443, and a
backend HTTP/1 web server is configured to listen to HTTP/1 request at
@@ -45,19 +54,19 @@ example, you can send GET request to the server using nghttp::
HTTP/2 proxy mode
-----------------
If nghttpx is invoked with ``-s`` option, it operates in HTTP/2 proxy
mode. The supported protocols in frontend and backend connections are
the same in `default mode`_. The difference is that this mode acts
like forward proxy and assumes the backend is HTTP/1 proxy server
(e.g., squid, traffic server). So HTTP/1 request must include
absolute URI in request line.
If nghttpx is invoked with :option:`--http2-proxy` (or its shorthand
:option:`-s`) option, it operates in HTTP/2 proxy mode. The supported
protocols in frontend and backend connections are the same in `default
mode`_. The difference is that this mode acts like forward proxy and
assumes the backend is HTTP/1 proxy server (e.g., squid, traffic
server). So HTTP/1 request must include absolute URI in request line.
By default, frontend connection is encrypted. So this mode is also
called secure proxy. If nghttpx is linked with spdylay, it supports
SPDY protocols and it works as so called SPDY proxy.
With ``--frontend-no-tls`` option, SSL/TLS is turned off in frontend
connection, so the connection gets insecure.
With :option:`--frontend-no-tls` option, SSL/TLS is turned off in
frontend connection, so the connection gets insecure.
The backend must be HTTP/1 proxy server. nghttpx supports multiple
backend server addresses. It translates incoming requests to HTTP/1
@@ -91,7 +100,9 @@ Chromium require valid certificate for secure proxy.
For Firefox, open Preference window and select Advanced then click
Network tab. Clicking Connection Settings button will show the
dialog. Select "Automatic proxy configuration URL" and enter the path
to proxy.pac file, something like this::
to proxy.pac file, something like this:
.. code-block:: text
file:///path/to/proxy.pac
@@ -107,25 +118,27 @@ configuration items to edit::
CONFIG proxy.config.url_remap.remap_required INT 0
Consult Traffic server `documentation
<https://docs.trafficserver.apache.org/en/latest/admin/forward-proxy.en.html>`_
<http://trafficserver.readthedocs.org/en/latest/admin-guide/configuration/transparent-forward-proxying.en.html>`_
to know how to configure traffic server as forward proxy and its
security implications.
Client mode
-----------
If nghttpx is invoked with ``--client`` option, it operates in client
mode. In this mode, nghttpx listens for plain, unencrypted HTTP/2 and
HTTP/1 requests and translates them to encrypted HTTP/2 requests to
the backend. User cannot enable SSL/TLS in frontend connection.
If nghttpx is invoked with :option:`--client` option, it operates in
client mode. In this mode, nghttpx listens for plain, unencrypted
HTTP/2 and HTTP/1 requests and translates them to encrypted HTTP/2
requests to the backend. User cannot enable SSL/TLS in frontend
connection.
HTTP/1 frontend connection can be upgraded to HTTP/2 using HTTP
Upgrade. To disable SSL/TLS in backend connection, use
``--backend-no-tls`` option.
:option:`--backend-no-tls` option.
By default, the number of backend HTTP/2 connections per worker
(thread) is determined by number of ``-b`` option. To adjust this
value, use ``--backend-http2-connections-per-worker`` option.
(thread) is determined by number of :option:`--backend` option. To
adjust this value, use
:option:`--backend-http2-connections-per-worker` option.
The backend server is supporsed to be a HTTP/2 web server (e.g.,
nghttpd). The one use-case of this mode is utilize existing HTTP/1
@@ -137,9 +150,10 @@ mode to access to that web server::
.. note::
You may need ``-k`` option if HTTP/2 server enables SSL/TLS and
its certificate is self-signed. But please note that it is
insecure.
You may need :option:`--insecure` (or its shorthand :option:`-k`)
option if HTTP/2 server enables SSL/TLS and its certificate is
self-signed. But please note that it is insecure, and you should
know what you are doing.
Then you can use curl to access HTTP/2 server via nghttpx::
@@ -148,18 +162,19 @@ Then you can use curl to access HTTP/2 server via nghttpx::
Client proxy mode
-----------------
If nghttpx is invoked with ``-p`` option, it operates in client proxy
mode. This mode behaves like `client mode`_, but it works like
forward proxy. So HTTP/1 request must include absolute URI in request
line.
If nghttpx is invoked with :option:`--client-proxy` (or its shorthand
:option:`-p`) option, it operates in client proxy mode. This mode
behaves like `client mode`_, but it works like forward proxy. So
HTTP/1 request must include absolute URI in request line.
HTTP/1 frontend connection can be upgraded to HTTP/2 using HTTP
Upgrade. To disable SSL/TLS in backend connection, use
``--backend-no-tls`` option.
:option:`--backend-no-tls` option.
By default, the number of backend HTTP/2 connections per worker
(thread) is determined by number of ``-b`` option. To adjust this
value, use ``--backend-http2-connections-per-worker`` option.
(thread) is determined by number of :option:`--backend` option. To
adjust this value, use
:option:`--backend-http2-connections-per-worker` option.
The backend server must be a HTTP/2 proxy. You can use nghttpx in
`HTTP/2 proxy mode`_ as backend server. The one use-case of this mode
@@ -177,8 +192,9 @@ that server, invoke nghttpx like this::
.. note::
You may need ``-k`` option if HTTP/2 server's certificate is
self-signed. But please note that it is insecure.
You may need :option:`--insecure` (or its shorthand :option:`-k`)
option if HTTP/2 server's certificate is self-signed. But please
note that it is insecure, and you should know what you are doing.
Then you can use curl to issue HTTP request via HTTP/2 proxy::
@@ -190,23 +206,24 @@ proxy.
HTTP/2 bridge mode
------------------
If nghttpx is invoked with ``--http2-bridge`` option, it operates in
HTTP/2 bridge mode. The supported protocols in frontend connections
are the same in `default mode`_. The protocol in backend is HTTP/2
only.
If nghttpx is invoked with :option:`--http2-bridge` option, it
operates in HTTP/2 bridge mode. The supported protocols in frontend
connections are the same in `default mode`_. The protocol in backend
is HTTP/2 only.
With ``--frontend-no-tls`` option, SSL/TLS is turned off in frontend
connection, so the connection gets insecure. To disable SSL/TLS in
backend connection, use ``--backend-no-tls`` option.
With :option:`--frontend-no-tls` option, SSL/TLS is turned off in
frontend connection, so the connection gets insecure. To disable
SSL/TLS in backend connection, use :option:`--backend-no-tls` option.
By default, the number of backend HTTP/2 connections per worker
(thread) is determined by number of ``-b`` option. To adjust this
value, use ``--backend-http2-connections-per-worker`` option.
(thread) is determined by number of :option:`--backend` option. To
adjust this value, use
:option:`--backend-http2-connections-per-worker` option.
The backend server is supporsed to be a HTTP/2 web server or HTTP/2
proxy. If backend server is HTTP/2 proxy, use
``--no-location-rewrite`` and ``--no-host-rewrite`` options to disable
rewriting location, host and :authority header field.
:option:`--no-location-rewrite` option to disable rewriting
``Location`` header field.
The use-case of this mode is aggregate the incoming connections to one
HTTP/2 connection. One backend HTTP/2 connection is created per
@@ -217,26 +234,48 @@ Disable SSL/TLS
In `default mode`_, `HTTP/2 proxy mode`_ and `HTTP/2 bridge mode`_,
frontend connections are encrypted with SSL/TLS by default. To turn
off SSL/TLS, use ``--frontend-no-tls`` option. If this option is
used, the private key and certificate are not required to run nghttpx.
off SSL/TLS, use :option:`--frontend-no-tls` option. If this option
is used, the private key and certificate are not required to run
nghttpx.
In `client mode`_, `client proxy mode`_ and `HTTP/2 bridge mode`_,
backend connections are encrypted with SSL/TLS by default. To turn
off SSL/TLS, use ``--backend-no-tls`` option.
off SSL/TLS, use :option:`--backend-no-tls` option.
Enable SSL/TLS on HTTP/1 backend
--------------------------------
In all modes which use HTTP/1 as backend protocol, backend HTTP/1
connection is not encrypted by default. To enable encryption, use
:option:`--backend-http1-tls` option.
Enable SSL/TLS on memcached connection
--------------------------------------
By default, memcached connection is not encrypted. To enable
encryption, use :option:`--tls-ticket-key-memcached-tls` for TLS
ticket key, and use :option:`--tls-session-cache-memcached-tls` for
TLS session cache.
Specifying additional server certificates
-----------------------------------------
nghttpx accepts additional server private key and certificate pairs
using :option:`--subcert` option. It can be used multiple times.
Specifying additional CA certificate
------------------------------------
By default, nghttpx tries to read CA certificate from system. But
depending on the system you use, this may fail or is not supported.
To specify CA certificate manually, use ``--cacert`` option. The
specified file must be PEM format and can contain multiple
To specify CA certificate manually, use :option:`--cacert` option.
The specified file must be PEM format and can contain multiple
certificates.
By default, nghttpx validates server's certificate. If you want to
turn off this validation, knowing this is really insecure and what you
are doing, you can use ``-k`` option to disable certificate
validation.
are doing, you can use :option:`--insecure` option to disable
certificate validation.
Read/write rate limit
---------------------
@@ -245,9 +284,9 @@ nghttpx supports transfer rate limiting on frontend connections. You
can do rate limit per frontend connection for reading and writing
individually.
To perform rate limit for reading, use ``--read-rate`` and
``--read-burst`` options. For writing, use ``--write-rate`` and
``--write-burst``.
To perform rate limit for reading, use :option:`--read-rate` and
:option:`--read-burst` options. For writing, use
:option:`--write-rate` and :option:`--write-burst`.
Please note that rate limit is performed on top of TCP and nothing to
do with HTTP/2 flow control.
@@ -289,14 +328,64 @@ Re-opening log files
When rotating log files, it is desirable to re-open log files after
log rotation daemon renamed existing log files. To tell nghttpx to
re-open log files, send USR1 signal to nghttpx process. It will
re-open files specified by ``--accesslog-file`` and
``--errorlog-file`` options.
re-open files specified by :option:`--accesslog-file` and
:option:`--errorlog-file` options.
Multiple backend addresses
--------------------------
nghttpx supports multiple backend addresses. To specify them, just
use ``-b`` option repeatedly. For example, to use backend1:8080 and
backend2:8080, use command-line like this: ``-bbackend1,8080
-bbackend2,8080``. For HTTP/2 backend, see also
``--backend-http2-connections-per-worker`` option.
use :option:`--backend` (or its shorthand :option:`-b`) option
repeatedly. For example, to use ``192.168.0.10:8080`` and
``192.168.0.11:8080``, use command-line like this:
``-b192.168.0.10,8080 -b192.168.0.11,8080``. In configuration file,
this looks like:
.. code-block:: text
backend=192.168.0.10,8080
backend=192.168.0.11,8008
nghttpx can route request to different backend according to request
host and path. For example, to route request destined to host
``doc.example.com`` to backend server ``docserv:3000``, you can write
like so:
.. code-block:: text
backend=docserv,3000;doc.example.com/
When you write this option in command-line, you should enclose
argument with single or double quotes, since the character ``;`` has a
special meaning in shell.
To route, request to request path whose prefix is ``/foo`` to backend
server ``[::1]:8080``, you can write like so:
.. code-block:: text
backend=::1,8080;/foo
Of course, you can specify both host and request path at the same
time.
One important thing you have to remember is that we have to specify
default routing pattern for so called "catch all" pattern. To write
"catch all" pattern, just specify backend server address, without
pattern.
Usually, host is the value of ``Host`` header field. In HTTP/2, the
value of ``:authority`` pseudo header field is used.
When you write multiple backend addresses sharing the same routing
pattern, they are used as load balancing. For example, to use 2
servers ``serv1:3000`` and ``serv2:3000`` for request host
``example.com`` and path ``/myservice``, you can write like so:
.. code-block:: text
backend=serv1,3000;example.com/myservice
backend=serv2,3000;example.com/myservice
For HTTP/2 backend, see also
:option:`--backend-http2-connections-per-worker` option.

View File

@@ -24,7 +24,7 @@
if ENABLE_EXAMPLES
AM_CFLAGS = $(WARNCFLAGS)
AM_CXXFLAGS = $(WARNCXXFLAGS)
AM_CXXFLAGS = $(WARNCXXFLAGS) $(CXX1XCXXFLAGS)
AM_CPPFLAGS = \
-I$(top_srcdir)/lib/includes \
-I$(top_builddir)/lib/includes \

View File

@@ -289,8 +289,6 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
return 0;
}
#define MAX_OUTLEN 4096
/*
* The implementation of nghttp2_on_data_chunk_recv_callback type. We
* use this function to print the received response body.

View File

@@ -295,7 +295,7 @@ static size_t http_date(char *buf, time_t t) {
static char date[29];
static size_t datelen;
static void update_date() { datelen = http_date(date, time(NULL)); }
static void update_date(void) { datelen = http_date(date, time(NULL)); }
static size_t utos(char *buf, size_t len, uint64_t n) {
size_t nwrite = 0;

32
genauthoritychartbl.py Executable file
View File

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

View File

@@ -62,11 +62,67 @@ HEADERS = [
('vary', 58),
('via', 59),
('www-authenticate', 60),
('te', None),
('accept-ch', None),
('accept-datetime', None),
('accept-features', None),
('accept-patch', None),
('access-control-allow-credentials', None),
('access-control-allow-headers', None),
('access-control-allow-methods', None),
('access-control-expose-headers', None),
('access-control-max-age', None),
('access-control-request-headers', None),
('access-control-request-method', None),
('alt-svc', None),
('alternates', None),
('connection', None),
('keep-alive',None),
('content-md5', None),
('content-security-policy', None),
('content-security-policy-report-only', None),
('dnt', None),
('forwarded', None),
('front-end-https', None),
('keep-alive', None),
('last-event-id', None),
('negotiate', None),
('origin', None),
('p3p', None),
('pragma', None),
('proxy-connection', None),
('public-key-pins', None),
('sec-websocket-extensions', None),
('sec-websocket-key', None),
('sec-websocket-origin', None),
('sec-websocket-protocol', None),
('sec-websocket-version', None),
('set-cookie2', None),
('status', None),
('tcn', None),
('te', None),
('trailer', None),
('tsv', None),
('upgrade', None),
('upgrade-insecure-requests', None),
('variant-vary', None),
('warning', None),
('x-api-version', None),
('x-att-deviceid', None),
('x-cache', None),
('x-cache-lookup', None),
('x-content-duration', None),
('x-content-security-policy', None),
('x-content-type-options', None),
('x-dnsprefetch-control', None),
('x-forwarded-for', None),
('x-forwarded-host', None),
('x-forwarded-proto', None),
('x-frame-options', None),
('x-powered-by', None),
('x-requested-with', None),
('x-ua-compatible', None),
('x-wap-profile', None),
('x-webkit-csp', None),
('x-xss-protection', None),
]
def to_enum_hd(k):

View File

@@ -88,12 +88,11 @@ OPTIONS = [
"fetch-ocsp-response-file",
"ocsp-update-interval",
"no-ocsp",
"header-field-buffer",
"max-header-fields",
"include",
"tls-ticket-key-cipher",
"host-rewrite",
"tls-session-cache-memcached",
"tls-session-cache-memcached-tls",
"tls-ticket-key-memcached",
"tls-ticket-key-memcached-interval",
"tls-ticket-key-memcached-max-retry",
@@ -107,7 +106,23 @@ OPTIONS = [
"add-forwarded",
"strip-incoming-forwarded",
"forwarded-by",
"forwarded-for"
"forwarded-for",
"response-header-field-buffer",
"max-response-header-fields",
"request-header-field-buffer",
"max-request-header-fields",
"header-field-buffer",
"max-header-fields",
"no-http2-cipher-black-list",
"backend-http1-tls",
"tls-session-cache-memcached-cert-file",
"tls-session-cache-memcached-private-key-file",
"tls-session-cache-memcached-address-family",
"tls-ticket-key-memcached-tls",
"tls-ticket-key-memcached-cert-file",
"tls-ticket-key-memcached-private-key-file",
"tls-ticket-key-memcached-address-family",
"backend-address-family"
]
LOGVARS = [

View File

@@ -21,11 +21,14 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
EXTRA_DIST = \
GO_FILES = \
nghttpx_http1_test.go \
nghttpx_http2_test.go \
nghttpx_spdy_test.go \
server_tester.go \
server_tester.go
EXTRA_DIST = \
$(GO_FILES) \
server.key \
server.crt \
alt-server.key \
@@ -43,4 +46,5 @@ itprep-local:
go get -d -v golang.org/x/net/websocket
it-local:
for i in $(GO_FILES); do [ -e $(builddir)/$$i ] || cp $(srcdir)/$$i $(builddir); done
sh setenv go test -v

View File

@@ -2,4 +2,5 @@ package nghttp2
const (
buildDir = "@top_builddir@"
sourceDir = "@top_srcdir@"
)

View File

@@ -29,7 +29,8 @@ import (
const (
serverBin = buildDir + "/src/nghttpx"
serverPort = 3009
testDir = buildDir + "/integration-tests"
testDir = sourceDir + "/integration-tests"
logDir = buildDir + "/integration-tests"
)
func pair(name, value string) hpack.HeaderField {
@@ -124,7 +125,7 @@ func newServerTesterInternal(args []string, t *testing.T, handler http.Handler,
// "127.0.0.1,8080"
b := "-b" + strings.Replace(backendURL.Host, ":", ",", -1)
args = append(args, fmt.Sprintf("-f127.0.0.1,%v", serverPort), b,
"--errorlog-file="+testDir+"/log.txt", "-LINFO")
"--errorlog-file="+logDir+"/log.txt", "-LINFO")
authority := fmt.Sprintf("127.0.0.1:%v", serverPort)

View File

@@ -15,7 +15,7 @@ THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
USE_CYTHON := 1
#USE_CYTHON := 0
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV], //g')
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -r -e 's/(-DEV)?], //g')
_VERSION := $(subst ., ,$(_VERSION))
VER_MAJOR := $(word 1,$(_VERSION))
VER_MINOR := $(word 2,$(_VERSION))

View File

@@ -382,6 +382,10 @@ typedef enum {
* Unexpected internal error, but recovered.
*/
NGHTTP2_ERR_INTERNAL = -534,
/**
* Indicates that a processing was canceled.
*/
NGHTTP2_ERR_CANCEL = -535,
/**
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
* under unexpected condition and processing was terminated (e.g.,
@@ -1608,6 +1612,14 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_header_callback()`.
*
* .. warning::
*
* Application should properly limit the total buffer size to store
* incoming header fields. Without it, peer may send large number
* of header fields or large header fields to cause out of memory in
* local endpoint. Due to how HPACK works, peer can do this
* effectively without using much memory on their own.
*/
typedef int (*nghttp2_on_header_callback)(nghttp2_session *session,
const nghttp2_frame *frame,
@@ -1692,6 +1704,99 @@ typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session,
const nghttp2_frame_hd *hd,
void *user_data);
/**
* @functypedef
*
* Callback function invoked when chunk of extension frame payload is
* received. The |hd| points to frame header. The received
* chunk is |data| of length |len|.
*
* The implementation of this function must return 0 if it succeeds.
*
* To abort processing this extension frame, return
* :enum:`NGHTTP2_ERR_CANCEL`.
*
* If fatal error occurred, application should return
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
* other values are returned, currently they are treated as
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef int (*nghttp2_on_extension_chunk_recv_callback)(
nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data,
size_t len, void *user_data);
/**
* @functypedef
*
* Callback function invoked when library asks the application to
* unpack extension payload from its wire format. The extension
* payload has been passed to the application using
* :type:`nghttp2_on_extension_chunk_recv_callback`. The frame header
* is already unpacked by the library and provided as |hd|.
*
* To receive extension frames, the application must tell desired
* extension frame type to the library using
* `nghttp2_option_set_user_recv_extension_type()`.
*
* The implementation of this function may store the pointer to the
* created object as a result of unpacking in |*payload|, and returns
* 0. The pointer stored in |*payload| is opaque to the library, and
* the library does not own its pointer. |*payload| is initialized as
* ``NULL``. The |*payload| is available as ``frame->ext.payload`` in
* :type:`nghttp2_on_frame_recv_callback`. Therefore if application
* can free that memory inside :type:`nghttp2_on_frame_recv_callback`
* callback. Of course, application has a liberty not ot use
* |*payload|, and do its own mechanism to process extension frames.
*
* To abort processing this extension frame, return
* :enum:`NGHTTP2_ERR_CANCEL`.
*
* If fatal error occurred, application should return
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
* other values are returned, currently they are treated as
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session,
void **payload,
const nghttp2_frame_hd *hd,
void *user_data);
/**
* @functypedef
*
* Callback function invoked when library asks the application to pack
* extension payload in its wire format. The frame header will be
* packed by library. Application must pack payload only.
* ``frame->ext.payload`` is the object passed to
* `nghttp2_submit_extension()` as payload parameter. Application
* must pack extension payload to the |buf| of its capacity |len|
* bytes. The |len| is at least 16KiB.
*
* The implementation of this function should return the number of
* bytes written into |buf| when it succeeds.
*
* To abort processing this extension frame, return
* :enum:`NGHTTP2_ERR_CANCEL`, and
* :type:`nghttp2_on_frame_not_send_callback` will be invoked.
*
* If fatal error occurred, application should return
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
* `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
* other values are returned, currently they are treated as
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the return value is
* strictly larger than |len|, it is treated as
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
uint8_t *buf, size_t len,
const nghttp2_frame *frame,
void *user_data);
struct nghttp2_session_callbacks;
/**
@@ -1884,6 +1989,37 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback(
nghttp2_session_callbacks *cbs,
nghttp2_send_data_callback send_data_callback);
/**
* @function
*
* Sets callback function invoked when the library asks the
* application to pack extension frame payload in wire format.
*/
NGHTTP2_EXTERN void nghttp2_session_callbacks_set_pack_extension_callback(
nghttp2_session_callbacks *cbs,
nghttp2_pack_extension_callback pack_extension_callback);
/**
* @function
*
* Sets callback function invoked when the library asks the
* application to unpack extension frame payload from wire format.
*/
NGHTTP2_EXTERN void nghttp2_session_callbacks_set_unpack_extension_callback(
nghttp2_session_callbacks *cbs,
nghttp2_unpack_extension_callback unpack_extension_callback);
/**
* @function
*
* Sets callback function invoked when chunk of extension frame
* payload is received.
*/
NGHTTP2_EXTERN void
nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback);
/**
* @functypedef
*
@@ -2098,6 +2234,23 @@ NGHTTP2_EXTERN void
nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
uint32_t val);
/**
* @function
*
* Sets extension frame type the application is willing to handle with
* user defined callbacks (see
* :type:`nghttp2_on_extension_chunk_recv_callback` and
* :type:`nghttp2_unpack_extension_callback`). The |type| is
* extension frame type, and must be strictly greater than 0x9.
* Otherwise, this function does nothing. The application can call
* this function multiple times to set more than one frame type to
* receive. The application does not have to call this function if it
* just sends extension frames.
*/
NGHTTP2_EXTERN void
nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
uint8_t type);
/**
* @function
*
@@ -3768,6 +3921,48 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
int32_t stream_id,
int32_t window_size_increment);
/**
* @function
*
* Submits extension frame.
*
* Application can pass arbitrary frame flags and stream ID in |flags|
* and |stream_id| respectively. The |payload| is opaque pointer, and
* it can be accessible though ``frame->ext.payload`` in
* :type:`nghttp2_pack_extension_callback`. The library will not own
* passed |payload| pointer.
*
* The application must set :type:`nghttp2_pack_extension_callback`
* using `nghttp2_session_callbacks_set_pack_extension_callback()`.
*
* The application should retain the memory pointed by |payload| until
* the transmission of extension frame is done (which is indicated by
* :type:`nghttp2_on_frame_send_callback`), or transmission fails
* (which is indicated by :type:`nghttp2_on_frame_not_send_callback`).
* If application does not touch this memory region after packing it
* into a wire format, application can free it inside
* :type:`nghttp2_pack_extension_callback`.
*
* The standard HTTP/2 frame cannot be sent with this function, so
* |type| must be strictly grater than 0x9. Otherwise, this function
* will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :enum:`NGHTTP2_ERR_INVALID_STATE`
* If :type:`nghttp2_pack_extension_callback` is not set.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* If |type| specifies standard HTTP/2 frame type. The frame
* types in the rage [0x0, 0x9], both inclusive, are standard
* HTTP/2 frame type, and cannot be sent using this function.
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory
*/
NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session,
uint8_t type, uint8_t flags,
int32_t stream_id, void *payload);
/**
* @function
*

View File

@@ -127,3 +127,21 @@ void nghttp2_session_callbacks_set_send_data_callback(
nghttp2_send_data_callback send_data_callback) {
cbs->send_data_callback = send_data_callback;
}
void nghttp2_session_callbacks_set_pack_extension_callback(
nghttp2_session_callbacks *cbs,
nghttp2_pack_extension_callback pack_extension_callback) {
cbs->pack_extension_callback = pack_extension_callback;
}
void nghttp2_session_callbacks_set_unpack_extension_callback(
nghttp2_session_callbacks *cbs,
nghttp2_unpack_extension_callback unpack_extension_callback) {
cbs->unpack_extension_callback = unpack_extension_callback;
}
void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) {
cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback;
}

View File

@@ -107,6 +107,9 @@ struct nghttp2_session_callbacks {
*/
nghttp2_on_begin_frame_callback on_begin_frame_callback;
nghttp2_send_data_callback send_data_callback;
nghttp2_pack_extension_callback pack_extension_callback;
nghttp2_unpack_extension_callback unpack_extension_callback;
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
};
#endif /* NGHTTP2_CALLBACKS_H */

View File

@@ -184,6 +184,15 @@ void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
void nghttp2_frame_data_free(nghttp2_data *frame _U_) {}
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
uint8_t flags, int32_t stream_id,
void *payload) {
nghttp2_frame_hd_init(&frame->hd, 0, type, flags, stream_id);
frame->payload = payload;
}
void nghttp2_frame_extension_free(nghttp2_extension *frame _U_) {}
size_t nghttp2_frame_priority_len(uint8_t flags) {
if (flags & NGHTTP2_FLAG_PRIORITY) {
return NGHTTP2_PRIORITY_SPECLEN;

View File

@@ -439,6 +439,12 @@ void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
uint8_t flags, int32_t stream_id,
void *payload);
void nghttp2_frame_extension_free(nghttp2_extension *frame);
/*
* Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does

View File

@@ -137,6 +137,26 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
return NGHTTP2_TOKEN_AGE;
}
break;
case 'n':
if (lstreq("tc", name, 2)) {
return NGHTTP2_TOKEN_TCN;
}
break;
case 'p':
if (lstreq("p3", name, 2)) {
return NGHTTP2_TOKEN_P3P;
}
break;
case 't':
if (lstreq("dn", name, 2)) {
return NGHTTP2_TOKEN_DNT;
}
break;
case 'v':
if (lstreq("ts", name, 2)) {
return NGHTTP2_TOKEN_TSV;
}
break;
}
break;
case 4:
@@ -197,16 +217,31 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
break;
case 6:
switch (name[5]) {
case 'a':
if (lstreq("pragm", name, 5)) {
return NGHTTP2_TOKEN_PRAGMA;
}
break;
case 'e':
if (lstreq("cooki", name, 5)) {
return NGHTTP2_TOKEN_COOKIE;
}
break;
case 'n':
if (lstreq("origi", name, 5)) {
return NGHTTP2_TOKEN_ORIGIN;
}
break;
case 'r':
if (lstreq("serve", name, 5)) {
return NGHTTP2_TOKEN_SERVER;
}
break;
case 's':
if (lstreq("statu", name, 5)) {
return NGHTTP2_TOKEN_STATUS;
}
break;
case 't':
if (lstreq("accep", name, 5)) {
return NGHTTP2_TOKEN_ACCEPT;
@@ -219,6 +254,11 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
break;
case 7:
switch (name[6]) {
case 'c':
if (lstreq("alt-sv", name, 6)) {
return NGHTTP2_TOKEN_ALT_SVC;
}
break;
case 'd':
if (lstreq(":metho", name, 6)) {
return NGHTTP2_TOKEN__METHOD;
@@ -237,6 +277,14 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
if (lstreq("upgrad", name, 6)) {
return NGHTTP2_TOKEN_UPGRADE;
}
if (lstreq("x-cach", name, 6)) {
return NGHTTP2_TOKEN_X_CACHE;
}
break;
case 'g':
if (lstreq("warnin", name, 6)) {
return NGHTTP2_TOKEN_WARNING;
}
break;
case 'h':
if (lstreq("refres", name, 6)) {
@@ -247,6 +295,9 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
if (lstreq("refere", name, 6)) {
return NGHTTP2_TOKEN_REFERER;
}
if (lstreq("traile", name, 6)) {
return NGHTTP2_TOKEN_TRAILER;
}
break;
case 's':
if (lstreq(":statu", name, 6)) {
@@ -295,6 +346,25 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
break;
}
break;
case 9:
switch (name[8]) {
case 'd':
if (lstreq("forwarde", name, 8)) {
return NGHTTP2_TOKEN_FORWARDED;
}
break;
case 'e':
if (lstreq("negotiat", name, 8)) {
return NGHTTP2_TOKEN_NEGOTIATE;
}
break;
case 'h':
if (lstreq("accept-c", name, 8)) {
return NGHTTP2_TOKEN_ACCEPT_CH;
}
break;
}
break;
case 10:
switch (name[9]) {
case 'e':
@@ -310,6 +380,11 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
return NGHTTP2_TOKEN_CONNECTION;
}
break;
case 's':
if (lstreq("alternate", name, 9)) {
return NGHTTP2_TOKEN_ALTERNATES;
}
break;
case 't':
if (lstreq("user-agen", name, 9)) {
return NGHTTP2_TOKEN_USER_AGENT;
@@ -324,6 +399,16 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
break;
case 11:
switch (name[10]) {
case '2':
if (lstreq("set-cookie", name, 10)) {
return NGHTTP2_TOKEN_SET_COOKIE2;
}
break;
case '5':
if (lstreq("content-md", name, 10)) {
return NGHTTP2_TOKEN_CONTENT_MD5;
}
break;
case 'r':
if (lstreq("retry-afte", name, 10)) {
return NGHTTP2_TOKEN_RETRY_AFTER;
@@ -338,16 +423,37 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
return NGHTTP2_TOKEN_CONTENT_TYPE;
}
break;
case 'h':
if (lstreq("accept-patc", name, 11)) {
return NGHTTP2_TOKEN_ACCEPT_PATCH;
}
break;
case 'p':
if (lstreq("x-webkit-cs", name, 11)) {
return NGHTTP2_TOKEN_X_WEBKIT_CSP;
}
break;
case 's':
if (lstreq("max-forward", name, 11)) {
return NGHTTP2_TOKEN_MAX_FORWARDS;
}
break;
case 'y':
if (lstreq("variant-var", name, 11)) {
return NGHTTP2_TOKEN_VARIANT_VARY;
}
if (lstreq("x-powered-b", name, 11)) {
return NGHTTP2_TOKEN_X_POWERED_BY;
}
break;
}
break;
case 13:
switch (name[12]) {
case 'd':
if (lstreq("last-event-i", name, 12)) {
return NGHTTP2_TOKEN_LAST_EVENT_ID;
}
if (lstreq("last-modifie", name, 12)) {
return NGHTTP2_TOKEN_LAST_MODIFIED;
}
@@ -356,6 +462,9 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
if (lstreq("content-rang", name, 12)) {
return NGHTTP2_TOKEN_CONTENT_RANGE;
}
if (lstreq("x-wap-profil", name, 12)) {
return NGHTTP2_TOKEN_X_WAP_PROFILE;
}
break;
case 'h':
if (lstreq("if-none-matc", name, 12)) {
@@ -371,6 +480,9 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
if (lstreq("authorizatio", name, 12)) {
return NGHTTP2_TOKEN_AUTHORIZATION;
}
if (lstreq("x-api-versio", name, 12)) {
return NGHTTP2_TOKEN_X_API_VERSION;
}
break;
case 's':
if (lstreq("accept-range", name, 12)) {
@@ -381,11 +493,21 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
break;
case 14:
switch (name[13]) {
case 'd':
if (lstreq("x-att-devicei", name, 13)) {
return NGHTTP2_TOKEN_X_ATT_DEVICEID;
}
break;
case 'h':
if (lstreq("content-lengt", name, 13)) {
return NGHTTP2_TOKEN_CONTENT_LENGTH;
}
break;
case 'p':
if (lstreq("x-cache-looku", name, 13)) {
return NGHTTP2_TOKEN_X_CACHE_LOOKUP;
}
break;
case 't':
if (lstreq("accept-charse", name, 13)) {
return NGHTTP2_TOKEN_ACCEPT_CHARSET;
@@ -396,15 +518,40 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
case 15:
switch (name[14]) {
case 'e':
if (lstreq("accept-datetim", name, 14)) {
return NGHTTP2_TOKEN_ACCEPT_DATETIME;
}
if (lstreq("accept-languag", name, 14)) {
return NGHTTP2_TOKEN_ACCEPT_LANGUAGE;
}
if (lstreq("x-ua-compatibl", name, 14)) {
return NGHTTP2_TOKEN_X_UA_COMPATIBLE;
}
break;
case 'g':
if (lstreq("accept-encodin", name, 14)) {
return NGHTTP2_TOKEN_ACCEPT_ENCODING;
}
break;
case 'r':
if (lstreq("x-forwarded-fo", name, 14)) {
return NGHTTP2_TOKEN_X_FORWARDED_FOR;
}
break;
case 's':
if (lstreq("accept-feature", name, 14)) {
return NGHTTP2_TOKEN_ACCEPT_FEATURES;
}
if (lstreq("front-end-http", name, 14)) {
return NGHTTP2_TOKEN_FRONT_END_HTTPS;
}
if (lstreq("public-key-pin", name, 14)) {
return NGHTTP2_TOKEN_PUBLIC_KEY_PINS;
}
if (lstreq("x-frame-option", name, 14)) {
return NGHTTP2_TOKEN_X_FRAME_OPTIONS;
}
break;
}
break;
case 16:
@@ -422,6 +569,11 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
return NGHTTP2_TOKEN_CONTENT_ENCODING;
}
break;
case 'h':
if (lstreq("x-requested-wit", name, 15)) {
return NGHTTP2_TOKEN_X_REQUESTED_WITH;
}
break;
case 'n':
if (lstreq("content-locatio", name, 15)) {
return NGHTTP2_TOKEN_CONTENT_LOCATION;
@@ -429,6 +581,14 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
if (lstreq("proxy-connectio", name, 15)) {
return NGHTTP2_TOKEN_PROXY_CONNECTION;
}
if (lstreq("x-xss-protectio", name, 15)) {
return NGHTTP2_TOKEN_X_XSS_PROTECTION;
}
break;
case 't':
if (lstreq("x-forwarded-hos", name, 15)) {
return NGHTTP2_TOKEN_X_FORWARDED_HOST;
}
break;
}
break;
@@ -444,6 +604,16 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
return NGHTTP2_TOKEN_TRANSFER_ENCODING;
}
break;
case 'o':
if (lstreq("x-forwarded-prot", name, 16)) {
return NGHTTP2_TOKEN_X_FORWARDED_PROTO;
}
break;
case 'y':
if (lstreq("sec-websocket-ke", name, 16)) {
return NGHTTP2_TOKEN_SEC_WEBSOCKET_KEY;
}
break;
}
break;
case 18:
@@ -453,6 +623,11 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
return NGHTTP2_TOKEN_PROXY_AUTHENTICATE;
}
break;
case 'n':
if (lstreq("x-content-duratio", name, 17)) {
return NGHTTP2_TOKEN_X_CONTENT_DURATION;
}
break;
}
break;
case 19:
@@ -472,12 +647,80 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
break;
}
break;
case 20:
switch (name[19]) {
case 'n':
if (lstreq("sec-websocket-origi", name, 19)) {
return NGHTTP2_TOKEN_SEC_WEBSOCKET_ORIGIN;
}
break;
}
break;
case 21:
switch (name[20]) {
case 'l':
if (lstreq("x-dnsprefetch-contro", name, 20)) {
return NGHTTP2_TOKEN_X_DNSPREFETCH_CONTROL;
}
break;
case 'n':
if (lstreq("sec-websocket-versio", name, 20)) {
return NGHTTP2_TOKEN_SEC_WEBSOCKET_VERSION;
}
break;
}
break;
case 22:
switch (name[21]) {
case 'e':
if (lstreq("access-control-max-ag", name, 21)) {
return NGHTTP2_TOKEN_ACCESS_CONTROL_MAX_AGE;
}
break;
case 'l':
if (lstreq("sec-websocket-protoco", name, 21)) {
return NGHTTP2_TOKEN_SEC_WEBSOCKET_PROTOCOL;
}
break;
case 's':
if (lstreq("x-content-type-option", name, 21)) {
return NGHTTP2_TOKEN_X_CONTENT_TYPE_OPTIONS;
}
break;
}
break;
case 23:
switch (name[22]) {
case 'y':
if (lstreq("content-security-polic", name, 22)) {
return NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY;
}
break;
}
break;
case 24:
switch (name[23]) {
case 's':
if (lstreq("sec-websocket-extension", name, 23)) {
return NGHTTP2_TOKEN_SEC_WEBSOCKET_EXTENSIONS;
}
break;
}
break;
case 25:
switch (name[24]) {
case 's':
if (lstreq("upgrade-insecure-request", name, 24)) {
return NGHTTP2_TOKEN_UPGRADE_INSECURE_REQUESTS;
}
break;
case 'y':
if (lstreq("strict-transport-securit", name, 24)) {
return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY;
}
if (lstreq("x-content-security-polic", name, 24)) {
return NGHTTP2_TOKEN_X_CONTENT_SECURITY_POLICY;
}
break;
}
break;
@@ -490,6 +733,59 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
break;
}
break;
case 28:
switch (name[27]) {
case 's':
if (lstreq("access-control-allow-header", name, 27)) {
return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS;
}
if (lstreq("access-control-allow-method", name, 27)) {
return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_METHODS;
}
break;
}
break;
case 29:
switch (name[28]) {
case 'd':
if (lstreq("access-control-request-metho", name, 28)) {
return NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_METHOD;
}
break;
case 's':
if (lstreq("access-control-expose-header", name, 28)) {
return NGHTTP2_TOKEN_ACCESS_CONTROL_EXPOSE_HEADERS;
}
break;
}
break;
case 30:
switch (name[29]) {
case 's':
if (lstreq("access-control-request-header", name, 29)) {
return NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_HEADERS;
}
break;
}
break;
case 32:
switch (name[31]) {
case 's':
if (lstreq("access-control-allow-credential", name, 31)) {
return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS;
}
break;
}
break;
case 35:
switch (name[34]) {
case 'y':
if (lstreq("content-security-policy-report-onl", name, 34)) {
return NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY_REPORT_ONLY;
}
break;
}
break;
}
return -1;
}
@@ -617,8 +913,8 @@ static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match,
*exact_match = 0;
for (p = map->table[hash & (HD_MAP_SIZE - 1)]; p; p = p->next) {
if (hash != p->hash || token != p->token ||
(token == -1 && !name_eq(&p->nv, nv))) {
if (token != p->token ||
(token == -1 && (hash != p->hash || !name_eq(&p->nv, nv)))) {
continue;
}
if (!res) {
@@ -1444,7 +1740,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
int indexing_mode;
int token;
nghttp2_mem *mem;
uint32_t hash;
uint32_t hash = 0;
DEBUGF(fprintf(stderr, "deflatehd: deflating %.*s: %.*s\n", (int)nv->namelen,
nv->name, (int)nv->valuelen, nv->value));
@@ -1452,9 +1748,9 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
mem = deflater->ctx.mem;
token = lookup_token(nv->name, nv->namelen);
if (token == -1 || token > NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
if (token == -1) {
hash = name_hash(nv);
} else {
} else if (token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
hash = static_table[token].hash;
}

View File

@@ -105,11 +105,67 @@ typedef enum {
NGHTTP2_TOKEN_VARY = 58,
NGHTTP2_TOKEN_VIA = 59,
NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
NGHTTP2_TOKEN_TE,
NGHTTP2_TOKEN_ACCEPT_CH,
NGHTTP2_TOKEN_ACCEPT_DATETIME,
NGHTTP2_TOKEN_ACCEPT_FEATURES,
NGHTTP2_TOKEN_ACCEPT_PATCH,
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS,
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS,
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_METHODS,
NGHTTP2_TOKEN_ACCESS_CONTROL_EXPOSE_HEADERS,
NGHTTP2_TOKEN_ACCESS_CONTROL_MAX_AGE,
NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_HEADERS,
NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_METHOD,
NGHTTP2_TOKEN_ALT_SVC,
NGHTTP2_TOKEN_ALTERNATES,
NGHTTP2_TOKEN_CONNECTION,
NGHTTP2_TOKEN_CONTENT_MD5,
NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY,
NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY_REPORT_ONLY,
NGHTTP2_TOKEN_DNT,
NGHTTP2_TOKEN_FORWARDED,
NGHTTP2_TOKEN_FRONT_END_HTTPS,
NGHTTP2_TOKEN_KEEP_ALIVE,
NGHTTP2_TOKEN_LAST_EVENT_ID,
NGHTTP2_TOKEN_NEGOTIATE,
NGHTTP2_TOKEN_ORIGIN,
NGHTTP2_TOKEN_P3P,
NGHTTP2_TOKEN_PRAGMA,
NGHTTP2_TOKEN_PROXY_CONNECTION,
NGHTTP2_TOKEN_UPGRADE
NGHTTP2_TOKEN_PUBLIC_KEY_PINS,
NGHTTP2_TOKEN_SEC_WEBSOCKET_EXTENSIONS,
NGHTTP2_TOKEN_SEC_WEBSOCKET_KEY,
NGHTTP2_TOKEN_SEC_WEBSOCKET_ORIGIN,
NGHTTP2_TOKEN_SEC_WEBSOCKET_PROTOCOL,
NGHTTP2_TOKEN_SEC_WEBSOCKET_VERSION,
NGHTTP2_TOKEN_SET_COOKIE2,
NGHTTP2_TOKEN_STATUS,
NGHTTP2_TOKEN_TCN,
NGHTTP2_TOKEN_TE,
NGHTTP2_TOKEN_TRAILER,
NGHTTP2_TOKEN_TSV,
NGHTTP2_TOKEN_UPGRADE,
NGHTTP2_TOKEN_UPGRADE_INSECURE_REQUESTS,
NGHTTP2_TOKEN_VARIANT_VARY,
NGHTTP2_TOKEN_WARNING,
NGHTTP2_TOKEN_X_API_VERSION,
NGHTTP2_TOKEN_X_ATT_DEVICEID,
NGHTTP2_TOKEN_X_CACHE,
NGHTTP2_TOKEN_X_CACHE_LOOKUP,
NGHTTP2_TOKEN_X_CONTENT_DURATION,
NGHTTP2_TOKEN_X_CONTENT_SECURITY_POLICY,
NGHTTP2_TOKEN_X_CONTENT_TYPE_OPTIONS,
NGHTTP2_TOKEN_X_DNSPREFETCH_CONTROL,
NGHTTP2_TOKEN_X_FORWARDED_FOR,
NGHTTP2_TOKEN_X_FORWARDED_HOST,
NGHTTP2_TOKEN_X_FORWARDED_PROTO,
NGHTTP2_TOKEN_X_FRAME_OPTIONS,
NGHTTP2_TOKEN_X_POWERED_BY,
NGHTTP2_TOKEN_X_REQUESTED_WITH,
NGHTTP2_TOKEN_X_UA_COMPATIBLE,
NGHTTP2_TOKEN_X_WAP_PROFILE,
NGHTTP2_TOKEN_X_WEBKIT_CSP,
NGHTTP2_TOKEN_X_XSS_PROTECTION,
} nghttp2_token;
typedef enum {

View File

@@ -288,6 +288,8 @@ const char *nghttp2_strerror(int error_code) {
return "Stream was refused";
case NGHTTP2_ERR_INTERNAL:
return "Internal error";
case NGHTTP2_ERR_CANCEL:
return "Cancel";
case NGHTTP2_ERR_NOMEM:
return "Out of memory";
case NGHTTP2_ERR_CALLBACK_FAILURE:

View File

@@ -25,9 +25,9 @@
#ifndef NGHTTP2_NPN_H
#define NGHTTP2_NPN_H
#ifdef HAVE_CONFIG
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG */
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>

View File

@@ -62,3 +62,14 @@ void nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
option->opt_set_mask |= NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS;
option->max_reserved_remote_streams = val;
}
void nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
uint8_t type) {
if (type < 10) {
return;
}
option->opt_set_mask |= NGHTTP2_OPT_USER_RECV_EXT_TYPES;
option->user_recv_ext_types[type / 8] =
(uint8_t)(option->user_recv_ext_types[type / 8] | (1 << (type & 0x7)));
}

View File

@@ -59,7 +59,8 @@ typedef enum {
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5
} nghttp2_option_flag;
/**
@@ -91,6 +92,10 @@ struct nghttp2_option {
* NGHTTP2_OPT_NO_HTTP_MESSAGING
*/
int no_http_messaging;
/**
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
*/
uint8_t user_recv_ext_types[32];
};
#endif /* NGHTTP2_OPTION_H */

View File

@@ -72,6 +72,9 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
case NGHTTP2_WINDOW_UPDATE:
nghttp2_frame_window_update_free(&frame->window_update);
break;
default:
nghttp2_frame_extension_free(&frame->ext);
break;
}
}

View File

@@ -231,6 +231,8 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
nghttp2_session_new(), we rely on the fact that
iframe->frame.hd.type is 0, so that no free is performed. */
switch (iframe->frame.hd.type) {
case NGHTTP2_DATA:
break;
case NGHTTP2_HEADERS:
nghttp2_frame_headers_free(&iframe->frame.headers, mem);
break;
@@ -255,6 +257,10 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
case NGHTTP2_WINDOW_UPDATE:
nghttp2_frame_window_update_free(&iframe->frame.window_update);
break;
default:
/* extension frame */
nghttp2_frame_extension_free(&iframe->frame.ext);
break;
}
memset(&iframe->frame, 0, sizeof(nghttp2_frame));
@@ -405,6 +411,11 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_HTTP_MESSAGING;
}
if (option->opt_set_mask & NGHTTP2_OPT_USER_RECV_EXT_TYPES) {
memcpy((*session_ptr)->user_recv_ext_types, option->user_recv_ext_types,
sizeof((*session_ptr)->user_recv_ext_types));
}
}
(*session_ptr)->callbacks = *callbacks;
@@ -1216,11 +1227,12 @@ int nghttp2_session_adjust_idle_stream(nghttp2_session *session) {
size_t max;
int rv;
/* Make minimum number of idle streams 16, which is arbitrary chosen
number. */
max = nghttp2_max(16,
nghttp2_min(session->local_settings.max_concurrent_streams,
session->pending_local_max_concurrent_stream));
/* Make minimum number of idle streams 16, and maximum 100, which
are arbitrary chosen numbers. */
max = nghttp2_min(
100, nghttp2_max(
16, nghttp2_min(session->local_settings.max_concurrent_streams,
session->pending_local_max_concurrent_stream)));
DEBUGF(fprintf(stderr, "stream: adjusting kept idle streams "
"num_idle_streams=%zu, max=%zu\n",
@@ -1291,7 +1303,9 @@ static int session_allow_incoming_new_stream(nghttp2_session *session) {
* This function returns nonzero if session is closing.
*/
static int session_is_closing(nghttp2_session *session) {
return (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) != 0;
return (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) != 0 ||
(nghttp2_session_want_read(session) == 0 &&
nghttp2_session_want_write(session) == 0);
}
/*
@@ -1322,8 +1336,8 @@ static int session_predicate_for_stream_send(nghttp2_session *session,
int nghttp2_session_check_request_allowed(nghttp2_session *session) {
return !session->server && session->next_stream_id <= INT32_MAX &&
(session->goaway_flags &
(NGHTTP2_GOAWAY_TERM_ON_SEND | NGHTTP2_GOAWAY_RECV)) == 0;
(session->goaway_flags & NGHTTP2_GOAWAY_RECV) == 0 &&
!session_is_closing(session);
}
/*
@@ -1345,10 +1359,11 @@ static int session_predicate_request_headers_send(nghttp2_session *session,
if (item->aux_data.headers.canceled) {
return NGHTTP2_ERR_STREAM_CLOSING;
}
/* If we are terminating session (NGHTTP2_GOAWAY_TERM_ON_SEND) or
GOAWAY was received from peer, new request is not allowed. */
if (session->goaway_flags &
(NGHTTP2_GOAWAY_TERM_ON_SEND | NGHTTP2_GOAWAY_RECV)) {
/* If we are terminating session (NGHTTP2_GOAWAY_TERM_ON_SEND),
GOAWAY was received from peer, or session is about to close, new
request is not allowed. */
if ((session->goaway_flags & NGHTTP2_GOAWAY_RECV) ||
session_is_closing(session)) {
return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED;
}
return 0;
@@ -1745,6 +1760,41 @@ static size_t session_estimate_headers_payload(nghttp2_session *session,
additional;
}
static int session_pack_extension(nghttp2_session *session, nghttp2_bufs *bufs,
nghttp2_frame *frame) {
ssize_t rv;
nghttp2_buf *buf;
size_t buflen;
size_t framelen;
assert(session->callbacks.pack_extension_callback);
buf = &bufs->head->buf;
buflen = nghttp2_min(nghttp2_buf_avail(buf), NGHTTP2_MAX_PAYLOADLEN);
rv = session->callbacks.pack_extension_callback(session, buf->last, buflen,
frame, session->user_data);
if (rv == NGHTTP2_ERR_CANCEL) {
return (int)rv;
}
if (rv < 0 || (size_t)rv > buflen) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
framelen = (size_t)rv;
frame->hd.length = framelen;
assert(buf->pos == buf->last);
buf->last += framelen;
buf->pos -= NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
return 0;
}
/*
* This function serializes frame for transmission.
*
@@ -1903,6 +1953,13 @@ static int session_prep_frame(nghttp2_session *session,
if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
assert(session->obq_flood_counter_ > 0);
--session->obq_flood_counter_;
/* When session is about to close, don't send SETTINGS ACK.
We are required to send SETTINGS without ACK though; for
example, we have to send SETTINGS as a part of connection
preface. */
if (session_is_closing(session)) {
return NGHTTP2_ERR_SESSION_CLOSING;
}
}
rv = nghttp2_frame_pack_settings(&session->aob.framebufs,
@@ -1978,8 +2035,22 @@ static int session_prep_frame(nghttp2_session *session,
nghttp2_frame_pack_window_update(&session->aob.framebufs,
&frame->window_update);
break;
case NGHTTP2_CONTINUATION:
/* We never handle CONTINUATION here. */
assert(0);
break;
default:
return NGHTTP2_ERR_INVALID_ARGUMENT;
/* extension frame */
if (session_is_closing(session)) {
return NGHTTP2_ERR_SESSION_CLOSING;
}
rv = session_pack_extension(session, &session->aob.framebufs, frame);
if (rv != 0) {
return rv;
}
break;
}
return 0;
} else {
@@ -3063,6 +3134,47 @@ static int session_call_on_header(nghttp2_session *session,
return 0;
}
static int
session_call_on_extension_chunk_recv_callback(nghttp2_session *session,
const uint8_t *data, size_t len) {
int rv;
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
if (session->callbacks.on_extension_chunk_recv_callback) {
rv = session->callbacks.on_extension_chunk_recv_callback(
session, &frame->hd, data, len, session->user_data);
if (rv == NGHTTP2_ERR_CANCEL) {
return rv;
}
if (rv != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
return 0;
}
static int session_call_unpack_extension_callback(nghttp2_session *session) {
int rv;
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
void *payload = NULL;
rv = session->callbacks.unpack_extension_callback(
session, &payload, &frame->hd, session->user_data);
if (rv == NGHTTP2_ERR_CANCEL) {
return rv;
}
if (rv != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
frame->ext.payload = payload;
return 0;
}
/*
* Handles frame size error.
*
@@ -4401,6 +4513,24 @@ static int session_process_window_update_frame(nghttp2_session *session) {
return nghttp2_session_on_window_update_received(session, frame);
}
static int session_process_extension_frame(nghttp2_session *session) {
int rv;
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
rv = session_call_unpack_extension_callback(session);
if (nghttp2_is_fatal(rv)) {
return rv;
}
/* This handles the case where rv == NGHTTP2_ERR_CANCEL as well */
if (rv != 0) {
return 0;
}
return session_call_on_frame_received(session, frame);
}
int nghttp2_session_on_data_received(nghttp2_session *session,
nghttp2_frame *frame) {
int rv = 0;
@@ -5219,11 +5349,21 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
default:
DEBUGF(fprintf(stderr, "recv: unknown frame\n"));
/* Silently ignore unknown frame type. */
if (!session->callbacks.unpack_extension_callback ||
(session->user_recv_ext_types[iframe->frame.hd.type / 8] &
(1 << (iframe->frame.hd.type & 0x7))) == 0) {
/* Silently ignore unknown frame type. */
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break;
}
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
iframe->state = NGHTTP2_IB_READ_EXTENSION_PAYLOAD;
break;
}
@@ -5630,10 +5770,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
readlen = inbound_frame_payload_readlen(iframe, in, last);
iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen);
if (readlen > 0) {
iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen);
iframe->payloadleft -= readlen;
in += readlen;
iframe->payloadleft -= readlen;
in += readlen;
}
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", readlen,
iframe->payloadleft));
@@ -5921,6 +6063,44 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break;
case NGHTTP2_IB_IGN_ALL:
return (ssize_t)inlen;
case NGHTTP2_IB_READ_EXTENSION_PAYLOAD:
DEBUGF(fprintf(stderr, "recv: [IB_READ_EXTENSION_PAYLOAD]\n"));
readlen = inbound_frame_payload_readlen(iframe, in, last);
iframe->payloadleft -= readlen;
in += readlen;
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", readlen,
iframe->payloadleft));
if (readlen > 0) {
rv = session_call_on_extension_chunk_recv_callback(
session, in - readlen, readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (rv != 0) {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break;
}
}
if (iframe->payloadleft > 0) {
break;
}
rv = session_process_extension_frame(session);
if (nghttp2_is_fatal(rv)) {
return rv;
}
session_inbound_frame_reset(session);
break;
}
if (!busy && in == last) {

View File

@@ -105,7 +105,8 @@ typedef enum {
NGHTTP2_IB_READ_PAD_DATA,
NGHTTP2_IB_READ_DATA,
NGHTTP2_IB_IGN_DATA,
NGHTTP2_IB_IGN_ALL
NGHTTP2_IB_IGN_ALL,
NGHTTP2_IB_READ_EXTENSION_PAYLOAD
} nghttp2_inbound_state;
#define NGHTTP2_INBOUND_NUM_IV 7
@@ -304,6 +305,13 @@ struct nghttp2_session {
this session. The nonzero does not necessarily mean
WINDOW_UPDATE is not queued. */
uint8_t window_update_queued;
/* Bitfield of extension frame types that application is willing to
receive. To designate the bit of given frame type i, use
user_recv_ext_types[i / 8] & (1 << (i & 0x7)). First 10 frame
types are standard frame types and not used in this bitfield. If
bit is set, it indicates that incoming frame with that type is
passed to user defined callbacks, otherwise they are ignored. */
uint8_t user_recv_ext_types[32];
};
/* Struct used when updating initial window size of each active

View File

@@ -30,14 +30,32 @@
#include "nghttp2_session.h"
#include "nghttp2_helper.h"
/* Maximum distance between any two stream's cycle in the same
prirority queue. Imagine stream A's cycle is A, and stream B's
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
may get overflow. Because of how we calculate the next cycle
value, if B - A is less than or equals to
NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other
words, B is really greater than or equal to A. Otherwise, A is a
result of overflow, and it is actually A > B if we consider that
fact. */
#define NGHTTP2_MAX_CYCLE_DISTANCE (16384 * 256 + 255)
static int stream_less(const void *lhsx, const void *rhsx) {
const nghttp2_stream *lhs, *rhs;
lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
return lhs->cycle < rhs->cycle ||
(lhs->cycle == rhs->cycle && lhs->seq < rhs->seq);
if (lhs->cycle == rhs->cycle) {
return lhs->seq < rhs->seq;
}
if (lhs->cycle < rhs->cycle) {
return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE;
}
return lhs->cycle - rhs->cycle > NGHTTP2_MAX_CYCLE_DISTANCE;
}
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
@@ -116,14 +134,14 @@ static int stream_subtree_active(nghttp2_stream *stream) {
/*
* Returns next cycle for |stream|.
*/
static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) {
size_t penalty;
static void stream_next_cycle(nghttp2_stream *stream, uint32_t last_cycle) {
uint32_t penalty;
penalty =
stream->last_writelen * NGHTTP2_MAX_WEIGHT + stream->pending_penalty;
penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT +
stream->pending_penalty;
stream->cycle = last_cycle + penalty / (uint32_t)stream->weight;
stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight);
stream->pending_penalty = penalty % (uint32_t)stream->weight;
}
static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
@@ -229,9 +247,9 @@ void nghttp2_stream_reschedule(nghttp2_stream *stream) {
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
nghttp2_stream *dep_stream;
uint64_t last_cycle;
uint32_t last_cycle;
int32_t old_weight;
size_t wlen_penalty;
uint32_t wlen_penalty;
if (stream->weight == weight) {
return;
@@ -254,7 +272,7 @@ void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
wlen_penalty = stream->last_writelen * NGHTTP2_MAX_WEIGHT;
wlen_penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;
/* Compute old stream->pending_penalty we used to calculate
stream->cycle */
@@ -270,7 +288,9 @@ void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
place */
stream_next_cycle(stream, last_cycle);
if (stream->cycle < dep_stream->descendant_last_cycle) {
if (stream->cycle < dep_stream->descendant_last_cycle &&
(dep_stream->descendant_last_cycle - stream->cycle) <=
NGHTTP2_MAX_CYCLE_DISTANCE) {
stream->cycle = dep_stream->descendant_last_cycle;
}

View File

@@ -147,9 +147,9 @@ struct nghttp2_stream {
/* Received body so far */
int64_t recv_content_length;
/* Base last_cycle for direct descendent streams. */
uint64_t descendant_last_cycle;
uint32_t descendant_last_cycle;
/* Next scheduled time to sent item */
uint64_t cycle;
uint32_t cycle;
/* Next seq used for direct descendant streams */
uint64_t descendant_next_seq;
/* Secondary key for prioritization to break a tie for cycle. This

View File

@@ -530,3 +530,40 @@ ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
return (ssize_t)nghttp2_frame_pack_settings_payload(buf, iv, niv);
}
int nghttp2_submit_extension(nghttp2_session *session, uint8_t type,
uint8_t flags, int32_t stream_id, void *payload) {
int rv;
nghttp2_outbound_item *item;
nghttp2_frame *frame;
nghttp2_mem *mem;
mem = &session->mem;
if (type <= NGHTTP2_CONTINUATION) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
if (!session->callbacks.pack_extension_callback) {
return NGHTTP2_ERR_INVALID_STATE;
}
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
if (item == NULL) {
return NGHTTP2_ERR_NOMEM;
}
nghttp2_outbound_item_init(item);
frame = &item->frame;
nghttp2_frame_extension_init(&frame->ext, type, flags, stream_id, payload);
rv = nghttp2_session_add_item(session, item);
if (rv != 0) {
nghttp2_frame_extension_free(&frame->ext);
nghttp2_mem_free(mem, item);
return rv;
}
return 0;
}

View File

@@ -9,6 +9,8 @@ git checkout refs/tags/$TAG
git log --pretty=fuller --date=short refs/tags/$PREV_TAG..HEAD > ChangeLog
git submodule update --init
autoreconf -i
./configure --with-mruby && \
make dist-bzip2 && make dist-gzip && make dist-xz || echo "error"
make distclean

5
releasechk Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/sh -e
git submodule update --init
./configure --with-mruby --with-neverbleed --enable-asio-lib
make -j3 distcheck DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --enable-asio-lib --enable-werror"

View File

@@ -101,12 +101,26 @@ template <typename Array> void append_nv(Stream *stream, const Array &nva) {
} // namespace
Config::Config()
: mime_types_file("/etc/mime.types"), stream_read_timeout(1_min),
stream_write_timeout(1_min), data_ptr(nullptr), padding(0), num_worker(1),
max_concurrent_streams(100), header_table_size(-1), port(0),
verbose(false), daemon(false), verify_client(false), no_tls(false),
error_gzip(false), early_response(false), hexdump(false),
echo_upload(false), no_content_length(false) {}
: mime_types_file("/etc/mime.types"),
stream_read_timeout(1_min),
stream_write_timeout(1_min),
data_ptr(nullptr),
padding(0),
num_worker(1),
max_concurrent_streams(100),
header_table_size(-1),
window_bits(-1),
connection_window_bits(-1),
port(0),
verbose(false),
daemon(false),
verify_client(false),
no_tls(false),
error_gzip(false),
early_response(false),
hexdump(false),
echo_upload(false),
no_content_length(false) {}
Config::~Config() {}
@@ -225,8 +239,13 @@ class Sessions {
public:
Sessions(HttpServer *sv, struct ev_loop *loop, const Config *config,
SSL_CTX *ssl_ctx)
: sv_(sv), loop_(loop), config_(config), ssl_ctx_(ssl_ctx),
callbacks_(nullptr), next_session_id_(1), tstamp_cached_(ev_now(loop)),
: sv_(sv),
loop_(loop),
config_(config),
ssl_ctx_(ssl_ctx),
callbacks_(nullptr),
next_session_id_(1),
tstamp_cached_(ev_now(loop)),
cached_date_(util::http_date(tstamp_cached_)) {
nghttp2_session_callbacks_new(&callbacks_);
@@ -289,7 +308,6 @@ public:
}
auto handler =
make_unique<Http2Handler>(this, fd, ssl, get_next_session_id());
handler->setup_bev();
if (!ssl) {
if (handler->connection_made() != 0) {
return;
@@ -424,8 +442,13 @@ void release_fd_cb(struct ev_loop *loop, ev_timer *w, int revents) {
} // namespace
Stream::Stream(Http2Handler *handler, int32_t stream_id)
: handler(handler), file_ent(nullptr), body_length(0), body_offset(0),
stream_id(stream_id), echo_upload(false) {
: handler(handler),
file_ent(nullptr),
body_length(0),
body_offset(0),
header_buffer_size(0),
stream_id(stream_id),
echo_upload(false) {
auto config = handler->get_config();
ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
ev_timer_init(&wtimer, stream_timeout_cb, 0., config->stream_write_timeout);
@@ -496,8 +519,13 @@ void writecb(struct ev_loop *loop, ev_io *w, int revents) {
Http2Handler::Http2Handler(Sessions *sessions, int fd, SSL *ssl,
int64_t session_id)
: session_id_(session_id), session_(nullptr), sessions_(sessions),
ssl_(ssl), data_pending_(nullptr), data_pendinglen_(0), fd_(fd) {
: session_id_(session_id),
session_(nullptr),
sessions_(sessions),
ssl_(ssl),
data_pending_(nullptr),
data_pendinglen_(0),
fd_(fd) {
ev_timer_init(&settings_timerev_, settings_timeout_cb, 10., 0.);
ev_io_init(&wev_, writecb, fd, EV_WRITE);
ev_io_init(&rev_, readcb, fd, EV_READ);
@@ -546,7 +574,9 @@ struct ev_loop *Http2Handler::get_loop() const {
Http2Handler::WriteBuf *Http2Handler::get_wb() { return &wb_; }
int Http2Handler::setup_bev() { return 0; }
void Http2Handler::start_settings_timer() {
ev_timer_start(sessions_->get_loop(), &settings_timerev_);
}
int Http2Handler::fill_wb() {
if (data_pending_) {
@@ -819,12 +849,27 @@ int Http2Handler::connection_made() {
entry[niv].value = config->header_table_size;
++niv;
}
if (config->window_bits != -1) {
entry[niv].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
entry[niv].value = (1 << config->window_bits) - 1;
++niv;
}
r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(), niv);
if (r != 0) {
return r;
}
ev_timer_start(sessions_->get_loop(), &settings_timerev_);
if (config->connection_window_bits != -1) {
r = nghttp2_submit_window_update(
session_, NGHTTP2_FLAG_NONE, 0,
(1 << config->connection_window_bits) - 1 -
NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE);
if (r != 0) {
return r;
}
}
if (ssl_ && !nghttp2::ssl::check_http2_requirement(ssl_)) {
terminate_session(NGHTTP2_INADEQUATE_SECURITY);
@@ -864,6 +909,21 @@ int Http2Handler::verify_npn_result() {
return -1;
}
namespace {
std::string make_trailer_header_value(const Headers &trailer) {
if (trailer.empty()) {
return "";
}
auto trailer_names = trailer[0].name;
for (size_t i = 1; i < trailer.size(); ++i) {
trailer_names += ", ";
trailer_names += trailer[i].name;
}
return trailer_names;
}
} // namespace
int Http2Handler::submit_file_response(const std::string &status,
Stream *stream, time_t last_modified,
off_t file_length,
@@ -888,14 +948,8 @@ int Http2Handler::submit_file_response(const std::string &status,
if (content_type) {
nva[nvlen++] = http2::make_nv_ls("content-type", *content_type);
}
auto &trailer = get_config()->trailer;
std::string trailer_names;
if (!trailer.empty()) {
trailer_names = trailer[0].name;
for (size_t i = 1; i < trailer.size(); ++i) {
trailer_names += ", ";
trailer_names += trailer[i].name;
}
auto trailer_names = make_trailer_header_value(get_config()->trailer);
if (!trailer_names.empty()) {
nva[nvlen++] = http2::make_nv_ls("trailer", trailer_names);
}
return nghttp2_submit_response(session_, stream->stream_id, nva.data(), nvlen,
@@ -906,10 +960,19 @@ int Http2Handler::submit_response(const std::string &status, int32_t stream_id,
const Headers &headers,
nghttp2_data_provider *data_prd) {
auto nva = std::vector<nghttp2_nv>();
nva.reserve(3 + headers.size());
nva.reserve(4 + headers.size());
nva.push_back(http2::make_nv_ls(":status", status));
nva.push_back(http2::make_nv_ll("server", NGHTTPD_SERVER));
nva.push_back(http2::make_nv_ls("date", sessions_->get_cached_date()));
std::string trailer_names;
if (data_prd) {
trailer_names = make_trailer_header_value(get_config()->trailer);
if (!trailer_names.empty()) {
nva.push_back(http2::make_nv_ls("trailer", trailer_names));
}
}
for (auto &nv : headers) {
nva.push_back(http2::make_nv(nv.name, nv.value, nv.no_index));
}
@@ -920,11 +983,21 @@ int Http2Handler::submit_response(const std::string &status, int32_t stream_id,
int Http2Handler::submit_response(const std::string &status, int32_t stream_id,
nghttp2_data_provider *data_prd) {
auto nva =
make_array(http2::make_nv_ls(":status", status),
http2::make_nv_ll("server", NGHTTPD_SERVER),
http2::make_nv_ls("date", sessions_->get_cached_date()));
return nghttp2_submit_response(session_, stream_id, nva.data(), nva.size(),
auto nva = make_array(http2::make_nv_ls(":status", status),
http2::make_nv_ll("server", NGHTTPD_SERVER),
http2::make_nv_ls("date", sessions_->get_cached_date()),
http2::make_nv_ll("", ""));
size_t nvlen = 3;
std::string trailer_names;
if (data_prd) {
trailer_names = make_trailer_header_value(get_config()->trailer);
if (!trailer_names.empty()) {
nva[nvlen++] = http2::make_nv_ls("trailer", trailer_names);
}
}
return nghttp2_submit_response(session_, stream_id, nva.data(), nvlen,
data_prd);
}
@@ -1316,6 +1389,13 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
return 0;
}
if (stream->header_buffer_size + namelen + valuelen > 64_k) {
hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
return 0;
}
stream->header_buffer_size += namelen + valuelen;
auto token = http2::lookup_token(name, namelen);
http2::index_header(stream->hdidx, token, stream->headers.size());
@@ -1457,6 +1537,15 @@ int hd_on_frame_send_callback(nghttp2_session *session,
break;
}
case NGHTTP2_SETTINGS: {
if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
return 0;
}
hd->start_settings_timer();
break;
}
case NGHTTP2_PUSH_PROMISE: {
auto promised_stream_id = frame->push_promise.promised_stream_id;
auto promised_stream = hd->get_stream(promised_stream_id);

View File

@@ -67,6 +67,8 @@ struct Config {
size_t num_worker;
size_t max_concurrent_streams;
ssize_t header_table_size;
int window_bits;
int connection_window_bits;
uint16_t port;
bool verbose;
bool daemon;
@@ -87,9 +89,16 @@ struct FileEntry {
FileEntry(std::string path, int64_t length, int64_t mtime, int fd,
const std::string *content_type, ev_tstamp last_valid,
bool stale = false)
: path(std::move(path)), length(length), mtime(mtime),
last_valid(last_valid), content_type(content_type), dlnext(nullptr),
dlprev(nullptr), fd(fd), usecount(1), stale(stale) {}
: path(std::move(path)),
length(length),
mtime(mtime),
last_valid(last_valid),
content_type(content_type),
dlnext(nullptr),
dlprev(nullptr),
fd(fd),
usecount(1),
stale(stale) {}
std::string path;
std::multimap<std::string, std::unique_ptr<FileEntry>>::iterator it;
int64_t length;
@@ -110,6 +119,9 @@ struct Stream {
ev_timer wtimer;
int64_t body_length;
int64_t body_offset;
// Total amount of bytes (sum of name and value length) used in
// headers.
size_t header_buffer_size;
int32_t stream_id;
http2::HeaderIndex hdidx;
bool echo_upload;
@@ -125,7 +137,7 @@ public:
~Http2Handler();
void remove_self();
int setup_bev();
void start_settings_timer();
int on_read();
int on_write();
int connection_made();

View File

@@ -27,7 +27,7 @@ check_PROGRAMS =
TESTS =
AM_CFLAGS = $(WARNCFLAGS)
AM_CXXFLAGS = $(WARNCXXFLAGS)
AM_CXXFLAGS = $(WARNCXXFLAGS) $(CXX1XCXXFLAGS)
AM_CPPFLAGS = \
-DPKGDATADIR='"$(pkgdatadir)"' \
-I$(top_srcdir)/lib/includes \
@@ -62,7 +62,7 @@ HELPER_OBJECTS = util.cc \
http2.cc timegm.c app_helper.cc nghttp2_gzip.c
HELPER_HFILES = util.h \
http2.h timegm.h app_helper.h nghttp2_config.h \
nghttp2_gzip.h
nghttp2_gzip.h network.h
HTML_PARSER_OBJECTS =
HTML_PARSER_HFILES = HtmlParser.h
@@ -176,7 +176,8 @@ nghttpx_unittest_SOURCES = shrpx-unittest.cc \
nghttp2_gzip.c nghttp2_gzip.h \
buffer_test.cc buffer_test.h \
memchunk_test.cc memchunk_test.h \
template_test.cc template_test.h
template_test.cc template_test.h \
base64_test.cc base64_test.h
nghttpx_unittest_CPPFLAGS = ${AM_CPPFLAGS} \
-DNGHTTP2_TESTS_DIR=\"$(top_srcdir)/tests\"
nghttpx_unittest_LDADD = libnghttpx.a ${LDADD} @CUNIT_LIBS@ @TESTLDADD@

View File

@@ -121,7 +121,7 @@ const char *strsettingsid(int32_t id) {
} // namespace
namespace {
const char *strframetype(uint8_t type) {
std::string strframetype(uint8_t type) {
switch (type) {
case NGHTTP2_DATA:
return "DATA";
@@ -141,9 +141,13 @@ const char *strframetype(uint8_t type) {
return "GOAWAY";
case NGHTTP2_WINDOW_UPDATE:
return "WINDOW_UPDATE";
default:
return "UNKNOWN";
}
std::string s = "extension(0x";
s += util::format_hex(&type, 1);
s += ')';
return s;
};
} // namespace
@@ -280,7 +284,7 @@ const char *frame_name_ansi_esc(print_type ptype) {
namespace {
void print_frame(print_type ptype, const nghttp2_frame *frame) {
fprintf(outfile, "%s%s%s frame ", frame_name_ansi_esc(ptype),
strframetype(frame->hd.type), ansi_escend());
strframetype(frame->hd.type).c_str(), ansi_escend());
print_frame_hd(frame->hd);
if (frame->hd.flags) {
print_frame_attr_indent();

View File

@@ -32,7 +32,7 @@ namespace nghttp2 {
namespace asio_http2 {
namespace client {
request_impl::request_impl() : strm_(nullptr) {}
request_impl::request_impl() : strm_(nullptr), header_buffer_size_(0) {}
void request_impl::write_trailer(header_map h) {
auto sess = strm_->session();
@@ -105,6 +105,12 @@ void request_impl::method(std::string s) { method_ = std::move(s); }
const std::string &request_impl::method() const { return method_; }
size_t request_impl::header_buffer_size() const { return header_buffer_size_; }
void request_impl::update_header_buffer_size(size_t len) {
header_buffer_size_ += len;
}
} // namespace client
} // namespace asio_http2
} // namespace nghttp2

View File

@@ -75,6 +75,9 @@ public:
void method(std::string s);
const std::string &method() const;
size_t header_buffer_size() const;
void update_header_buffer_size(size_t len);
private:
header_map header_;
response_cb response_cb_;
@@ -84,6 +87,7 @@ private:
class stream *strm_;
uri_ref uri_;
std::string method_;
size_t header_buffer_size_;
};
} // namespace client

View File

@@ -30,7 +30,8 @@ namespace nghttp2 {
namespace asio_http2 {
namespace client {
response_impl::response_impl() : content_length_(-1), status_code_(0) {}
response_impl::response_impl()
: content_length_(-1), header_buffer_size_(0), status_code_(0) {}
void response_impl::on_data(data_cb cb) { data_cb_ = std::move(cb); }
@@ -52,6 +53,12 @@ header_map &response_impl::header() { return header_; }
const header_map &response_impl::header() const { return header_; }
size_t response_impl::header_buffer_size() const { return header_buffer_size_; }
void response_impl::update_header_buffer_size(size_t len) {
header_buffer_size_ += len;
}
} // namespace client
} // namespace asio_http2
} // namespace nghttp2

View File

@@ -53,12 +53,16 @@ public:
header_map &header();
const header_map &header() const;
size_t header_buffer_size() const;
void update_header_buffer_size(size_t len);
private:
data_cb data_cb_;
header_map header_;
int64_t content_length_;
size_t header_buffer_size_;
int status_code_;
};

View File

@@ -39,15 +39,33 @@ using boost::asio::ip::tcp;
session::session(boost::asio::io_service &io_service, const std::string &host,
const std::string &service)
: impl_(std::make_shared<session_tcp_impl>(io_service, host, service)) {
: impl_(std::make_shared<session_tcp_impl>(
io_service, host, service, boost::posix_time::seconds(60))) {
impl_->start_resolve(host, service);
}
session::session(boost::asio::io_service &io_service, 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, host, service,
connect_timeout)) {
impl_->start_resolve(host, service);
}
session::session(boost::asio::io_service &io_service,
boost::asio::ssl::context &tls_ctx, const std::string &host,
const std::string &service)
: impl_(std::make_shared<session_tls_impl>(
io_service, tls_ctx, host, service, boost::posix_time::seconds(60))) {
impl_->start_resolve(host, service);
}
session::session(boost::asio::io_service &io_service,
boost::asio::ssl::context &tls_ctx, const std::string &host,
const std::string &service,
const boost::posix_time::time_duration &connect_timeout)
: impl_(std::make_shared<session_tls_impl>(io_service, tls_ctx, host,
service)) {
service, connect_timeout)) {
impl_->start_resolve(host, service);
}
@@ -97,10 +115,6 @@ const request *session::submit(boost::system::error_code &ec,
return impl_->submit(ec, method, uri, std::move(cb), std::move(h));
}
void session::connect_timeout(const boost::posix_time::time_duration &t) {
impl_->connect_timeout(t);
}
void session::read_timeout(const boost::posix_time::time_duration &t) {
impl_->read_timeout(t);
}

View File

@@ -38,12 +38,21 @@ namespace nghttp2 {
namespace asio_http2 {
namespace client {
session_impl::session_impl(boost::asio::io_service &io_service)
: wblen_(0), io_service_(io_service), resolver_(io_service),
deadline_(io_service), connect_timeout_(boost::posix_time::seconds(60)),
read_timeout_(boost::posix_time::seconds(60)), session_(nullptr),
data_pending_(nullptr), data_pendinglen_(0), writing_(false),
inside_callback_(false), stopped_(false) {}
session_impl::session_impl(
boost::asio::io_service &io_service,
const boost::posix_time::time_duration &connect_timeout)
: wblen_(0),
io_service_(io_service),
resolver_(io_service),
deadline_(io_service),
connect_timeout_(connect_timeout),
read_timeout_(boost::posix_time::seconds(60)),
session_(nullptr),
data_pending_(nullptr),
data_pendinglen_(0),
writing_(false),
inside_callback_(false),
stopped_(false) {}
session_impl::~session_impl() {
// finish up all active stream
@@ -174,6 +183,12 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
if (token == http2::HD__STATUS) {
res.status_code(util::parse_uint(value, valuelen));
} else {
if (res.header_buffer_size() + namelen + valuelen > 64_k) {
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
frame->hd.stream_id, NGHTTP2_INTERNAL_ERROR);
break;
}
res.update_header_buffer_size(namelen + valuelen);
if (token == http2::HD_CONTENT_LENGTH) {
res.content_length(util::parse_uint(value, valuelen));
@@ -214,6 +229,13 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
}
// fall through
default:
if (req.header_buffer_size() + namelen + valuelen > 64_k) {
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
frame->hd.stream_id, NGHTTP2_INTERNAL_ERROR);
break;
}
req.update_header_buffer_size(namelen + valuelen);
req.header().emplace(
std::string(name, name + namelen),
header_value{std::string(value, value + valuelen),
@@ -698,9 +720,7 @@ void session_impl::stop() {
stopped_ = true;
}
void session_impl::connect_timeout(const boost::posix_time::time_duration &t) {
connect_timeout_ = t;
}
bool session_impl::stopped() const { return stopped_; }
void session_impl::read_timeout(const boost::posix_time::time_duration &t) {
read_timeout_ = t;

View File

@@ -43,7 +43,8 @@ using boost::asio::ip::tcp;
class session_impl : public std::enable_shared_from_this<session_impl> {
public:
session_impl(boost::asio::io_service &io_service);
session_impl(boost::asio::io_service &io_service,
const boost::posix_time::time_duration &connect_timeout);
virtual ~session_impl();
void start_resolve(const std::string &host, const std::string &service);
@@ -91,10 +92,10 @@ public:
void do_read();
void do_write();
void connect_timeout(const boost::posix_time::time_duration &t);
void read_timeout(const boost::posix_time::time_duration &t);
void stop();
bool stopped() const;
protected:
boost::array<uint8_t, 8_k> rb_;

View File

@@ -28,10 +28,11 @@ namespace nghttp2 {
namespace asio_http2 {
namespace client {
session_tcp_impl::session_tcp_impl(boost::asio::io_service &io_service,
const std::string &host,
const std::string &service)
: session_impl(io_service), socket_(io_service) {}
session_tcp_impl::session_tcp_impl(
boost::asio::io_service &io_service, 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) {}
session_tcp_impl::~session_tcp_impl() {}
@@ -39,6 +40,10 @@ void session_tcp_impl::start_connect(tcp::resolver::iterator endpoint_it) {
boost::asio::async_connect(socket_, endpoint_it,
[this](const boost::system::error_code &ec,
tcp::resolver::iterator endpoint_it) {
if (stopped()) {
return;
}
if (ec) {
not_connected(ec);
return;

View File

@@ -38,7 +38,8 @@ using boost::asio::ip::tcp;
class session_tcp_impl : public session_impl {
public:
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);
virtual ~session_tcp_impl();
virtual void start_connect(tcp::resolver::iterator endpoint_it);

View File

@@ -29,11 +29,11 @@ namespace nghttp2 {
namespace asio_http2 {
namespace client {
session_tls_impl::session_tls_impl(boost::asio::io_service &io_service,
boost::asio::ssl::context &tls_ctx,
const std::string &host,
const std::string &service)
: session_impl(io_service), socket_(io_service, tls_ctx) {
session_tls_impl::session_tls_impl(
boost::asio::io_service &io_service, boost::asio::ssl::context &tls_ctx,
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, tls_ctx) {
// this callback setting is no effect is
// ssl::context::set_verify_mode(boost::asio::ssl::verify_peer) is
// not used, which is what we want.
@@ -46,6 +46,10 @@ void session_tls_impl::start_connect(tcp::resolver::iterator endpoint_it) {
boost::asio::async_connect(
socket(), endpoint_it, [this](const boost::system::error_code &ec,
tcp::resolver::iterator endpoint_it) {
if (stopped()) {
return;
}
if (ec) {
not_connected(ec);
return;
@@ -54,6 +58,10 @@ void session_tls_impl::start_connect(tcp::resolver::iterator endpoint_it) {
socket_.async_handshake(
boost::asio::ssl::stream_base::client,
[this, endpoint_it](const boost::system::error_code &ec) {
if (stopped()) {
return;
}
if (ec) {
not_connected(ec);
return;

View File

@@ -41,7 +41,8 @@ class session_tls_impl : public session_impl {
public:
session_tls_impl(boost::asio::io_service &io_service,
boost::asio::ssl::context &tls_ctx, const std::string &host,
const std::string &service);
const std::string &service,
const boost::posix_time::time_duration &connect_timeout);
virtual ~session_tls_impl();
virtual void start_connect(tcp::resolver::iterator endpoint_it);

View File

@@ -69,10 +69,13 @@ public:
const boost::posix_time::time_duration &tls_handshake_timeout,
const boost::posix_time::time_duration &read_timeout,
SocketArgs &&... args)
: socket_(std::forward<SocketArgs>(args)...), mux_(mux),
: socket_(std::forward<SocketArgs>(args)...),
mux_(mux),
deadline_(socket_.get_io_service()),
tls_handshake_timeout_(tls_handshake_timeout),
read_timeout_(read_timeout), writing_(false), stopped_(false) {}
read_timeout_(read_timeout),
writing_(false),
stopped_(false) {}
/// Start the first asynchronous operation for the connection.
void start() {

View File

@@ -105,6 +105,13 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
}
// fall through
default:
if (req.header_buffer_size() + namelen + valuelen > 64_k) {
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
NGHTTP2_INTERNAL_ERROR);
break;
}
req.update_header_buffer_size(namelen + valuelen);
req.header().emplace(std::string(name, name + namelen),
header_value{std::string(value, value + valuelen),
(flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0});
@@ -230,8 +237,14 @@ int on_frame_not_send_callback(nghttp2_session *session,
http2_handler::http2_handler(boost::asio::io_service &io_service,
boost::asio::ip::tcp::endpoint ep,
connection_write writefun, serve_mux &mux)
: writefun_(writefun), mux_(mux), io_service_(io_service), remote_ep_(ep),
session_(nullptr), buf_(nullptr), buflen_(0), inside_callback_(false),
: writefun_(writefun),
mux_(mux),
io_service_(io_service),
remote_ep_(ep),
session_(nullptr),
buf_(nullptr),
buflen_(0),
inside_callback_(false),
tstamp_cached_(time(nullptr)),
formatted_date_(util::http_date(tstamp_cached_)) {}

View File

@@ -38,7 +38,8 @@ namespace asio_http2 {
namespace server {
http2_impl::http2_impl()
: num_threads_(1), backlog_(-1),
: num_threads_(1),
backlog_(-1),
tls_handshake_timeout_(boost::posix_time::seconds(60)),
read_timeout_(boost::posix_time::seconds(60)) {}

View File

@@ -28,7 +28,7 @@ namespace nghttp2 {
namespace asio_http2 {
namespace server {
request_impl::request_impl() : strm_(nullptr) {}
request_impl::request_impl() : strm_(nullptr), header_buffer_size_(0) {}
const header_map &request_impl::header() const { return header_; }
@@ -62,6 +62,12 @@ void request_impl::remote_endpoint(boost::asio::ip::tcp::endpoint ep) {
remote_ep_ = std::move(ep);
}
size_t request_impl::header_buffer_size() const { return header_buffer_size_; }
void request_impl::update_header_buffer_size(size_t len) {
header_buffer_size_ += len;
}
} // namespace server
} // namespace asio_http2
} // namespace nghttp2

View File

@@ -58,6 +58,9 @@ public:
const boost::asio::ip::tcp::endpoint &remote_endpoint() const;
void remote_endpoint(boost::asio::ip::tcp::endpoint ep);
size_t header_buffer_size() const;
void update_header_buffer_size(size_t len);
private:
class stream *strm_;
header_map header_;
@@ -65,6 +68,7 @@ private:
uri_ref uri_;
data_cb on_data_cb_;
boost::asio::ip::tcp::endpoint remote_ep_;
size_t header_buffer_size_;
};
} // namespace server

View File

@@ -36,8 +36,11 @@ namespace asio_http2 {
namespace server {
response_impl::response_impl()
: strm_(nullptr), generator_cb_(deferred_generator()), status_code_(200),
state_(response_state::INITIAL), pushed_(false),
: strm_(nullptr),
generator_cb_(deferred_generator()),
status_code_(200),
state_(response_state::INITIAL),
pushed_(false),
push_promise_sent_(false) {}
unsigned int response_impl::status_code() const { return status_code_; }

View File

@@ -33,9 +33,8 @@ namespace nghttp2 {
namespace base64 {
template <typename InputIterator>
std::string encode(InputIterator first, InputIterator last) {
static const char CHAR_TABLE[] = {
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',
@@ -48,39 +47,38 @@ std::string encode(InputIterator first, InputIterator last) {
return res;
}
size_t r = len % 3;
InputIterator j = last - r;
char temp[4];
res.resize((len + 2) / 3 * 4);
auto j = last - r;
auto p = std::begin(res);
while (first != j) {
int n = static_cast<unsigned char>(*first++) << 16;
n += static_cast<unsigned char>(*first++) << 8;
n += static_cast<unsigned char>(*first++);
temp[0] = CHAR_TABLE[n >> 18];
temp[1] = CHAR_TABLE[(n >> 12) & 0x3fu];
temp[2] = CHAR_TABLE[(n >> 6) & 0x3fu];
temp[3] = CHAR_TABLE[n & 0x3fu];
res.append(temp, sizeof(temp));
uint32_t n = static_cast<uint8_t>(*first++) << 16;
n += static_cast<uint8_t>(*first++) << 8;
n += static_cast<uint8_t>(*first++);
*p++ = CHAR_TABLE[n >> 18];
*p++ = CHAR_TABLE[(n >> 12) & 0x3fu];
*p++ = CHAR_TABLE[(n >> 6) & 0x3fu];
*p++ = CHAR_TABLE[n & 0x3fu];
}
if (r == 2) {
int n = static_cast<unsigned char>(*first++) << 16;
n += static_cast<unsigned char>(*first++) << 8;
temp[0] = CHAR_TABLE[n >> 18];
temp[1] = CHAR_TABLE[(n >> 12) & 0x3fu];
temp[2] = CHAR_TABLE[(n >> 6) & 0x3fu];
temp[3] = '=';
res.append(temp, sizeof(temp));
uint32_t n = static_cast<uint8_t>(*first++) << 16;
n += static_cast<uint8_t>(*first++) << 8;
*p++ = CHAR_TABLE[n >> 18];
*p++ = CHAR_TABLE[(n >> 12) & 0x3fu];
*p++ = CHAR_TABLE[(n >> 6) & 0x3fu];
*p++ = '=';
} else if (r == 1) {
int n = static_cast<unsigned char>(*first++) << 16;
temp[0] = CHAR_TABLE[n >> 18];
temp[1] = CHAR_TABLE[(n >> 12) & 0x3fu];
temp[2] = '=';
temp[3] = '=';
res.append(temp, sizeof(temp));
uint32_t n = static_cast<uint8_t>(*first++) << 16;
*p++ = CHAR_TABLE[n >> 18];
*p++ = CHAR_TABLE[(n >> 12) & 0x3fu];
*p++ = '=';
*p++ = '=';
}
return res;
}
template <typename InputIterator>
InputIterator getNext(InputIterator first, InputIterator last, const int *tbl) {
template <typename InputIt>
InputIt next_decode_input(InputIt first, InputIt last, const int *tbl) {
for (; first != last; ++first) {
if (tbl[static_cast<size_t>(*first)] != -1 || *first == '=') {
break;
@@ -89,9 +87,8 @@ InputIterator getNext(InputIterator first, InputIterator last, const int *tbl) {
return first;
}
template <typename InputIterator>
std::string decode(InputIterator first, InputIterator last) {
static const int INDEX_TABLE[] = {
template <typename InputIt> std::string decode(InputIt first, InputIt last) {
static constexpr int INDEX_TABLE[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57,
@@ -107,59 +104,47 @@ std::string decode(InputIterator first, InputIterator last) {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1};
std::string res;
InputIterator k[4];
int eq = 0;
for (; first != last;) {
for (int i = 1; i <= 4; ++i) {
k[i - 1] = getNext(first, last, INDEX_TABLE);
if (k[i - 1] == last) {
// If i == 1, input may look like this: "TWFu\n" (i.e.,
// garbage at the end)
if (i != 1) {
res.clear();
}
return res;
} else if (*k[i - 1] == '=' && eq == 0) {
eq = i;
}
first = k[i - 1] + 1;
}
if (eq) {
break;
}
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18) +
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12) +
(INDEX_TABLE[static_cast<unsigned char>(*k[2])] << 6) +
INDEX_TABLE[static_cast<unsigned char>(*k[3])];
res += n >> 16;
res += n >> 8 & 0xffu;
res += n & 0xffu;
auto len = last - first;
if (len % 4 != 0) {
return "";
}
if (eq) {
if (eq <= 2) {
res.clear();
return res;
} else {
for (int i = eq; i <= 4; ++i) {
if (*k[i - 1] != '=') {
res.clear();
std::string res;
res.resize(len / 4 * 3);
auto p = std::begin(res);
for (; first != last;) {
uint32_t n = 0;
for (int i = 1; i <= 4; ++i, ++first) {
auto idx = INDEX_TABLE[static_cast<size_t>(*first)];
if (idx == -1) {
if (i <= 2) {
return "";
}
if (i == 3) {
if (*first == '=' && *(first + 1) == '=' && first + 2 == last) {
*p++ = n >> 16;
res.resize(p - std::begin(res));
return res;
}
return "";
}
if (*first == '=' && first + 1 == last) {
*p++ = n >> 16;
*p++ = n >> 8 & 0xffu;
res.resize(p - std::begin(res));
return res;
}
return "";
}
if (eq == 3) {
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18) +
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12);
res += n >> 16;
} else if (eq == 4) {
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18) +
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12) +
(INDEX_TABLE[static_cast<unsigned char>(*k[2])] << 6);
res += n >> 16;
res += n >> 8 & 0xffu;
}
n += idx << (24 - i * 6);
}
*p++ = n >> 16;
*p++ = n >> 8 & 0xffu;
*p++ = n & 0xffu;
}
return res;
}

109
src/base64_test.cc Normal file
View File

@@ -0,0 +1,109 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2016 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "base64_test.h"
#include <cstring>
#include <iostream>
#include <CUnit/CUnit.h>
#include <nghttp2/nghttp2.h>
#include "base64.h"
namespace nghttp2 {
void test_base64_encode(void) {
{
std::string in = "\xff";
auto out = base64::encode(std::begin(in), std::end(in));
CU_ASSERT("/w==" == out);
}
{
std::string in = "\xff\xfe";
auto out = base64::encode(std::begin(in), std::end(in));
CU_ASSERT("//4=" == out);
}
{
std::string in = "\xff\xfe\xfd";
auto out = base64::encode(std::begin(in), std::end(in));
CU_ASSERT("//79" == out);
}
{
std::string in = "\xff\xfe\xfd\xfc";
auto out = base64::encode(std::begin(in), std::end(in));
CU_ASSERT("//79/A==" == out);
}
}
void test_base64_decode(void) {
{
std::string in = "/w==";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff" == out);
}
{
std::string in = "//4=";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe" == out);
}
{
std::string in = "//79";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe\xfd" == out);
}
{
std::string in = "//79/A==";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe\xfd\xfc" == out);
}
{
// we check the number of valid input must be multiples of 4
std::string in = "//79=";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out);
}
{
// ending invalid character at the boundary of multiples of 4 is
// bad
std::string in = "bmdodHRw\n";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out);
}
{
// after seeing '=', subsequent input must be also '='.
std::string in = "//79/A=A";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out);
}
{
// additional '=' at the end is bad
std::string in = "//79/A======";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out);
}
}
} // namespace nghttp2

39
src/base64_test.h Normal file
View File

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

View File

@@ -79,11 +79,26 @@ bool recorded(const std::chrono::steady_clock::time_point &t) {
} // namespace
Config::Config()
: data_length(-1), addrs(nullptr), nreqs(1), nclients(1), nthreads(1),
max_concurrent_streams(-1), window_bits(30), connection_window_bits(30),
rate(0), rate_period(1.0), conn_active_timeout(0.),
conn_inactivity_timeout(0.), no_tls_proto(PROTO_HTTP2), data_fd(-1),
port(0), default_port(0), verbose(false), timing_script(false) {}
: data_length(-1),
addrs(nullptr),
nreqs(1),
nclients(1),
nthreads(1),
max_concurrent_streams(-1),
window_bits(30),
connection_window_bits(30),
rate(0),
rate_period(1.0),
conn_active_timeout(0.),
conn_inactivity_timeout(0.),
no_tls_proto(PROTO_HTTP2),
data_fd(-1),
port(0),
default_port(0),
verbose(false),
timing_script(false),
base_uri_unix(false),
unix_addr{} {}
Config::~Config() {
if (base_uri_unix) {
@@ -106,9 +121,18 @@ constexpr size_t MAX_SAMPLES = 1000000;
} // namespace
Stats::Stats(size_t req_todo, size_t nclients)
: req_todo(req_todo), req_started(0), req_done(0), req_success(0),
req_status_success(0), req_failed(0), req_error(0), req_timedout(0),
bytes_total(0), bytes_head(0), bytes_head_decomp(0), bytes_body(0),
: req_todo(req_todo),
req_started(0),
req_done(0),
req_success(0),
req_status_success(0),
req_failed(0),
req_error(0),
req_timedout(0),
bytes_total(0),
bytes_head(0),
bytes_head_decomp(0),
bytes_body(0),
status() {}
Stream::Stream() : req_stat{}, status_success(-1) {}
@@ -290,9 +314,18 @@ void client_request_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
} // namespace
Client::Client(uint32_t id, Worker *worker, size_t req_todo)
: cstat{}, worker(worker), ssl(nullptr), next_addr(config.addrs),
current_addr(nullptr), reqidx(0), state(CLIENT_IDLE), req_todo(req_todo),
req_started(0), req_done(0), id(id), fd(-1),
: cstat{},
worker(worker),
ssl(nullptr),
next_addr(config.addrs),
current_addr(nullptr),
reqidx(0),
state(CLIENT_IDLE),
req_todo(req_todo),
req_started(0),
req_done(0),
id(id),
fd(-1),
new_connection_requested(false) {
ev_io_init(&wev, writecb, 0, EV_WRITE);
ev_io_init(&rev, readcb, 0, EV_READ);
@@ -1094,11 +1127,20 @@ void Client::try_new_connection() { new_connection_requested = true; }
Worker::Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t req_todo, size_t nclients,
size_t rate, size_t max_samples, Config *config)
: stats(req_todo, nclients), loop(ev_loop_new(0)), ssl_ctx(ssl_ctx),
config(config), id(id), tls_info_report_done(false),
app_info_report_done(false), nconns_made(0), nclients(nclients),
nreqs_per_client(req_todo / nclients), nreqs_rem(req_todo % nclients),
rate(rate), max_samples(max_samples), next_client_id(0) {
: stats(req_todo, nclients),
loop(ev_loop_new(0)),
ssl_ctx(ssl_ctx),
config(config),
id(id),
tls_info_report_done(false),
app_info_report_done(false),
nconns_made(0),
nclients(nclients),
nreqs_per_client(req_todo / nclients),
nreqs_rem(req_todo % nclients),
rate(rate),
max_samples(max_samples),
next_client_id(0) {
if (!config->is_rate_mode()) {
progress_interval = std::max(static_cast<size_t>(1), req_todo / 10);
} else {

View File

@@ -41,7 +41,10 @@ using namespace nghttp2;
namespace h2load {
Http1Session::Http1Session(Client *client)
: stream_req_counter_(1), stream_resp_counter_(1), client_(client), htp_(),
: stream_req_counter_(1),
stream_resp_counter_(1),
client_(client),
htp_(),
complete_(false) {
http_parser_init(&htp_, HTTP_RESPONSE);
htp_.data = this;

View File

@@ -271,7 +271,7 @@ void copy_url_component(std::string &dest, const http_parser_url *u, int field,
Headers::value_type to_header(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
bool no_index, int16_t token) {
bool no_index, int32_t token) {
return Header(std::string(reinterpret_cast<const char *>(name), namelen),
std::string(reinterpret_cast<const char *>(value), valuelen),
no_index, token);
@@ -279,7 +279,7 @@ Headers::value_type to_header(const uint8_t *name, size_t namelen,
void add_header(Headers &nva, const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen, bool no_index,
int16_t token) {
int32_t token) {
if (valuelen > 0) {
size_t i, j;
for (i = 0; i < valuelen && (value[i] == ' ' || value[i] == '\t'); ++i)
@@ -760,7 +760,7 @@ void init_hdidx(HeaderIndex &hdidx) {
std::fill(std::begin(hdidx), std::end(hdidx), -1);
}
void index_header(HeaderIndex &hdidx, int16_t token, size_t idx) {
void index_header(HeaderIndex &hdidx, int32_t token, size_t idx) {
if (token == -1) {
return;
}
@@ -768,52 +768,7 @@ void index_header(HeaderIndex &hdidx, int16_t token, size_t idx) {
hdidx[token] = idx;
}
bool check_http2_request_pseudo_header(const HeaderIndex &hdidx,
int16_t token) {
switch (token) {
case HD__AUTHORITY:
case HD__METHOD:
case HD__PATH:
case HD__SCHEME:
return hdidx[token] == -1;
default:
return false;
}
}
bool check_http2_response_pseudo_header(const HeaderIndex &hdidx,
int16_t token) {
switch (token) {
case HD__STATUS:
return hdidx[token] == -1;
default:
return false;
}
}
bool http2_header_allowed(int16_t token) {
switch (token) {
case HD_CONNECTION:
case HD_KEEP_ALIVE:
case HD_PROXY_CONNECTION:
case HD_TRANSFER_ENCODING:
case HD_UPGRADE:
return false;
default:
return true;
}
}
bool http2_mandatory_request_headers_presence(const HeaderIndex &hdidx) {
if (hdidx[HD__METHOD] == -1 || hdidx[HD__PATH] == -1 ||
hdidx[HD__SCHEME] == -1 ||
(hdidx[HD__AUTHORITY] == -1 && hdidx[HD_HOST] == -1)) {
return false;
}
return true;
}
const Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
const Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
const Headers &nva) {
auto i = hdidx[token];
if (i == -1) {
@@ -822,7 +777,7 @@ const Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
return &nva[i];
}
Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
Headers &nva) {
auto i = hdidx[token];
if (i == -1) {

View File

@@ -44,8 +44,10 @@ namespace nghttp2 {
struct Header {
Header(std::string name, std::string value, bool no_index = false,
int16_t token = -1)
: name(std::move(name)), value(std::move(value)), token(token),
int32_t token = -1)
: name(std::move(name)),
value(std::move(value)),
token(token),
no_index(no_index) {}
Header() : token(-1), no_index(false) {}
@@ -60,7 +62,7 @@ struct Header {
std::string name;
std::string value;
int16_t token;
int32_t token;
bool no_index;
};
@@ -87,14 +89,14 @@ void copy_url_component(std::string &dest, const http_parser_url *u, int field,
Headers::value_type to_header(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
bool no_index, int16_t token);
bool no_index, int32_t token);
// Add name/value pairs to |nva|. If |no_index| is true, this
// name/value pair won't be indexed when it is forwarded to the next
// hop. This function strips white spaces around |value|.
void add_header(Headers &nva, const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen, bool no_index,
int16_t token);
int32_t token);
// Returns pointer to the entry in |nva| which has name |name|. If
// more than one entries which have the name |name|, last occurrence
@@ -275,30 +277,13 @@ int lookup_token(const std::string &name);
// array containing at least HD_MAXIDX elements.
void init_hdidx(HeaderIndex &hdidx);
// Indexes header |token| using index |idx|.
void index_header(HeaderIndex &hdidx, int16_t token, size_t idx);
// Returns true if HTTP/2 request pseudo header |token| is not indexed
// yet and not -1.
bool check_http2_request_pseudo_header(const HeaderIndex &hdidx, int16_t token);
// Returns true if HTTP/2 response pseudo header |token| is not
// indexed yet and not -1.
bool check_http2_response_pseudo_header(const HeaderIndex &hdidx,
int16_t token);
// Returns true if header field denoted by |token| is allowed for
// HTTP/2.
bool http2_header_allowed(int16_t token);
// Returns true that |hdidx| contains mandatory HTTP/2 request
// headers.
bool http2_mandatory_request_headers_presence(const HeaderIndex &hdidx);
void index_header(HeaderIndex &hdidx, int32_t token, size_t idx);
// Returns header denoted by |token| using index |hdidx|.
const Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
const Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
const Headers &nva);
Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
Headers &nva);
struct LinkHeader {

View File

@@ -271,53 +271,6 @@ void test_http2_lookup_token(void) {
CU_ASSERT(http2::HD_EXPECT == http2::lookup_token("expect"));
}
void test_http2_check_http2_pseudo_header(void) {
http2::HeaderIndex hdidx;
http2::init_hdidx(hdidx);
CU_ASSERT(http2::check_http2_request_pseudo_header(hdidx, http2::HD__METHOD));
hdidx[http2::HD__PATH] = 0;
CU_ASSERT(http2::check_http2_request_pseudo_header(hdidx, http2::HD__METHOD));
hdidx[http2::HD__METHOD] = 1;
CU_ASSERT(
!http2::check_http2_request_pseudo_header(hdidx, http2::HD__METHOD));
CU_ASSERT(!http2::check_http2_request_pseudo_header(hdidx, http2::HD_VIA));
http2::init_hdidx(hdidx);
CU_ASSERT(
http2::check_http2_response_pseudo_header(hdidx, http2::HD__STATUS));
hdidx[http2::HD__STATUS] = 0;
CU_ASSERT(
!http2::check_http2_response_pseudo_header(hdidx, http2::HD__STATUS));
CU_ASSERT(!http2::check_http2_response_pseudo_header(hdidx, http2::HD_VIA));
}
void test_http2_http2_header_allowed(void) {
CU_ASSERT(http2::http2_header_allowed(http2::HD__PATH));
CU_ASSERT(http2::http2_header_allowed(http2::HD_CONTENT_LENGTH));
CU_ASSERT(!http2::http2_header_allowed(http2::HD_CONNECTION));
}
void test_http2_mandatory_request_headers_presence(void) {
http2::HeaderIndex hdidx;
http2::init_hdidx(hdidx);
CU_ASSERT(!http2::http2_mandatory_request_headers_presence(hdidx));
hdidx[http2::HD__AUTHORITY] = 0;
CU_ASSERT(!http2::http2_mandatory_request_headers_presence(hdidx));
hdidx[http2::HD__METHOD] = 1;
CU_ASSERT(!http2::http2_mandatory_request_headers_presence(hdidx));
hdidx[http2::HD__PATH] = 2;
CU_ASSERT(!http2::http2_mandatory_request_headers_presence(hdidx));
hdidx[http2::HD__SCHEME] = 3;
CU_ASSERT(http2::http2_mandatory_request_headers_presence(hdidx));
hdidx[http2::HD__AUTHORITY] = -1;
hdidx[http2::HD_HOST] = 0;
CU_ASSERT(http2::http2_mandatory_request_headers_presence(hdidx));
}
void test_http2_parse_link_header(void) {
{
// only URI appears; we don't extract URI unless it bears rel=preload

View File

@@ -40,9 +40,6 @@ void test_http2_rewrite_location_uri(void);
void test_http2_parse_http_status_code(void);
void test_http2_index_header(void);
void test_http2_lookup_token(void);
void test_http2_check_http2_pseudo_header(void);
void test_http2_http2_header_allowed(void);
void test_http2_mandatory_request_headers_presence(void);
void test_http2_parse_link_header(void);
void test_http2_path_join(void);
void test_http2_normalize_path(void);

View File

@@ -123,15 +123,33 @@ class session_impl;
class session {
public:
// Starts HTTP/2 session by connecting to |host| and |service|
// (e.g., "80") using clear text TCP connection.
// (e.g., "80") using clear text TCP connection with connect timeout
// 60 seconds.
session(boost::asio::io_service &io_service, const std::string &host,
const std::string &service);
// Starts HTTP/2 session by connecting to |host| and |service|
// (e.g., "443") using encrypted SSL/TLS connection.
// (e.g., "80") using clear text TCP connection with given connect
// timeout.
session(boost::asio::io_service &io_service, const std::string &host,
const std::string &service,
const boost::posix_time::time_duration &connect_timeout);
// Starts HTTP/2 session by connecting to |host| and |service|
// (e.g., "443") using encrypted SSL/TLS connection with connect
// timeout 60 seconds.
session(boost::asio::io_service &io_service,
boost::asio::ssl::context &tls_context, const std::string &host,
const std::string &service);
// Starts HTTP/2 session by connecting to |host| and |service|
// (e.g., "443") using encrypted SSL/TLS connection with given
// connect timeout.
session(boost::asio::io_service &io_service,
boost::asio::ssl::context &tls_context, const std::string &host,
const std::string &service,
const boost::posix_time::time_duration &connect_timeout);
~session();
session(session &&other) noexcept;
@@ -144,9 +162,6 @@ public:
// and session is terminated.
void on_error(error_cb cb) const;
// Sets connect timeout, which defaults to 60 seconds.
void connect_timeout(const boost::posix_time::time_duration &t);
// Sets read timeout, which defaults to 60 seconds.
void read_timeout(const boost::posix_time::time_duration &t);

View File

@@ -32,13 +32,23 @@ namespace nghttp2 {
namespace util {
EvbufferBuffer::EvbufferBuffer()
: evbuffer_(nullptr), bucket_(nullptr), buf_(nullptr), bufmax_(0),
buflen_(0), limit_(0), writelen_(0) {}
: evbuffer_(nullptr),
bucket_(nullptr),
buf_(nullptr),
bufmax_(0),
buflen_(0),
limit_(0),
writelen_(0) {}
EvbufferBuffer::EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
ssize_t limit)
: evbuffer_(evbuffer), bucket_(limit == -1 ? nullptr : evbuffer_new()),
buf_(buf), bufmax_(bufmax), buflen_(0), limit_(limit), writelen_(0) {}
: evbuffer_(evbuffer),
bucket_(limit == -1 ? nullptr : evbuffer_new()),
buf_(buf),
bufmax_(bufmax),
buflen_(0),
limit_(limit),
writelen_(0) {}
void EvbufferBuffer::reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
ssize_t limit) {

View File

@@ -41,9 +41,19 @@
namespace nghttp2 {
#define DEFAULT_WR_IOVCNT 16
#if defined(IOV_MAX) && IOV_MAX < DEFAULT_WR_IOVCNT
#define MAX_WR_IOVCNT IOV_MAX
#else // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
#define MAX_WR_IOVCNT DEFAULT_WR_IOVCNT
#endif // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
template <size_t N> struct Memchunk {
Memchunk(std::unique_ptr<Memchunk> next_chunk)
: pos(std::begin(buf)), last(pos), knext(std::move(next_chunk)),
: pos(std::begin(buf)),
last(pos),
knext(std::move(next_chunk)),
next(nullptr) {}
size_t len() const { return last - pos; }
size_t left() const { return std::end(buf) - last; }
@@ -199,6 +209,36 @@ template <typename Memchunk> struct Memchunks {
return first - static_cast<uint8_t *>(dest);
}
size_t remove(Memchunks &dest, size_t count) {
if (!tail || count == 0) {
return 0;
}
auto left = count;
auto m = head;
while (m) {
auto next = m->next;
auto n = std::min(left, m->len());
assert(m->len());
dest.append(m->pos, n);
m->pos += n;
len -= n;
left -= n;
if (m->len() > 0) {
break;
}
pool->recycle(m);
m = next;
}
head = m;
if (head == nullptr) {
tail = nullptr;
}
return count - left;
}
size_t drain(size_t count) {
auto ndata = count;
auto m = head;
@@ -252,8 +292,12 @@ template <typename Memchunk> struct Memchunks {
// Wrapper around Memchunks to offer "peeking" functionality.
template <typename Memchunk> struct PeekMemchunks {
PeekMemchunks(Pool<Memchunk> *pool)
: memchunks(pool), cur(nullptr), cur_pos(nullptr), cur_last(nullptr),
len(0), peeking(true) {}
: memchunks(pool),
cur(nullptr),
cur_pos(nullptr),
cur_last(nullptr),
len(0),
peeking(true) {}
PeekMemchunks(const PeekMemchunks &) = delete;
PeekMemchunks(PeekMemchunks &&other) noexcept
: memchunks(std::move(other.memchunks)),
@@ -374,14 +418,6 @@ using MemchunkPool = Pool<Memchunk16K>;
using DefaultMemchunks = Memchunks<Memchunk16K>;
using DefaultPeekMemchunks = PeekMemchunks<Memchunk16K>;
#define DEFAULT_WR_IOVCNT 16
#if defined(IOV_MAX) && IOV_MAX < DEFAULT_WR_IOVCNT
#define MAX_WR_IOVCNT IOV_MAX
#else // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
#define MAX_WR_IOVCNT DEFAULT_WR_IOVCNT
#endif // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
inline int limit_iovec(struct iovec *iov, int iovcnt, size_t max) {
if (max == 0) {
return 0;

61
src/network.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2016 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NETWORK_H
#define NETWORK_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H
#include <sys/un.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif // HAVE_NETINET_IN_H
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif // HAVE_ARPA_INET_H
namespace nghttp2 {
union sockaddr_union {
sockaddr_storage storage;
sockaddr sa;
sockaddr_in6 in6;
sockaddr_in in;
sockaddr_un un;
};
struct Address {
size_t len;
union sockaddr_union su;
};
} // namespace nghttp2
#endif // NETWORK_H

View File

@@ -94,13 +94,26 @@ constexpr auto anchors = std::array<Anchor, 5>{{
Config::Config()
: header_table_size(-1),
min_header_table_size(std::numeric_limits<uint32_t>::max()), padding(0),
max_concurrent_streams(100), peer_max_concurrent_streams(100),
weight(NGHTTP2_DEFAULT_WEIGHT), multiply(1), timeout(0.), window_bits(-1),
connection_window_bits(-1), verbose(0), null_out(false),
remote_name(false), get_assets(false), stat(false), upgrade(false),
continuation(false), no_content_length(false), no_dep(false),
hexdump(false), no_push(false) {
min_header_table_size(std::numeric_limits<uint32_t>::max()),
padding(0),
max_concurrent_streams(100),
peer_max_concurrent_streams(100),
weight(NGHTTP2_DEFAULT_WEIGHT),
multiply(1),
timeout(0.),
window_bits(-1),
connection_window_bits(-1),
verbose(0),
null_out(false),
remote_name(false),
get_assets(false),
stat(false),
upgrade(false),
continuation(false),
no_content_length(false),
no_dep(false),
hexdump(false),
no_push(false) {
nghttp2_option_new(&http2_option);
nghttp2_option_set_peer_max_concurrent_streams(http2_option,
peer_max_concurrent_streams);
@@ -133,9 +146,19 @@ std::string strip_fragment(const char *raw_uri) {
Request::Request(const std::string &uri, const http_parser_url &u,
const nghttp2_data_provider *data_prd, int64_t data_length,
const nghttp2_priority_spec &pri_spec, int level)
: uri(uri), u(u), pri_spec(pri_spec), data_length(data_length),
data_offset(0), response_len(0), inflater(nullptr), html_parser(nullptr),
data_prd(data_prd), stream_id(-1), status(0), level(level),
: uri(uri),
u(u),
pri_spec(pri_spec),
data_length(data_length),
data_offset(0),
response_len(0),
inflater(nullptr),
html_parser(nullptr),
data_prd(data_prd),
header_buffer_size(0),
stream_id(-1),
status(0),
level(level),
expect_final_response(false) {
http2::init_hdidx(res_hdidx);
http2::init_hdidx(req_hdidx);
@@ -250,34 +273,7 @@ bool Request::is_ipv6_literal_addr() const {
}
}
bool Request::response_pseudo_header_allowed(int16_t token) const {
if (!res_nva.empty() && res_nva.back().name.c_str()[0] != ':') {
return false;
}
switch (token) {
case http2::HD__STATUS:
return res_hdidx[token] == -1;
default:
return false;
}
}
bool Request::push_request_pseudo_header_allowed(int16_t token) const {
if (!req_nva.empty() && req_nva.back().name.c_str()[0] != ':') {
return false;
}
switch (token) {
case http2::HD__AUTHORITY:
case http2::HD__METHOD:
case http2::HD__PATH:
case http2::HD__SCHEME:
return req_hdidx[token] == -1;
default:
return false;
}
}
Headers::value_type *Request::get_res_header(int16_t token) {
Headers::value_type *Request::get_res_header(int32_t token) {
auto idx = res_hdidx[token];
if (idx == -1) {
return nullptr;
@@ -285,7 +281,7 @@ Headers::value_type *Request::get_res_header(int16_t token) {
return &res_nva[idx];
}
Headers::value_type *Request::get_req_header(int16_t token) {
Headers::value_type *Request::get_req_header(int32_t token) {
auto idx = req_hdidx[token];
if (idx == -1) {
return nullptr;
@@ -467,10 +463,20 @@ void settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
HttpClient::HttpClient(const nghttp2_session_callbacks *callbacks,
struct ev_loop *loop, SSL_CTX *ssl_ctx)
: session(nullptr), callbacks(callbacks), loop(loop), ssl_ctx(ssl_ctx),
ssl(nullptr), addrs(nullptr), next_addr(nullptr), cur_addr(nullptr),
complete(0), success(0), settings_payloadlen(0), state(ClientState::IDLE),
upgrade_response_status_code(0), fd(-1),
: session(nullptr),
callbacks(callbacks),
loop(loop),
ssl_ctx(ssl_ctx),
ssl(nullptr),
addrs(nullptr),
next_addr(nullptr),
cur_addr(nullptr),
complete(0),
success(0),
settings_payloadlen(0),
state(ClientState::IDLE),
upgrade_response_status_code(0),
fd(-1),
upgrade_response_complete(false) {
ev_io_init(&wev, writecb, 0, EV_WRITE);
ev_io_init(&rev, readcb, 0, EV_READ);
@@ -1704,6 +1710,14 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
break;
}
if (req->header_buffer_size + namelen + valuelen > 64_k) {
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
NGHTTP2_INTERNAL_ERROR);
return 0;
}
req->header_buffer_size += namelen + valuelen;
auto token = http2::lookup_token(name, namelen);
http2::index_header(req->res_hdidx, token, req->res_nva.size());
@@ -1719,6 +1733,15 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
break;
}
if (req->header_buffer_size + namelen + valuelen > 64_k) {
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
frame->push_promise.promised_stream_id,
NGHTTP2_INTERNAL_ERROR);
return 0;
}
req->header_buffer_size += namelen + valuelen;
auto token = http2::lookup_token(name, namelen);
http2::index_header(req->req_hdidx, token, req->req_nva.size());
@@ -1806,6 +1829,10 @@ int on_frame_recv_callback2(nghttp2_session *session,
if (!req) {
break;
}
// Reset for response header field reception
req->header_buffer_size = 0;
auto scheme = req->get_req_header(http2::HD__SCHEME);
auto authority = req->get_req_header(http2::HD__AUTHORITY);
auto path = req->get_req_header(http2::HD__PATH);

View File

@@ -125,11 +125,8 @@ struct Request {
bool is_ipv6_literal_addr() const;
bool response_pseudo_header_allowed(int16_t token) const;
bool push_request_pseudo_header_allowed(int16_t token) const;
Headers::value_type *get_res_header(int16_t token);
Headers::value_type *get_req_header(int16_t token);
Headers::value_type *get_res_header(int32_t token);
Headers::value_type *get_req_header(int32_t token);
void record_request_start_time();
void record_response_start_time();
@@ -150,6 +147,7 @@ struct Request {
nghttp2_gzip *inflater;
HtmlParser *html_parser;
const nghttp2_data_provider *data_prd;
size_t header_buffer_size;
int32_t stream_id;
int status;
// Recursion level: 0: first entity, 1: entity linked from first entity

View File

@@ -143,6 +143,11 @@ Options:
Default: 1
-e, --error-gzip
Make error response gzipped.
-w, --window-bits=<N>
Sets the stream level initial window size to 2**<N>-1.
-W, --connection-window-bits=<N>
Sets the connection level initial window size to
2**<N>-1.
--dh-param-file=<PATH>
Path to file that contains DH parameters in PEM format.
Without this option, DHE cipher suites are not
@@ -202,6 +207,8 @@ int main(int argc, char **argv) {
{"max-concurrent-streams", required_argument, nullptr, 'm'},
{"workers", required_argument, nullptr, 'n'},
{"error-gzip", no_argument, nullptr, 'e'},
{"window-bits", required_argument, nullptr, 'w'},
{"connection-window-bits", required_argument, nullptr, 'W'},
{"no-tls", no_argument, &flag, 1},
{"color", no_argument, &flag, 2},
{"version", no_argument, &flag, 3},
@@ -214,7 +221,7 @@ int main(int argc, char **argv) {
{"no-content-length", no_argument, &flag, 10},
{nullptr, 0, nullptr, 0}};
int option_index = 0;
int c = getopt_long(argc, argv, "DVb:c:d:ehm:n:p:va:", long_options,
int c = getopt_long(argc, argv, "DVb:c:d:ehm:n:p:va:w:W:", long_options,
&option_index);
char *end;
if (c == -1) {
@@ -281,6 +288,26 @@ int main(int argc, char **argv) {
std::cerr << "-p: Bad option value: " << optarg << std::endl;
}
break;
case 'w':
case 'W': {
char *endptr;
errno = 0;
auto n = strtoul(optarg, &endptr, 10);
if (errno != 0 || *endptr != '\0' || n >= 31) {
std::cerr << "-" << static_cast<char>(c)
<< ": specify the integer in the range [0, 30], inclusive"
<< std::endl;
exit(EXIT_FAILURE);
}
if (c == 'w') {
config.window_bits = n;
} else {
config.connection_window_bits = n;
}
break;
}
case '?':
util::show_candidates(argv[optind - 1], long_options);
exit(EXIT_FAILURE);

View File

@@ -40,6 +40,7 @@
#include "memchunk_test.h"
#include "template_test.h"
#include "shrpx_http_test.h"
#include "base64_test.h"
#include "shrpx_config.h"
#include "ssl.h"
@@ -88,12 +89,6 @@ int main(int argc, char *argv[]) {
shrpx::test_http2_index_header) ||
!CU_add_test(pSuite, "http2_lookup_token",
shrpx::test_http2_lookup_token) ||
!CU_add_test(pSuite, "http2_check_http2_pseudo_header",
shrpx::test_http2_check_http2_pseudo_header) ||
!CU_add_test(pSuite, "http2_http2_header_allowed",
shrpx::test_http2_http2_header_allowed) ||
!CU_add_test(pSuite, "http2_mandatory_request_headers_presence",
shrpx::test_http2_mandatory_request_headers_presence) ||
!CU_add_test(pSuite, "http2_parse_link_header",
shrpx::test_http2_parse_link_header) ||
!CU_add_test(pSuite, "http2_path_join", shrpx::test_http2_path_join) ||
@@ -105,8 +100,8 @@ int main(int argc, char *argv[]) {
shrpx::test_http2_get_pure_path_component) ||
!CU_add_test(pSuite, "http2_construct_push_component",
shrpx::test_http2_construct_push_component) ||
!CU_add_test(pSuite, "downstream_field_store_index_headers",
shrpx::test_downstream_field_store_index_headers) ||
!CU_add_test(pSuite, "downstream_field_store_add_header_lower",
shrpx::test_downstream_field_store_add_header_lower) ||
!CU_add_test(pSuite, "downstream_field_store_header",
shrpx::test_downstream_field_store_header) ||
!CU_add_test(pSuite, "downstream_crumble_request_cookie",
@@ -166,6 +161,10 @@ int main(int argc, char *argv[]) {
!CU_add_test(pSuite, "util_get_uint64", shrpx::test_util_get_uint64) ||
!CU_add_test(pSuite, "util_parse_config_str_list",
shrpx::test_util_parse_config_str_list) ||
!CU_add_test(pSuite, "util_make_http_hostport",
shrpx::test_util_make_http_hostport) ||
!CU_add_test(pSuite, "util_make_hostport",
shrpx::test_util_make_hostport) ||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
!CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
!CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||
@@ -186,7 +185,9 @@ int main(int argc, char *argv[]) {
!CU_add_test(pSuite, "template_immutable_string",
nghttp2::test_template_immutable_string) ||
!CU_add_test(pSuite, "template_string_ref",
nghttp2::test_template_string_ref)) {
nghttp2::test_template_string_ref) ||
!CU_add_test(pSuite, "base64_encode", nghttp2::test_base64_encode) ||
!CU_add_test(pSuite, "base64_decode", nghttp2::test_base64_decode)) {
CU_cleanup_registry();
return CU_get_error();
}

File diff suppressed because it is too large Load Diff

View File

@@ -45,16 +45,16 @@ void acceptcb(struct ev_loop *loop, ev_io *w, int revent) {
}
} // namespace
AcceptHandler::AcceptHandler(int fd, ConnectionHandler *h)
: conn_hnr_(h), fd_(fd) {
ev_io_init(&wev_, acceptcb, fd_, EV_READ);
AcceptHandler::AcceptHandler(const UpstreamAddr *faddr, ConnectionHandler *h)
: conn_hnr_(h), faddr_(faddr) {
ev_io_init(&wev_, acceptcb, faddr_->fd, EV_READ);
wev_.data = this;
ev_io_start(conn_hnr_->get_loop(), &wev_);
}
AcceptHandler::~AcceptHandler() {
ev_io_stop(conn_hnr_->get_loop(), &wev_);
close(fd_);
close(faddr_->fd);
}
void AcceptHandler::accept_connection() {
@@ -63,10 +63,10 @@ void AcceptHandler::accept_connection() {
socklen_t addrlen = sizeof(sockaddr);
#ifdef HAVE_ACCEPT4
auto cfd =
accept4(fd_, &sockaddr.sa, &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
#else // !HAVE_ACCEPT4
auto cfd = accept(fd_, &sockaddr.sa, &addrlen);
auto cfd = accept4(faddr_->fd, &sockaddr.sa, &addrlen,
SOCK_NONBLOCK | SOCK_CLOEXEC);
#else // !HAVE_ACCEPT4
auto cfd = accept(faddr_->fd, &sockaddr.sa, &addrlen);
#endif // !HAVE_ACCEPT4
if (cfd == -1) {
@@ -101,7 +101,7 @@ void AcceptHandler::accept_connection() {
util::make_socket_nodelay(cfd);
conn_hnr_->handle_connection(cfd, &sockaddr.sa, addrlen);
conn_hnr_->handle_connection(cfd, &sockaddr.sa, addrlen, faddr_);
}
}
@@ -109,6 +109,6 @@ void AcceptHandler::enable() { ev_io_start(conn_hnr_->get_loop(), &wev_); }
void AcceptHandler::disable() { ev_io_stop(conn_hnr_->get_loop(), &wev_); }
int AcceptHandler::get_fd() const { return fd_; }
int AcceptHandler::get_fd() const { return faddr_->fd; }
} // namespace shrpx

View File

@@ -32,10 +32,11 @@
namespace shrpx {
class ConnectionHandler;
struct UpstreamAddr;
class AcceptHandler {
public:
AcceptHandler(int fd, ConnectionHandler *h);
AcceptHandler(const UpstreamAddr *faddr, ConnectionHandler *h);
~AcceptHandler();
void accept_connection();
void enable();
@@ -45,7 +46,7 @@ public:
private:
ev_io wev_;
ConnectionHandler *conn_hnr_;
int fd_;
const UpstreamAddr *faddr_;
};
} // namespace shrpx

View File

@@ -127,6 +127,10 @@ int ClientHandler::read_clear() {
return 0;
}
if (!ev_is_active(&conn_.rev)) {
return 0;
}
auto nread = conn_.read_clear(rb_.last, rb_.wleft());
if (nread == 0) {
@@ -220,6 +224,10 @@ int ClientHandler::read_tls() {
return 0;
}
if (!ev_is_active(&conn_.rev)) {
return 0;
}
auto nread = conn_.read_tls(rb_.last, rb_.wleft());
if (nread == 0) {
@@ -369,7 +377,8 @@ int ClientHandler::upstream_http1_connhd_read() {
}
ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
const char *ipaddr, const char *port)
const char *ipaddr, const char *port, int family,
const UpstreamAddr *faddr)
: conn_(worker->get_loop(), fd, ssl, worker->get_mcpool(),
get_config()->conn.upstream.timeout.write,
get_config()->conn.upstream.timeout.read,
@@ -380,9 +389,12 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
pinned_http2sessions_(
get_config()->conn.downstream.proto == PROTO_HTTP2
? make_unique<std::vector<ssize_t>>(
get_config()->conn.downstream.addr_groups.size(), -1)
worker->get_downstream_addr_groups().size(), -1)
: nullptr),
ipaddr_(ipaddr), port_(port), worker_(worker),
ipaddr_(ipaddr),
port_(port),
faddr_(faddr),
worker_(worker),
left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN),
should_close_after_write_(false) {
@@ -406,11 +418,19 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
auto &fwdconf = get_config()->http.forwarded;
if ((fwdconf.params & FORWARDED_FOR) &&
fwdconf.for_node_type == FORWARDED_NODE_OBFUSCATED) {
forwarded_for_obfuscated_ = "_";
forwarded_for_obfuscated_ += util::random_alpha_digit(
worker_->get_randgen(), SHRPX_OBFUSCATED_NODE_LENGTH);
if (fwdconf.params & FORWARDED_FOR) {
if (fwdconf.for_node_type == FORWARDED_NODE_OBFUSCATED) {
forwarded_for_ = "_";
forwarded_for_ += util::random_alpha_digit(worker_->get_randgen(),
SHRPX_OBFUSCATED_NODE_LENGTH);
} else if (family == AF_INET6) {
forwarded_for_ = "[";
forwarded_for_ += ipaddr_;
forwarded_for_ += ']';
} else {
// family == AF_INET or family == AF_UNIX
forwarded_for_ = ipaddr_;
}
}
}
@@ -644,8 +664,8 @@ std::unique_ptr<DownstreamConnection>
ClientHandler::get_downstream_connection(Downstream *downstream) {
size_t group;
auto &downstreamconf = get_config()->conn.downstream;
auto &groups = downstreamconf.addr_groups;
auto catch_all = downstreamconf.addr_group_catch_all;
auto &groups = worker_->get_downstream_addr_groups();
const auto &req = downstream->request();
@@ -661,16 +681,19 @@ ClientHandler::get_downstream_connection(Downstream *downstream) {
} else {
auto &router = get_config()->router;
if (!req.authority.empty()) {
group = match_downstream_addr_group(router, req.authority, req.path,
groups, catch_all);
group =
match_downstream_addr_group(router, StringRef{req.authority},
StringRef{req.path}, groups, catch_all);
} else {
auto h = req.fs.header(http2::HD_HOST);
if (h) {
group = match_downstream_addr_group(router, h->value, req.path, groups,
catch_all);
group =
match_downstream_addr_group(router, StringRef{h->value},
StringRef{req.path}, groups, catch_all);
} else {
group = match_downstream_addr_group(router, "", req.path, groups,
catch_all);
group =
match_downstream_addr_group(router, StringRef::from_lit(""),
StringRef{req.path}, groups, catch_all);
}
}
}
@@ -702,8 +725,8 @@ ClientHandler::get_downstream_connection(Downstream *downstream) {
}
dconn = make_unique<Http2DownstreamConnection>(dconn_pool, http2session);
} else {
dconn =
make_unique<HttpDownstreamConnection>(dconn_pool, group, conn_.loop);
dconn = make_unique<HttpDownstreamConnection>(dconn_pool, group,
conn_.loop, worker_);
}
dconn->set_client_handler(this);
return dconn;
@@ -723,10 +746,6 @@ MemchunkPool *ClientHandler::get_mcpool() { return worker_->get_mcpool(); }
SSL *ClientHandler::get_ssl() const { return conn_.tls.ssl; }
ConnectBlocker *ClientHandler::get_connect_blocker() const {
return worker_->get_connect_blocker();
}
void ClientHandler::direct_http2_upgrade() {
upstream_ = make_unique<Http2Upstream>(this);
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
@@ -753,17 +772,6 @@ int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
"Upgrade: " NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "\r\n"
"\r\n";
auto required_size = str_size(res) + input->rleft();
if (output->wleft() < required_size) {
if (LOG_ENABLED(INFO)) {
CLOG(INFO, this)
<< "HTTP Upgrade failed because of insufficient buffer space: need "
<< required_size << ", available " << output->wleft();
}
return -1;
}
if (upstream->upgrade_upstream(http) != 0) {
return -1;
}
@@ -775,11 +783,8 @@ int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
on_read_ = &ClientHandler::upstream_http2_connhd_read;
write_ = &ClientHandler::write_clear;
auto nread =
downstream->get_response_buf()->remove(output->last, output->wleft());
output->write(nread);
output->write(res, str_size(res));
input->remove(*output, input->rleft());
output->append(res, str_size(res));
upstream_ = std::move(upstream);
signal_write();
@@ -855,8 +860,8 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
std::chrono::high_resolution_clock::now(), // request_end_time
req.http_major, req.http_minor, resp.http_status,
downstream->response_sent_body_length, StringRef(port_),
get_config()->conn.listener.port, get_config()->pid,
downstream->response_sent_body_length, StringRef(port_), faddr_->port,
get_config()->pid,
});
}
@@ -879,7 +884,7 @@ void ClientHandler::write_accesslog(int major, int minor, unsigned int status,
highres_now, // request_end_time
major, minor, // major, minor
status, body_bytes_sent, StringRef(port_),
get_config()->conn.listener.port, get_config()->pid,
faddr_->port, get_config()->pid,
});
}
@@ -969,7 +974,7 @@ int ClientHandler::proxy_protocol_read() {
--end;
constexpr const char HEADER[] = "PROXY ";
constexpr char HEADER[] = "PROXY ";
if (static_cast<size_t>(end - rb_.pos) < str_size(HEADER)) {
if (LOG_ENABLED(INFO)) {
@@ -1120,63 +1125,18 @@ int ClientHandler::proxy_protocol_read() {
return on_proxy_protocol_finish();
}
const std::string &ClientHandler::get_forwarded_by() {
StringRef ClientHandler::get_forwarded_by() {
auto &fwdconf = get_config()->http.forwarded;
if (fwdconf.by_node_type == FORWARDED_NODE_OBFUSCATED) {
return fwdconf.by_obfuscated;
}
if (!local_hostport_.empty()) {
return local_hostport_;
return StringRef(fwdconf.by_obfuscated);
}
auto &listenerconf = get_config()->conn.listener;
// For UNIX domain socket listener, just return empty string.
if (listenerconf.host_unix) {
return local_hostport_;
}
int rv;
sockaddr_union su;
socklen_t addrlen = sizeof(su);
rv = getsockname(conn_.fd, &su.sa, &addrlen);
if (rv != 0) {
return local_hostport_;
}
char host[NI_MAXHOST];
rv = getnameinfo(&su.sa, addrlen, host, sizeof(host), nullptr, 0,
NI_NUMERICHOST);
if (rv != 0) {
return local_hostport_;
}
if (su.storage.ss_family == AF_INET6) {
local_hostport_ = "[";
local_hostport_ += host;
local_hostport_ += "]:";
} else {
local_hostport_ = host;
local_hostport_ += ':';
}
local_hostport_ += util::utos(listenerconf.port);
return local_hostport_;
return StringRef(faddr_->hostport);
}
const std::string &ClientHandler::get_forwarded_for() const {
if (get_config()->http.forwarded.for_node_type == FORWARDED_NODE_OBFUSCATED) {
return forwarded_for_obfuscated_;
}
if (get_config()->conn.listener.host_unix) {
return EMPTY_STRING;
}
return ipaddr_;
return forwarded_for_;
}
} // namespace shrpx

View File

@@ -53,7 +53,7 @@ struct WorkerStat;
class ClientHandler {
public:
ClientHandler(Worker *worker, int fd, SSL *ssl, const char *ipaddr,
const char *port);
const char *port, int family, const UpstreamAddr *faddr);
~ClientHandler();
int noop();
@@ -99,7 +99,6 @@ public:
get_downstream_connection(Downstream *downstream);
MemchunkPool *get_mcpool();
SSL *get_ssl() const;
ConnectBlocker *get_connect_blocker() const;
// Call this function when HTTP/2 connection header is received at
// the start of the connection.
void direct_http2_upgrade();
@@ -136,7 +135,7 @@ public:
// Returns string suitable for use in "by" parameter of Forwarded
// header field.
const std::string &get_forwarded_by();
StringRef get_forwarded_by();
// Returns string suitable for use in "for" parameter of Forwarded
// header field.
const std::string &get_forwarded_for() const;
@@ -152,13 +151,13 @@ private:
std::string port_;
// The ALPN identifier negotiated for this connection.
std::string alpn_;
// Host and port of this socket (e.g., "[::1]:8443")
std::string local_hostport_;
// The obfuscated version of client address used in "for" parameter
// of Forwarded header field.
std::string forwarded_for_obfuscated_;
// The client address used in "for" parameter of Forwarded header
// field.
std::string forwarded_for_;
std::function<int(ClientHandler &)> read_, write_;
std::function<int(ClientHandler &)> on_read_, on_write_;
// Address of frontend listening socket
const UpstreamAddr *faddr_;
Worker *worker_;
// The number of bytes of HTTP/2 client connection header to read
size_t left_connhd_len_;

View File

@@ -54,9 +54,7 @@
#include "shrpx_log.h"
#include "shrpx_ssl.h"
#include "shrpx_http.h"
#include "http2.h"
#include "util.h"
#include "template.h"
#include "base64.h"
namespace shrpx {
@@ -80,39 +78,6 @@ TicketKeys::~TicketKeys() {
}
}
DownstreamAddr::DownstreamAddr(const DownstreamAddr &other)
: addr(other.addr), host(other.host), hostport(other.hostport),
port(other.port), host_unix(other.host_unix) {}
DownstreamAddr &DownstreamAddr::operator=(const DownstreamAddr &other) {
if (this == &other) {
return *this;
}
addr = other.addr;
host = other.host;
hostport = other.hostport;
port = other.port;
host_unix = other.host_unix;
return *this;
}
DownstreamAddrGroup::DownstreamAddrGroup(const DownstreamAddrGroup &other)
: pattern(strcopy(other.pattern)), addrs(other.addrs) {}
DownstreamAddrGroup &DownstreamAddrGroup::
operator=(const DownstreamAddrGroup &other) {
if (this == &other) {
return *this;
}
pattern = strcopy(other.pattern);
addrs = other.addrs;
return *this;
}
namespace {
int split_host_port(char *host, size_t hostlen, uint16_t *port_ptr,
const char *hostport, size_t hostportlen) {
@@ -276,7 +241,7 @@ std::string read_passwd_from_file(const char *filename) {
return line;
}
std::pair<std::string, std::string> parse_header(const char *optarg) {
Headers::value_type parse_header(const char *optarg) {
const auto *colon = strchr(optarg, ':');
if (colon == nullptr || colon == optarg) {
@@ -287,16 +252,15 @@ std::pair<std::string, std::string> parse_header(const char *optarg) {
for (; *value == '\t' || *value == ' '; ++value)
;
auto p = std::make_pair(std::string(optarg, colon),
std::string(value, strlen(value)));
util::inp_strlower(p.first);
auto p =
Header(std::string(optarg, colon), std::string(value, strlen(value)));
util::inp_strlower(p.name);
if (!nghttp2_check_header_name(
reinterpret_cast<const uint8_t *>(p.first.c_str()), p.first.size()) ||
reinterpret_cast<const uint8_t *>(p.name.c_str()), p.name.size()) ||
!nghttp2_check_header_value(
reinterpret_cast<const uint8_t *>(p.second.c_str()),
p.second.size())) {
return {"", ""};
reinterpret_cast<const uint8_t *>(p.value.c_str()), p.value.size())) {
return Header();
}
return p;
@@ -572,6 +536,26 @@ std::vector<LogFragment> parse_log_format(const char *optarg) {
return res;
}
namespace {
int parse_address_family(int *dest, const char *opt, const char *optarg) {
if (util::strieq("auto", optarg)) {
*dest = AF_UNSPEC;
return 0;
}
if (util::strieq("IPv4", optarg)) {
*dest = AF_INET;
return 0;
}
if (util::strieq("IPv6", optarg)) {
*dest = AF_INET6;
return 0;
}
LOG(ERROR) << opt << ": bad value: '" << optarg << "'";
return -1;
}
} // namespace
namespace {
int parse_duration(ev_tstamp *dest, const char *opt, const char *optarg) {
auto t = util::parse_duration_with_unit(optarg);
@@ -613,7 +597,7 @@ void parse_mapping(const DownstreamAddr &addr, const char *src) {
pattern += http2::normalize_path(slash, raw_pattern.second);
}
for (auto &g : addr_groups) {
if (g.pattern.get() == pattern) {
if (g.pattern == pattern) {
g.addrs.push_back(addr);
done = true;
break;
@@ -622,11 +606,10 @@ void parse_mapping(const DownstreamAddr &addr, const char *src) {
if (done) {
continue;
}
DownstreamAddrGroup g(pattern);
DownstreamAddrGroup g(StringRef{pattern});
g.addrs.push_back(addr);
mod_config()->router.add_route(g.pattern.get(), strlen(g.pattern.get()),
addr_groups.size());
mod_config()->router.add_route(StringRef{g.pattern}, addr_groups.size());
addr_groups.push_back(std::move(g));
}
@@ -670,9 +653,11 @@ enum {
SHRPX_OPTID_ADD_X_FORWARDED_FOR,
SHRPX_OPTID_ALTSVC,
SHRPX_OPTID_BACKEND,
SHRPX_OPTID_BACKEND_ADDRESS_FAMILY,
SHRPX_OPTID_BACKEND_HTTP_PROXY_URI,
SHRPX_OPTID_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND,
SHRPX_OPTID_BACKEND_HTTP1_CONNECTIONS_PER_HOST,
SHRPX_OPTID_BACKEND_HTTP1_TLS,
SHRPX_OPTID_BACKEND_HTTP2_CONNECTION_WINDOW_BITS,
SHRPX_OPTID_BACKEND_HTTP2_CONNECTIONS_PER_WORKER,
SHRPX_OPTID_BACKEND_HTTP2_WINDOW_BITS,
@@ -723,8 +708,11 @@ enum {
SHRPX_OPTID_LISTENER_DISABLE_TIMEOUT,
SHRPX_OPTID_LOG_LEVEL,
SHRPX_OPTID_MAX_HEADER_FIELDS,
SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS,
SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS,
SHRPX_OPTID_MRUBY_FILE,
SHRPX_OPTID_NO_HOST_REWRITE,
SHRPX_OPTID_NO_HTTP2_CIPHER_BLACK_LIST,
SHRPX_OPTID_NO_LOCATION_REWRITE,
SHRPX_OPTID_NO_OCSP,
SHRPX_OPTID_NO_SERVER_PUSH,
@@ -737,6 +725,8 @@ enum {
SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE,
SHRPX_OPTID_READ_BURST,
SHRPX_OPTID_READ_RATE,
SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER,
SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER,
SHRPX_OPTID_RLIMIT_NOFILE,
SHRPX_OPTID_STREAM_READ_TIMEOUT,
SHRPX_OPTID_STREAM_WRITE_TIMEOUT,
@@ -748,12 +738,20 @@ enum {
SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD,
SHRPX_OPTID_TLS_PROTO_LIST,
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED,
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY,
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE,
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE,
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS,
SHRPX_OPTID_TLS_TICKET_KEY_CIPHER,
SHRPX_OPTID_TLS_TICKET_KEY_FILE,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_INTERVAL,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_TLS,
SHRPX_OPTID_USER,
SHRPX_OPTID_VERIFY_CLIENT,
SHRPX_OPTID_VERIFY_CLIENT_CACERT,
@@ -1069,6 +1067,9 @@ int option_lookup_token(const char *name, size_t namelen) {
}
break;
case 's':
if (util::strieq_l("backend-http1-tl", name, 16)) {
return SHRPX_OPTID_BACKEND_HTTP1_TLS;
}
if (util::strieq_l("max-header-field", name, 16)) {
return SHRPX_OPTID_MAX_HEADER_FIELDS;
}
@@ -1191,6 +1192,11 @@ int option_lookup_token(const char *name, size_t namelen) {
return SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT;
}
break;
case 'y':
if (util::strieq_l("backend-address-famil", name, 21)) {
return SHRPX_OPTID_BACKEND_ADDRESS_FAMILY;
}
break;
}
break;
case 23:
@@ -1246,6 +1252,9 @@ int option_lookup_token(const char *name, size_t namelen) {
if (util::strieq_l("backend-http2-window-bit", name, 24)) {
return SHRPX_OPTID_BACKEND_HTTP2_WINDOW_BITS;
}
if (util::strieq_l("max-request-header-field", name, 24)) {
return SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS;
}
break;
}
break;
@@ -1255,11 +1264,17 @@ int option_lookup_token(const char *name, size_t namelen) {
if (util::strieq_l("frontend-http2-window-bit", name, 25)) {
return SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS;
}
if (util::strieq_l("max-response-header-field", name, 25)) {
return SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS;
}
break;
case 't':
if (util::strieq_l("backend-keep-alive-timeou", name, 25)) {
return SHRPX_OPTID_BACKEND_KEEP_ALIVE_TIMEOUT;
}
if (util::strieq_l("no-http2-cipher-black-lis", name, 25)) {
return SHRPX_OPTID_NO_HTTP2_CIPHER_BLACK_LIST;
}
break;
}
break;
@@ -1270,6 +1285,11 @@ int option_lookup_token(const char *name, size_t namelen) {
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED;
}
break;
case 'r':
if (util::strieq_l("request-header-field-buffe", name, 26)) {
return SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER;
}
break;
case 's':
if (util::strieq_l("worker-frontend-connection", name, 26)) {
return SHRPX_OPTID_WORKER_FRONTEND_CONNECTIONS;
@@ -1289,10 +1309,18 @@ int option_lookup_token(const char *name, size_t namelen) {
return SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD;
}
break;
case 'r':
if (util::strieq_l("response-header-field-buffe", name, 27)) {
return SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER;
}
break;
case 's':
if (util::strieq_l("http2-max-concurrent-stream", name, 27)) {
return SHRPX_OPTID_HTTP2_MAX_CONCURRENT_STREAMS;
}
if (util::strieq_l("tls-ticket-key-memcached-tl", name, 27)) {
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_TLS;
}
break;
}
break;
@@ -1305,6 +1333,15 @@ int option_lookup_token(const char *name, size_t namelen) {
break;
}
break;
case 31:
switch (name[30]) {
case 's':
if (util::strieq_l("tls-session-cache-memcached-tl", name, 30)) {
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS;
}
break;
}
break;
case 33:
switch (name[32]) {
case 'l':
@@ -1319,6 +1356,11 @@ int option_lookup_token(const char *name, size_t namelen) {
break;
case 34:
switch (name[33]) {
case 'e':
if (util::strieq_l("tls-ticket-key-memcached-cert-fil", name, 33)) {
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE;
}
break;
case 'r':
if (util::strieq_l("frontend-http2-dump-request-heade", name, 33)) {
return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER;
@@ -1361,6 +1403,11 @@ int option_lookup_token(const char *name, size_t namelen) {
break;
case 37:
switch (name[36]) {
case 'e':
if (util::strieq_l("tls-session-cache-memcached-cert-fil", name, 36)) {
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE;
}
break;
case 's':
if (util::strieq_l("frontend-http2-connection-window-bit", name, 36)) {
return SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS;
@@ -1377,6 +1424,45 @@ int option_lookup_token(const char *name, size_t namelen) {
break;
}
break;
case 39:
switch (name[38]) {
case 'y':
if (util::strieq_l("tls-ticket-key-memcached-address-famil", name, 38)) {
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY;
}
break;
}
break;
case 41:
switch (name[40]) {
case 'e':
if (util::strieq_l("tls-ticket-key-memcached-private-key-fil", name,
40)) {
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE;
}
break;
}
break;
case 42:
switch (name[41]) {
case 'y':
if (util::strieq_l("tls-session-cache-memcached-address-famil", name,
41)) {
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY;
}
break;
}
break;
case 44:
switch (name[43]) {
case 'e':
if (util::strieq_l("tls-session-cache-memcached-private-key-fil", name,
43)) {
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE;
}
break;
}
break;
}
return -1;
}
@@ -1396,7 +1482,7 @@ int parse_config(const char *opt, const char *optarg,
if (!pat_delim) {
pat_delim = optarg + optarglen;
}
DownstreamAddr addr;
DownstreamAddr addr{};
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
auto path = optarg + str_size(SHRPX_UNIX_PATH_PREFIX);
addr.host = ImmutableString(path, pat_delim);
@@ -1425,11 +1511,15 @@ int parse_config(const char *opt, const char *optarg,
case SHRPX_OPTID_FRONTEND: {
auto &listenerconf = mod_config()->conn.listener;
UpstreamAddr addr{};
addr.fd = -1;
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
auto path = optarg + str_size(SHRPX_UNIX_PATH_PREFIX);
listenerconf.host = strcopy(path);
listenerconf.port = 0;
listenerconf.host_unix = true;
addr.host = ImmutableString(path);
addr.host_unix = true;
listenerconf.addrs.push_back(std::move(addr));
return 0;
}
@@ -1439,9 +1529,26 @@ int parse_config(const char *opt, const char *optarg,
return -1;
}
listenerconf.host = strcopy(host);
listenerconf.port = port;
listenerconf.host_unix = false;
addr.host = ImmutableString(host);
addr.port = port;
if (util::numeric_host(host, AF_INET)) {
addr.family = AF_INET;
listenerconf.addrs.push_back(std::move(addr));
return 0;
}
if (util::numeric_host(host, AF_INET6)) {
addr.family = AF_INET6;
listenerconf.addrs.push_back(std::move(addr));
return 0;
}
addr.family = AF_INET;
listenerconf.addrs.push_back(addr);
addr.family = AF_INET6;
listenerconf.addrs.push_back(std::move(addr));
return 0;
}
@@ -1511,7 +1618,7 @@ int parse_config(const char *opt, const char *optarg,
return parse_duration(&mod_config()->http2.timeout.stream_write, opt,
optarg);
case SHRPX_OPTID_ACCESSLOG_FILE:
mod_config()->logging.access.file = strcopy(optarg);
mod_config()->logging.access.file = optarg;
return 0;
case SHRPX_OPTID_ACCESSLOG_SYSLOG:
@@ -1523,7 +1630,7 @@ int parse_config(const char *opt, const char *optarg,
return 0;
case SHRPX_OPTID_ERRORLOG_FILE:
mod_config()->logging.error.file = strcopy(optarg);
mod_config()->logging.error.file = optarg;
return 0;
case SHRPX_OPTID_ERRORLOG_SYSLOG:
@@ -1617,7 +1724,7 @@ int parse_config(const char *opt, const char *optarg,
return 0;
case SHRPX_OPTID_PID_FILE:
mod_config()->pid_file = strcopy(optarg);
mod_config()->pid_file = optarg;
return 0;
case SHRPX_OPTID_USER: {
@@ -1627,14 +1734,14 @@ int parse_config(const char *opt, const char *optarg,
<< strerror(errno);
return -1;
}
mod_config()->user = strcopy(pwd->pw_name);
mod_config()->user = pwd->pw_name;
mod_config()->uid = pwd->pw_uid;
mod_config()->gid = pwd->pw_gid;
return 0;
}
case SHRPX_OPTID_PRIVATE_KEY_FILE:
mod_config()->tls.private_key_file = strcopy(optarg);
mod_config()->tls.private_key_file = optarg;
return 0;
case SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE: {
@@ -1643,16 +1750,16 @@ int parse_config(const char *opt, const char *optarg,
LOG(ERROR) << opt << ": Couldn't read key file's passwd from " << optarg;
return -1;
}
mod_config()->tls.private_key_passwd = strcopy(passwd);
mod_config()->tls.private_key_passwd = passwd;
return 0;
}
case SHRPX_OPTID_CERTIFICATE_FILE:
mod_config()->tls.cert_file = strcopy(optarg);
mod_config()->tls.cert_file = optarg;
return 0;
case SHRPX_OPTID_DH_PARAM_FILE:
mod_config()->tls.dh_param_file = strcopy(optarg);
mod_config()->tls.dh_param_file = optarg;
return 0;
case SHRPX_OPTID_SUBCERT: {
@@ -1693,7 +1800,7 @@ int parse_config(const char *opt, const char *optarg,
return 0;
}
case SHRPX_OPTID_CIPHERS:
mod_config()->tls.ciphers = strcopy(optarg);
mod_config()->tls.ciphers = optarg;
return 0;
case SHRPX_OPTID_CLIENT:
@@ -1705,15 +1812,21 @@ int parse_config(const char *opt, const char *optarg,
return 0;
case SHRPX_OPTID_CACERT:
mod_config()->tls.cacert = strcopy(optarg);
mod_config()->tls.cacert = optarg;
return 0;
case SHRPX_OPTID_BACKEND_IPV4:
mod_config()->conn.downstream.ipv4 = util::strieq(optarg, "yes");
LOG(WARN) << opt
<< ": deprecated. Use backend-address-family=IPv4 instead.";
mod_config()->conn.downstream.family = AF_INET;
return 0;
case SHRPX_OPTID_BACKEND_IPV6:
mod_config()->conn.downstream.ipv6 = util::strieq(optarg, "yes");
LOG(WARN) << opt
<< ": deprecated. Use backend-address-family=IPv6 instead.";
mod_config()->conn.downstream.family = AF_INET6;
return 0;
case SHRPX_OPTID_BACKEND_HTTP_PROXY_URI: {
@@ -1790,25 +1903,23 @@ int parse_config(const char *opt, const char *optarg,
return 0;
case SHRPX_OPTID_VERIFY_CLIENT_CACERT:
mod_config()->tls.client_verify.cacert = strcopy(optarg);
mod_config()->tls.client_verify.cacert = optarg;
return 0;
case SHRPX_OPTID_CLIENT_PRIVATE_KEY_FILE:
mod_config()->tls.client.private_key_file = strcopy(optarg);
mod_config()->tls.client.private_key_file = optarg;
return 0;
case SHRPX_OPTID_CLIENT_CERT_FILE:
mod_config()->tls.client.cert_file = strcopy(optarg);
mod_config()->tls.client.cert_file = optarg;
return 0;
case SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER:
mod_config()->http2.upstream.debug.dump.request_header_file =
strcopy(optarg);
mod_config()->http2.upstream.debug.dump.request_header_file = optarg;
return 0;
case SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER:
mod_config()->http2.upstream.debug.dump.response_header_file =
strcopy(optarg);
mod_config()->http2.upstream.debug.dump.response_header_file = optarg;
return 0;
case SHRPX_OPTID_HTTP2_NO_COOKIE_CRUMBLING:
@@ -1871,7 +1982,7 @@ int parse_config(const char *opt, const char *optarg,
case SHRPX_OPTID_ADD_REQUEST_HEADER:
case SHRPX_OPTID_ADD_RESPONSE_HEADER: {
auto p = parse_header(optarg);
if (p.first.empty()) {
if (p.name.empty()) {
LOG(ERROR) << opt << ": invalid header field: " << optarg;
return -1;
}
@@ -1969,7 +2080,7 @@ int parse_config(const char *opt, const char *optarg,
return parse_uint(&mod_config()->http2.downstream.connections_per_worker,
opt, optarg);
case SHRPX_OPTID_FETCH_OCSP_RESPONSE_FILE:
mod_config()->tls.ocsp.fetch_ocsp_response_file = strcopy(optarg);
mod_config()->tls.ocsp.fetch_ocsp_response_file = optarg;
return 0;
case SHRPX_OPTID_OCSP_UPDATE_INTERVAL:
@@ -1979,10 +2090,24 @@ int parse_config(const char *opt, const char *optarg,
return 0;
case SHRPX_OPTID_HEADER_FIELD_BUFFER:
return parse_uint_with_unit(&mod_config()->http.header_field_buffer, opt,
optarg);
LOG(WARN) << opt
<< ": deprecated. Use request-header-field-buffer instead.";
// fall through
case SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER:
return parse_uint_with_unit(&mod_config()->http.request_header_field_buffer,
opt, optarg);
case SHRPX_OPTID_MAX_HEADER_FIELDS:
return parse_uint(&mod_config()->http.max_header_fields, opt, optarg);
LOG(WARN) << opt << ": deprecated. Use max-request-header-fields instead.";
// fall through
case SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS:
return parse_uint(&mod_config()->http.max_request_header_fields, opt,
optarg);
case SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER:
return parse_uint_with_unit(
&mod_config()->http.response_header_field_buffer, opt, optarg);
case SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS:
return parse_uint(&mod_config()->http.max_response_header_fields, opt,
optarg);
case SHRPX_OPTID_INCLUDE: {
if (included_set.count(optarg)) {
LOG(ERROR) << opt << ": " << optarg << " has already been included";
@@ -2023,7 +2148,7 @@ int parse_config(const char *opt, const char *optarg,
}
auto &memcachedconf = mod_config()->tls.session_cache.memcached;
memcachedconf.host = strcopy(host);
memcachedconf.host = host;
memcachedconf.port = port;
return 0;
@@ -2035,7 +2160,7 @@ int parse_config(const char *opt, const char *optarg,
}
auto &memcachedconf = mod_config()->tls.ticket.memcached;
memcachedconf.host = strcopy(host);
memcachedconf.host = host;
memcachedconf.port = port;
return 0;
@@ -2076,7 +2201,7 @@ int parse_config(const char *opt, const char *optarg,
case SHRPX_OPTID_MRUBY_FILE:
#ifdef HAVE_MRUBY
mod_config()->mruby_file = strcopy(optarg);
mod_config()->mruby_file = optarg;
#else // !HAVE_MRUBY
LOG(WARN) << opt
<< ": ignored because mruby support is disabled at build time.";
@@ -2148,6 +2273,47 @@ int parse_config(const char *opt, const char *optarg,
return 0;
}
case SHRPX_OPTID_NO_HTTP2_CIPHER_BLACK_LIST:
mod_config()->tls.no_http2_cipher_black_list = util::strieq(optarg, "yes");
return 0;
case SHRPX_OPTID_BACKEND_HTTP1_TLS:
mod_config()->conn.downstream.http1_tls = util::strieq(optarg, "yes");
return 0;
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS:
mod_config()->tls.session_cache.memcached.tls = util::strieq(optarg, "yes");
return 0;
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE:
mod_config()->tls.session_cache.memcached.cert_file = optarg;
return 0;
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE:
mod_config()->tls.session_cache.memcached.private_key_file = optarg;
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_TLS:
mod_config()->tls.ticket.memcached.tls = util::strieq(optarg, "yes");
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE:
mod_config()->tls.ticket.memcached.cert_file = optarg;
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE:
mod_config()->tls.ticket.memcached.private_key_file = optarg;
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY:
return parse_address_family(&mod_config()->tls.ticket.memcached.family, opt,
optarg);
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY:
return parse_address_family(
&mod_config()->tls.session_cache.memcached.family, opt, optarg);
case SHRPX_OPTID_BACKEND_ADDRESS_FAMILY:
return parse_address_family(&mod_config()->conn.downstream.family, opt,
optarg);
case SHRPX_OPTID_CONF:
LOG(WARN) << "conf: ignored";
@@ -2328,17 +2494,15 @@ int int_syslog_facility(const char *strfacility) {
}
namespace {
size_t
match_downstream_addr_group_host(const Router &router, const std::string &host,
const char *path, size_t pathlen,
const std::vector<DownstreamAddrGroup> &groups,
size_t catch_all) {
if (pathlen == 0 || *path != '/') {
auto group = router.match(host, "/", 1);
size_t match_downstream_addr_group_host(
const Router &router, const StringRef &host, const StringRef &path,
const std::vector<DownstreamAddrGroup> &groups, size_t catch_all) {
if (path.empty() || path[0] != '/') {
auto group = router.match(host, StringRef::from_lit("/"));
if (group != -1) {
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Found pattern with query " << host
<< ", matched pattern=" << groups[group].pattern.get();
<< ", matched pattern=" << groups[group].pattern;
}
return group;
}
@@ -2347,24 +2511,23 @@ match_downstream_addr_group_host(const Router &router, const std::string &host,
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Perform mapping selection, using host=" << host
<< ", path=" << std::string(path, pathlen);
<< ", path=" << path;
}
auto group = router.match(host, path, pathlen);
auto group = router.match(host, path);
if (group != -1) {
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Found pattern with query " << host
<< std::string(path, pathlen)
<< ", matched pattern=" << groups[group].pattern.get();
LOG(INFO) << "Found pattern with query " << host << path
<< ", matched pattern=" << groups[group].pattern;
}
return group;
}
group = router.match("", path, pathlen);
group = router.match("", path);
if (group != -1) {
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Found pattern with query " << std::string(path, pathlen)
<< ", matched pattern=" << groups[group].pattern.get();
LOG(INFO) << "Found pattern with query " << path
<< ", matched pattern=" << groups[group].pattern;
}
return group;
}
@@ -2376,11 +2539,9 @@ match_downstream_addr_group_host(const Router &router, const std::string &host,
}
} // namespace
size_t
match_downstream_addr_group(const Router &router, const std::string &hostport,
const std::string &raw_path,
const std::vector<DownstreamAddrGroup> &groups,
size_t catch_all) {
size_t match_downstream_addr_group(
const Router &router, const StringRef &hostport, const StringRef &raw_path,
const std::vector<DownstreamAddrGroup> &groups, size_t catch_all) {
if (std::find(std::begin(hostport), std::end(hostport), '/') !=
std::end(hostport)) {
// We use '/' specially, and if '/' is included in host, it breaks
@@ -2390,12 +2551,11 @@ match_downstream_addr_group(const Router &router, const std::string &hostport,
auto fragment = std::find(std::begin(raw_path), std::end(raw_path), '#');
auto query = std::find(std::begin(raw_path), fragment, '?');
auto path = raw_path.c_str();
auto pathlen = query - std::begin(raw_path);
auto path = StringRef{std::begin(raw_path), query};
if (hostport.empty()) {
return match_downstream_addr_group_host(router, hostport, path, pathlen,
groups, catch_all);
return match_downstream_addr_group_host(router, hostport, path, groups,
catch_all);
}
std::string host;
@@ -2418,7 +2578,7 @@ match_downstream_addr_group(const Router &router, const std::string &hostport,
}
util::inp_strlower(host);
return match_downstream_addr_group_host(router, host, path, pathlen, groups,
return match_downstream_addr_group_host(router, StringRef{host}, path, groups,
catch_all);
}

View File

@@ -52,12 +52,15 @@
#include "shrpx_router.h"
#include "template.h"
#include "http2.h"
#include "network.h"
using namespace nghttp2;
namespace shrpx {
struct LogFragment;
class ConnectBlocker;
namespace ssl {
@@ -196,22 +199,37 @@ constexpr char SHRPX_OPT_STRIP_INCOMING_FORWARDED[] =
"strip-incoming-forwarded";
constexpr static char SHRPX_OPT_FORWARDED_BY[] = "forwarded-by";
constexpr char SHRPX_OPT_FORWARDED_FOR[] = "forwarded-for";
constexpr char SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER[] =
"request-header-field-buffer";
constexpr char SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS[] =
"max-request-header-fields";
constexpr char SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER[] =
"response-header-field-buffer";
constexpr char SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS[] =
"max-response-header-fields";
constexpr char SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST[] =
"no-http2-cipher-black-list";
constexpr char SHRPX_OPT_BACKEND_HTTP1_TLS[] = "backend-http1-tls";
constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS[] =
"tls-session-cache-memcached-tls";
constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE[] =
"tls-session-cache-memcached-cert-file";
constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE[] =
"tls-session-cache-memcached-private-key-file";
constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY[] =
"tls-session-cache-memcached-address-family";
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS[] =
"tls-ticket-key-memcached-tls";
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE[] =
"tls-ticket-key-memcached-cert-file";
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE[] =
"tls-ticket-key-memcached-private-key-file";
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY[] =
"tls-ticket-key-memcached-address-family";
constexpr char SHRPX_OPT_BACKEND_ADDRESS_FAMILY[] = "backend-address-family";
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
union sockaddr_union {
sockaddr_storage storage;
sockaddr sa;
sockaddr_in6 in6;
sockaddr_in in;
sockaddr_un un;
};
struct Address {
size_t len;
union sockaddr_union su;
};
enum shrpx_proto { PROTO_HTTP2, PROTO_HTTP };
enum shrpx_forwarded_param {
@@ -239,18 +257,41 @@ struct AltSvc {
uint16_t port;
};
struct DownstreamAddr {
DownstreamAddr() : addr{}, port(0), host_unix(false) {}
DownstreamAddr(const DownstreamAddr &other);
DownstreamAddr(DownstreamAddr &&) = default;
DownstreamAddr &operator=(const DownstreamAddr &other);
DownstreamAddr &operator=(DownstreamAddr &&other) = default;
struct UpstreamAddr {
// The frontend address (e.g., FQDN, hostname, IP address). If
// |host_unix| is true, this is UNIX domain socket path.
ImmutableString host;
// For TCP socket, this is <IP address>:<PORT>. For IPv6 address,
// address is surrounded by square brackets. If socket is UNIX
// domain socket, this is "localhost".
ImmutableString hostport;
// frontend port. 0 if |host_unix| is true.
uint16_t port;
// For TCP socket, this is either AF_INET or AF_INET6. For UNIX
// domain socket, this is 0.
int family;
// true if |host| contains UNIX domain socket path.
bool host_unix;
int fd;
};
struct TLSSessionCache {
// ASN1 representation of SSL_SESSION object. See
// i2d_SSL_SESSION(3SSL).
std::vector<uint8_t> session_data;
// The last time stamp when this cache entry is created or updated.
ev_tstamp last_updated;
};
struct DownstreamAddr {
Address addr;
// backend address. If |host_unix| is true, this is UNIX domain
// socket path.
ImmutableString host;
ImmutableString hostport;
ConnectBlocker *connect_blocker;
// Client side TLS session cache
TLSSessionCache tls_session_cache;
// backend port. 0 if |host_unix| is true.
uint16_t port;
// true if |host| contains UNIX domain socket path.
@@ -258,13 +299,10 @@ struct DownstreamAddr {
};
struct DownstreamAddrGroup {
DownstreamAddrGroup(const std::string &pattern) : pattern(strcopy(pattern)) {}
DownstreamAddrGroup(const DownstreamAddrGroup &other);
DownstreamAddrGroup(DownstreamAddrGroup &&) = default;
DownstreamAddrGroup &operator=(const DownstreamAddrGroup &other);
DownstreamAddrGroup &operator=(DownstreamAddrGroup &&) = default;
DownstreamAddrGroup(const StringRef &pattern)
: pattern(pattern.c_str(), pattern.size()) {}
std::unique_ptr<char[]> pattern;
ImmutableString pattern;
std::vector<DownstreamAddr> addrs;
};
@@ -303,7 +341,12 @@ struct TLSConfig {
struct {
Address addr;
uint16_t port;
std::unique_ptr<char[]> host;
// Hostname of memcached server. This is also used as SNI field
// if TLS is enabled.
ImmutableString host;
// Client private key and certificate for authentication
ImmutableString private_key_file;
ImmutableString cert_file;
ev_tstamp interval;
// Maximum number of retries when getting TLS ticket key from
// mamcached, due to network error.
@@ -311,6 +354,10 @@ struct TLSConfig {
// Maximum number of consecutive error from memcached, when this
// limit reached, TLS ticket is disabled.
size_t max_fail;
// Address family of memcached connection. One of either
// AF_INET, AF_INET6 or AF_UNSPEC.
int family;
bool tls;
} memcached;
std::vector<std::string> files;
const EVP_CIPHER *cipher;
@@ -323,7 +370,16 @@ struct TLSConfig {
struct {
Address addr;
uint16_t port;
std::unique_ptr<char[]> host;
// Hostname of memcached server. This is also used as SNI field
// if TLS is enabled.
ImmutableString host;
// Client private key and certificate for authentication
ImmutableString private_key_file;
ImmutableString cert_file;
// Address family of memcached connection. One of either
// AF_INET, AF_INET6 or AF_UNSPEC.
int family;
bool tls;
} memcached;
} session_cache;
@@ -336,7 +392,7 @@ struct TLSConfig {
// OCSP realted configurations
struct {
ev_tstamp update_interval;
std::unique_ptr<char[]> fetch_ocsp_response_file;
ImmutableString fetch_ocsp_response_file;
bool disabled;
} ocsp;
@@ -344,14 +400,14 @@ struct TLSConfig {
struct {
// Path to file containing CA certificate solely used for client
// certificate validation
std::unique_ptr<char[]> cacert;
ImmutableString cacert;
bool enabled;
} client_verify;
// Client private key and certificate used in backend connections.
struct {
std::unique_ptr<char[]> private_key_file;
std::unique_ptr<char[]> cert_file;
ImmutableString private_key_file;
ImmutableString cert_file;
} client;
// The list of (private key file, certificate file) pair
@@ -367,13 +423,14 @@ struct TLSConfig {
long int tls_proto_mask;
std::string backend_sni_name;
std::chrono::seconds session_timeout;
std::unique_ptr<char[]> private_key_file;
std::unique_ptr<char[]> private_key_passwd;
std::unique_ptr<char[]> cert_file;
std::unique_ptr<char[]> dh_param_file;
std::unique_ptr<char[]> ciphers;
std::unique_ptr<char[]> cacert;
ImmutableString private_key_file;
ImmutableString private_key_passwd;
ImmutableString cert_file;
ImmutableString dh_param_file;
ImmutableString ciphers;
ImmutableString cacert;
bool insecure;
bool no_http2_cipher_black_list;
};
struct HttpConfig {
@@ -397,11 +454,13 @@ struct HttpConfig {
bool strip_incoming;
} xff;
std::vector<AltSvc> altsvcs;
std::vector<std::pair<std::string, std::string>> add_request_headers;
std::vector<std::pair<std::string, std::string>> add_response_headers;
Headers add_request_headers;
Headers add_response_headers;
StringRef server_name;
size_t header_field_buffer;
size_t max_header_fields;
size_t request_header_field_buffer;
size_t max_request_header_fields;
size_t response_header_field_buffer;
size_t max_response_header_fields;
bool no_via;
bool no_location_rewrite;
bool no_host_rewrite;
@@ -411,8 +470,8 @@ struct Http2Config {
struct {
struct {
struct {
std::unique_ptr<char[]> request_header_file;
std::unique_ptr<char[]> response_header_file;
ImmutableString request_header_file;
ImmutableString response_header_file;
FILE *request_header;
FILE *response_header;
} dump;
@@ -442,12 +501,12 @@ struct Http2Config {
struct LoggingConfig {
struct {
std::vector<LogFragment> format;
std::unique_ptr<char[]> file;
ImmutableString file;
// Send accesslog to syslog, ignoring accesslog_file.
bool syslog;
} access;
struct {
std::unique_ptr<char[]> file;
ImmutableString file;
// Send errorlog to syslog, ignoring errorlog_file.
bool syslog;
} error;
@@ -464,14 +523,8 @@ struct ConnectionConfig {
struct {
ev_tstamp sleep;
} timeout;
// address of frontend connection. This could be a path to UNIX
// domain socket. In this case, |host_unix| must be true.
std::unique_ptr<char[]> host;
// frontend listening port. 0 if frontend listens on UNIX domain
// socket, in this case |host_unix| must be true.
uint16_t port;
// true if host contains UNIX domain socket path
bool host_unix;
// address of frontend acceptors
std::vector<UpstreamAddr> addrs;
int backlog;
// TCP fastopen. If this is positive, it is passed to
// setsockopt() along with TCP_FASTOPEN.
@@ -508,12 +561,12 @@ struct ConnectionConfig {
size_t response_buffer_size;
// downstream protocol; this will be determined by given options.
shrpx_proto proto;
// Address family of backend connection. One of either AF_INET,
// AF_INET6 or AF_UNSPEC. This is ignored if backend connection
// is made via Unix domain socket.
int family;
bool no_tls;
// true if IPv4 only; ipv4 and ipv6 are mutually exclusive; and
// (ipv4 && ipv6) must be false.
bool ipv4;
// true if IPv6 only
bool ipv6;
bool http1_tls;
} downstream;
};
@@ -525,10 +578,10 @@ struct Config {
TLSConfig tls;
LoggingConfig logging;
ConnectionConfig conn;
std::unique_ptr<char[]> pid_file;
std::unique_ptr<char[]> conf_path;
std::unique_ptr<char[]> user;
std::unique_ptr<char[]> mruby_file;
ImmutableString pid_file;
ImmutableString conf_path;
ImmutableString user;
ImmutableString mruby_file;
char **original_argv;
char **argv;
char *cwd;
@@ -573,7 +626,7 @@ std::string read_passwd_from_file(const char *filename);
// like "NAME: VALUE". We require that NAME is non empty string. ":"
// is allowed at the start of the NAME, but NAME == ":" is not
// allowed. This function returns pair of NAME and VALUE.
std::pair<std::string, std::string> parse_header(const char *optarg);
Headers::value_type parse_header(const char *optarg);
std::vector<LogFragment> parse_log_format(const char *optarg);
@@ -600,7 +653,7 @@ read_tls_ticket_key_file(const std::vector<std::string> &files,
// group. The catch-all group index is given in |catch_all|. All
// patterns are given in |groups|.
size_t match_downstream_addr_group(
const Router &router, const std::string &hostport, const std::string &path,
const Router &router, const StringRef &hostport, const StringRef &path,
const std::vector<DownstreamAddrGroup> &groups, size_t catch_all);
} // namespace shrpx

View File

@@ -38,32 +38,32 @@ namespace shrpx {
void test_shrpx_config_parse_header(void) {
auto p = parse_header("a: b");
CU_ASSERT("a" == p.first);
CU_ASSERT("b" == p.second);
CU_ASSERT("a" == p.name);
CU_ASSERT("b" == p.value);
p = parse_header("a: b");
CU_ASSERT("a" == p.first);
CU_ASSERT("b" == p.second);
CU_ASSERT("a" == p.name);
CU_ASSERT("b" == p.value);
p = parse_header(":a: b");
CU_ASSERT(p.first.empty());
CU_ASSERT(p.name.empty());
p = parse_header("a: :b");
CU_ASSERT("a" == p.first);
CU_ASSERT(":b" == p.second);
CU_ASSERT("a" == p.name);
CU_ASSERT(":b" == p.value);
p = parse_header(": b");
CU_ASSERT(p.first.empty());
CU_ASSERT(p.name.empty());
p = parse_header("alpha: bravo charlie");
CU_ASSERT("alpha" == p.first);
CU_ASSERT("bravo charlie" == p.second);
CU_ASSERT("alpha" == p.name);
CU_ASSERT("bravo charlie" == p.value);
p = parse_header("a,: b");
CU_ASSERT(p.first.empty());
CU_ASSERT(p.name.empty());
p = parse_header("a: b\x0a");
CU_ASSERT(p.first.empty());
CU_ASSERT(p.name.empty());
}
void test_shrpx_config_parse_log_format(void) {
@@ -256,7 +256,7 @@ void test_shrpx_config_match_downstream_addr_group(void) {
for (size_t i = 0; i < groups.size(); ++i) {
auto &g = groups[i];
router.add_route(g.pattern.get(), strlen(g.pattern.get()), i);
router.add_route(StringRef{g.pattern}, i);
}
CU_ASSERT(0 == match_downstream_addr_group(router, "nghttp2.org", "/", groups,

View File

@@ -26,20 +26,16 @@
namespace shrpx {
namespace {
const ev_tstamp INITIAL_SLEEP = 2.;
} // namespace
namespace {
void connect_blocker_cb(struct ev_loop *loop, ev_timer *w, int revents) {
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "unblock downstream connection";
LOG(INFO) << "Unblock";
}
}
} // namespace
ConnectBlocker::ConnectBlocker(struct ev_loop *loop)
: loop_(loop), sleep_(INITIAL_SLEEP) {
ConnectBlocker::ConnectBlocker(std::mt19937 &gen, struct ev_loop *loop)
: gen_(gen), loop_(loop), fail_count_(0) {
ev_timer_init(&timer_, connect_blocker_cb, 0., 0.);
}
@@ -47,18 +43,27 @@ ConnectBlocker::~ConnectBlocker() { ev_timer_stop(loop_, &timer_); }
bool ConnectBlocker::blocked() const { return ev_is_active(&timer_); }
void ConnectBlocker::on_success() { sleep_ = INITIAL_SLEEP; }
void ConnectBlocker::on_success() { fail_count_ = 0; }
namespace {
constexpr size_t MAX_BACKOFF_EXP = 10;
} // namespace
void ConnectBlocker::on_failure() {
if (ev_is_active(&timer_)) {
return;
}
sleep_ = std::min(128., sleep_ * 2);
++fail_count_;
LOG(WARN) << "connect failure, start sleeping " << sleep_;
auto max_backoff = (1 << std::min(MAX_BACKOFF_EXP, fail_count_)) - 1;
auto dist = std::uniform_int_distribution<>(0, max_backoff);
auto backoff = dist(gen_);
ev_timer_set(&timer_, sleep_, 0.);
LOG(WARN) << "Could not connect " << fail_count_
<< " times in a row; sleep for " << backoff << " seconds";
ev_timer_set(&timer_, backoff, 0.);
ev_timer_start(loop_, &timer_);
}

View File

@@ -27,13 +27,15 @@
#include "shrpx.h"
#include <random>
#include <ev.h>
namespace shrpx {
class ConnectBlocker {
public:
ConnectBlocker(struct ev_loop *loop);
ConnectBlocker(std::mt19937 &gen, struct ev_loop *loop);
~ConnectBlocker();
// Returns true if making connection is not allowed.
@@ -41,14 +43,18 @@ public:
// Call this function if connect operation succeeded. This will
// reset sleep_ to minimum value.
void on_success();
// Call this function if connect operation failed. This will start
// timer and blocks connection establishment for sleep_ seconds.
// Call this function if connect operations failed. This will start
// timer and blocks connection establishment with exponential
// backoff.
void on_failure();
private:
std::mt19937 gen_;
ev_timer timer_;
struct ev_loop *loop_;
ev_tstamp sleep_;
// The number of consecutive connection failure. Reset to 0 on
// success.
size_t fail_count_;
};
} // namespace

View File

@@ -51,8 +51,12 @@ Connection::Connection(struct ev_loop *loop, int fd, SSL *ssl,
: tls{DefaultMemchunks(mcpool), DefaultPeekMemchunks(mcpool)},
wlimit(loop, &wev, write_limit.rate, write_limit.burst),
rlimit(loop, &rev, read_limit.rate, read_limit.burst, this),
writecb(writecb), readcb(readcb), timeoutcb(timeoutcb), loop(loop),
data(data), fd(fd),
writecb(writecb),
readcb(readcb),
timeoutcb(timeoutcb),
loop(loop),
data(data),
fd(fd),
tls_dyn_rec_warmup_threshold(tls_dyn_rec_warmup_threshold),
tls_dyn_rec_idle_timeout(tls_dyn_rec_idle_timeout) {
@@ -484,10 +488,17 @@ int Connection::check_http2_requirement() {
!util::check_h2_is_selected(next_proto, next_proto_len)) {
return 0;
}
if (!nghttp2::ssl::check_http2_requirement(tls.ssl)) {
if (!nghttp2::ssl::check_http2_tls_version(tls.ssl)) {
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "TLSv1.2 and/or black listed cipher suite was negotiated. "
"HTTP/2 must not be used.";
LOG(INFO) << "TLSv1.2 was not negotiated. HTTP/2 must not be used.";
}
return -1;
}
if (!get_config()->tls.no_http2_cipher_black_list &&
nghttp2::ssl::check_http2_cipher_black_list(tls.ssl)) {
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "The negotiated cipher suite is in HTTP/2 cipher suite "
"black list. HTTP/2 must not be used.";
}
return -1;
}

View File

@@ -107,9 +107,12 @@ std::random_device rd;
} // namespace
ConnectionHandler::ConnectionHandler(struct ev_loop *loop)
: gen_(rd()), single_worker_(nullptr), loop_(loop),
: gen_(rd()),
single_worker_(nullptr),
loop_(loop),
tls_ticket_key_memcached_get_retry_count_(0),
tls_ticket_key_memcached_fail_count_(0), worker_round_robin_cnt_(0),
tls_ticket_key_memcached_fail_count_(0),
worker_round_robin_cnt_(0),
graceful_shutdown_(false) {
ev_timer_init(&disable_acceptor_timer_, acceptor_disable_cb, 0., 0.);
disable_acceptor_timer_.data = this;
@@ -180,7 +183,7 @@ int ConnectionHandler::create_single_worker() {
nb_.get()
#endif // HAVE_NEVERBLEED
);
auto cl_ssl_ctx = ssl::setup_client_ssl_context(
auto cl_ssl_ctx = ssl::setup_downstream_client_ssl_context(
#ifdef HAVE_NEVERBLEED
nb_.get()
#endif // HAVE_NEVERBLEED
@@ -190,8 +193,23 @@ int ConnectionHandler::create_single_worker() {
all_ssl_ctx_.push_back(cl_ssl_ctx);
}
single_worker_ = make_unique<Worker>(loop_, sv_ssl_ctx, cl_ssl_ctx, cert_tree,
ticket_keys_);
auto &tlsconf = get_config()->tls;
auto &memcachedconf = get_config()->tls.session_cache.memcached;
SSL_CTX *session_cache_ssl_ctx = nullptr;
if (memcachedconf.tls) {
session_cache_ssl_ctx = ssl::create_ssl_client_context(
#ifdef HAVE_NEVERBLEED
nb_.get(),
#endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
StringRef{memcachedconf.private_key_file}, StringRef(), nullptr);
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
}
single_worker_ =
make_unique<Worker>(loop_, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx,
cert_tree, ticket_keys_);
#ifdef HAVE_MRUBY
if (single_worker_->create_mruby_context() != 0) {
return -1;
@@ -212,7 +230,7 @@ int ConnectionHandler::create_worker_thread(size_t num) {
nb_.get()
#endif // HAVE_NEVERBLEED
);
auto cl_ssl_ctx = ssl::setup_client_ssl_context(
auto cl_ssl_ctx = ssl::setup_downstream_client_ssl_context(
#ifdef HAVE_NEVERBLEED
nb_.get()
#endif // HAVE_NEVERBLEED
@@ -222,11 +240,25 @@ int ConnectionHandler::create_worker_thread(size_t num) {
all_ssl_ctx_.push_back(cl_ssl_ctx);
}
auto &tlsconf = get_config()->tls;
auto &memcachedconf = get_config()->tls.session_cache.memcached;
for (size_t i = 0; i < num; ++i) {
auto loop = ev_loop_new(0);
auto worker = make_unique<Worker>(loop, sv_ssl_ctx, cl_ssl_ctx, cert_tree,
ticket_keys_);
SSL_CTX *session_cache_ssl_ctx = nullptr;
if (memcachedconf.tls) {
session_cache_ssl_ctx = ssl::create_ssl_client_context(
#ifdef HAVE_NEVERBLEED
nb_.get(),
#endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
StringRef{memcachedconf.private_key_file}, StringRef{}, nullptr);
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
}
auto worker =
make_unique<Worker>(loop, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx,
cert_tree, ticket_keys_);
#ifdef HAVE_MRUBY
if (worker->create_mruby_context() != 0) {
return -1;
@@ -294,7 +326,8 @@ void ConnectionHandler::graceful_shutdown_worker() {
#endif // NOTHREADS
}
int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen) {
int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen,
const UpstreamAddr *faddr) {
if (LOG_ENABLED(INFO)) {
LLOG(INFO, this) << "Accepted connection. fd=" << fd;
}
@@ -314,7 +347,7 @@ int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen) {
}
auto client =
ssl::accept_connection(single_worker_.get(), fd, addr, addrlen);
ssl::accept_connection(single_worker_.get(), fd, addr, addrlen, faddr);
if (!client) {
LLOG(ERROR, this) << "ClientHandler creation failed";
@@ -335,6 +368,7 @@ int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen) {
wev.client_fd = fd;
memcpy(&wev.client_addr, addr, addrlen);
wev.client_addrlen = addrlen;
wev.faddr = faddr;
workers_[idx]->send(wev);
@@ -349,39 +383,19 @@ Worker *ConnectionHandler::get_single_worker() const {
return single_worker_.get();
}
void ConnectionHandler::set_acceptor(std::unique_ptr<AcceptHandler> h) {
acceptor_ = std::move(h);
}
AcceptHandler *ConnectionHandler::get_acceptor() const {
return acceptor_.get();
}
void ConnectionHandler::set_acceptor6(std::unique_ptr<AcceptHandler> h) {
acceptor6_ = std::move(h);
}
AcceptHandler *ConnectionHandler::get_acceptor6() const {
return acceptor6_.get();
void ConnectionHandler::add_acceptor(std::unique_ptr<AcceptHandler> h) {
acceptors_.push_back(std::move(h));
}
void ConnectionHandler::enable_acceptor() {
if (acceptor_) {
acceptor_->enable();
}
if (acceptor6_) {
acceptor6_->enable();
for (auto &a : acceptors_) {
a->enable();
}
}
void ConnectionHandler::disable_acceptor() {
if (acceptor_) {
acceptor_->disable();
}
if (acceptor6_) {
acceptor6_->disable();
for (auto &a : acceptors_) {
a->disable();
}
}
@@ -397,11 +411,8 @@ void ConnectionHandler::sleep_acceptor(ev_tstamp t) {
}
void ConnectionHandler::accept_pending_connection() {
if (acceptor_) {
acceptor_->accept_connection();
}
if (acceptor6_) {
acceptor6_->accept_connection();
for (auto &a : acceptors_) {
a->accept_connection();
}
}
@@ -450,7 +461,8 @@ int ConnectionHandler::start_ocsp_update(const char *cert_file) {
assert(!ev_is_active(&ocsp_.chldev));
char *const argv[] = {
const_cast<char *>(get_config()->tls.ocsp.fetch_ocsp_response_file.get()),
const_cast<char *>(
get_config()->tls.ocsp.fetch_ocsp_response_file.c_str()),
const_cast<char *>(cert_file), nullptr};
char *const envp[] = {nullptr};
@@ -746,6 +758,22 @@ void ConnectionHandler::schedule_next_tls_ticket_key_memcached_get(
ev_timer_start(loop_, w);
}
SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
auto &tlsconf = get_config()->tls;
auto &memcachedconf = get_config()->tls.ticket.memcached;
auto ssl_ctx = ssl::create_ssl_client_context(
#ifdef HAVE_NEVERBLEED
nb_.get(),
#endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
StringRef{memcachedconf.private_key_file}, StringRef{}, nullptr);
all_ssl_ctx_.push_back(ssl_ctx);
return ssl_ctx;
}
#ifdef HAVE_NEVERBLEED
void ConnectionHandler::set_neverbleed(std::unique_ptr<neverbleed_t> nb) {
nb_ = std::move(nb);

View File

@@ -58,6 +58,7 @@ class Worker;
struct WorkerStat;
struct TicketKeys;
class MemcachedDispatcher;
struct UpstreamAddr;
struct OCSPUpdateContext {
// ocsp response buffer
@@ -79,7 +80,8 @@ class ConnectionHandler {
public:
ConnectionHandler(struct ev_loop *loop);
~ConnectionHandler();
int handle_connection(int fd, sockaddr *addr, int addrlen);
int handle_connection(int fd, sockaddr *addr, int addrlen,
const UpstreamAddr *faddr);
// Creates Worker object for single threaded configuration.
int create_single_worker();
// Creates |num| Worker objects for multi threaded configuration.
@@ -92,10 +94,7 @@ public:
const std::shared_ptr<TicketKeys> &get_ticket_keys() const;
struct ev_loop *get_loop() const;
Worker *get_single_worker() const;
void set_acceptor(std::unique_ptr<AcceptHandler> h);
AcceptHandler *get_acceptor() const;
void set_acceptor6(std::unique_ptr<AcceptHandler> h);
AcceptHandler *get_acceptor6() const;
void add_acceptor(std::unique_ptr<AcceptHandler> h);
void enable_acceptor();
void disable_acceptor();
void sleep_acceptor(ev_tstamp t);
@@ -130,6 +129,7 @@ public:
on_tls_ticket_key_get_success(const std::shared_ptr<TicketKeys> &ticket_keys,
ev_timer *w);
void schedule_next_tls_ticket_key_memcached_get(ev_timer *w);
SSL_CTX *create_tls_ticket_key_memcached_ssl_ctx();
#ifdef HAVE_NEVERBLEED
void set_neverbleed(std::unique_ptr<neverbleed_t> nb);
@@ -154,10 +154,7 @@ private:
// Worker object.
std::shared_ptr<TicketKeys> ticket_keys_;
struct ev_loop *loop_;
// acceptor for IPv4 address or UNIX domain socket.
std::unique_ptr<AcceptHandler> acceptor_;
// acceptor for IPv6 address
std::unique_ptr<AcceptHandler> acceptor6_;
std::vector<std::unique_ptr<AcceptHandler>> acceptors_;
#ifdef HAVE_NEVERBLEED
std::unique_ptr<neverbleed_t> nb_;
#endif // HAVE_NEVERBLEED

View File

@@ -113,15 +113,26 @@ void downstream_wtimeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
// upstream could be nullptr for unittests
Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
int32_t stream_id)
: dlnext(nullptr), dlprev(nullptr), response_sent_body_length(0),
: dlnext(nullptr),
dlprev(nullptr),
response_sent_body_length(0),
request_start_time_(std::chrono::high_resolution_clock::now()),
request_buf_(mcpool), response_buf_(mcpool), upstream_(upstream),
blocked_link_(nullptr), num_retry_(0), stream_id_(stream_id),
assoc_stream_id_(-1), downstream_stream_id_(-1),
request_buf_(mcpool),
response_buf_(mcpool),
upstream_(upstream),
blocked_link_(nullptr),
num_retry_(0),
stream_id_(stream_id),
assoc_stream_id_(-1),
downstream_stream_id_(-1),
response_rst_stream_error_code_(NGHTTP2_NO_ERROR),
request_state_(INITIAL), response_state_(INITIAL),
dispatch_state_(DISPATCH_NONE), upgraded_(false), chunked_request_(false),
chunked_response_(false), expect_final_response_(false),
request_state_(INITIAL),
response_state_(INITIAL),
dispatch_state_(DISPATCH_NONE),
upgraded_(false),
chunked_request_(false),
chunked_response_(false),
expect_final_response_(false),
request_pending_(false) {
auto &timeoutconf = get_config()->http2.timeout;
@@ -226,15 +237,15 @@ void Downstream::force_resume_read() {
}
namespace {
const Headers::value_type *search_header_linear(const Headers &headers,
const StringRef &name) {
const Headers::value_type *res = nullptr;
for (auto &kv : headers) {
const Headers::value_type *
search_header_linear_backwards(const Headers &headers, const StringRef &name) {
for (auto it = headers.rbegin(); it != headers.rend(); ++it) {
auto &kv = *it;
if (kv.name == name) {
res = &kv;
return &kv;
}
}
return res;
return nullptr;
}
} // namespace
@@ -318,23 +329,20 @@ void Downstream::crumble_request_cookie(std::vector<nghttp2_nv> &nva) {
}
namespace {
void add_header(bool &key_prev, size_t &sum, Headers &headers, std::string name,
std::string value) {
void add_header(bool &key_prev, size_t &sum, Headers &headers,
const StringRef &name, const StringRef &value, bool no_index,
int32_t token) {
key_prev = true;
sum += name.size() + value.size();
headers.emplace_back(std::move(name), std::move(value));
headers.emplace_back(name.str(), value.str(), no_index, token);
}
} // namespace
namespace {
void add_header(size_t &sum, Headers &headers, const uint8_t *name,
size_t namelen, const uint8_t *value, size_t valuelen,
bool no_index, int16_t token) {
sum += namelen + valuelen;
headers.emplace_back(
std::string(reinterpret_cast<const char *>(name), namelen),
std::string(reinterpret_cast<const char *>(value), valuelen), no_index,
token);
void add_header(size_t &sum, Headers &headers, const StringRef &name,
const StringRef &value, bool no_index, int32_t token) {
sum += name.size() + value.size();
headers.emplace_back(name.str(), value.str(), no_index, token);
}
} // namespace
@@ -345,6 +353,8 @@ void append_last_header_key(bool &key_prev, size_t &sum, Headers &headers,
sum += len;
auto &item = headers.back();
item.name.append(data, len);
util::inp_strlower(item.name);
item.token = http2::lookup_token(item.name);
}
} // namespace
@@ -358,67 +368,62 @@ void append_last_header_value(bool &key_prev, size_t &sum, Headers &headers,
}
} // namespace
int FieldStore::index_headers() {
http2::init_hdidx(hdidx_);
int FieldStore::parse_content_length() {
content_length = -1;
for (size_t i = 0; i < headers_.size(); ++i) {
auto &kv = headers_[i];
util::inp_strlower(kv.name);
auto token = http2::lookup_token(
reinterpret_cast<const uint8_t *>(kv.name.c_str()), kv.name.size());
if (token < 0) {
for (auto &kv : headers_) {
if (kv.token != http2::HD_CONTENT_LENGTH) {
continue;
}
kv.token = token;
http2::index_header(hdidx_, token, i);
if (token == http2::HD_CONTENT_LENGTH) {
auto len = util::parse_uint(kv.value);
if (len == -1) {
return -1;
}
if (content_length != -1) {
return -1;
}
content_length = len;
auto len = util::parse_uint(kv.value);
if (len == -1) {
return -1;
}
if (content_length != -1) {
return -1;
}
content_length = len;
}
return 0;
}
const Headers::value_type *FieldStore::header(int16_t token) const {
return http2::get_header(hdidx_, token, headers_);
const Headers::value_type *FieldStore::header(int32_t token) const {
for (auto it = headers_.rbegin(); it != headers_.rend(); ++it) {
auto &kv = *it;
if (kv.token == token) {
return &kv;
}
}
return nullptr;
}
Headers::value_type *FieldStore::header(int16_t token) {
return http2::get_header(hdidx_, token, headers_);
Headers::value_type *FieldStore::header(int32_t token) {
for (auto it = headers_.rbegin(); it != headers_.rend(); ++it) {
auto &kv = *it;
if (kv.token == token) {
return &kv;
}
}
return nullptr;
}
const Headers::value_type *FieldStore::header(const StringRef &name) const {
return search_header_linear(headers_, name);
return search_header_linear_backwards(headers_, name);
}
void FieldStore::add_header(std::string name, std::string value) {
shrpx::add_header(header_key_prev_, buffer_size_, headers_, std::move(name),
std::move(value));
void FieldStore::add_header_lower(const StringRef &name, const StringRef &value,
bool no_index) {
auto low_name = name.str();
util::inp_strlower(low_name);
auto token = http2::lookup_token(low_name);
shrpx::add_header(header_key_prev_, buffer_size_, headers_,
StringRef{low_name}, value, no_index, token);
}
void FieldStore::add_header(std::string name, std::string value,
int16_t token) {
http2::index_header(hdidx_, token, headers_.size());
buffer_size_ += name.size() + value.size();
headers_.emplace_back(std::move(name), std::move(value), false, token);
}
void FieldStore::add_header(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
bool no_index, int16_t token) {
http2::index_header(hdidx_, token, headers_.size());
shrpx::add_header(buffer_size_, headers_, name, namelen, value, valuelen,
no_index, token);
void FieldStore::add_header_token(const StringRef &name, const StringRef &value,
bool no_index, int32_t token) {
shrpx::add_header(buffer_size_, headers_, name, value, no_index, token);
}
void FieldStore::append_last_header_key(const char *data, size_t len) {
@@ -431,23 +436,23 @@ void FieldStore::append_last_header_value(const char *data, size_t len) {
data, len);
}
void FieldStore::clear_headers() {
headers_.clear();
http2::init_hdidx(hdidx_);
void FieldStore::clear_headers() { headers_.clear(); }
void FieldStore::add_trailer_lower(const StringRef &name,
const StringRef &value, bool no_index) {
auto low_name = name.str();
util::inp_strlower(low_name);
auto token = http2::lookup_token(low_name);
shrpx::add_header(trailer_key_prev_, buffer_size_, trailers_,
StringRef{low_name}, value, no_index, token);
}
void FieldStore::add_trailer(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
bool no_index, int16_t token) {
// we never index trailer fields. Header size limit should be
// applied to all header and trailer fields combined.
shrpx::add_header(buffer_size_, trailers_, name, namelen, value, valuelen,
no_index, -1);
}
void FieldStore::add_trailer(std::string name, std::string value) {
shrpx::add_header(trailer_key_prev_, buffer_size_, trailers_, std::move(name),
std::move(value));
void FieldStore::add_trailer_token(const StringRef &name,
const StringRef &value, bool no_index,
int32_t token) {
// Header size limit should be applied to all header and trailer
// fields combined.
shrpx::add_header(buffer_size_, trailers_, name, value, no_index, token);
}
void FieldStore::append_last_trailer_key(const char *data, size_t len) {

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