Compare commits

...

171 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
a61054e1f7 Update bash_completion 2015-06-12 22:38:32 +09:00
Tatsuhiro Tsujikawa
749f5d6a32 Update man pages 2015-06-12 22:38:19 +09:00
Tatsuhiro Tsujikawa
f09bd821ac Bump up version number to 1.0.2, LT revision to 14:2:0 2015-06-12 22:35:29 +09:00
Tatsuhiro Tsujikawa
6d5c00b8eb nghttpx: Use vector for WorkerEvent queue 2015-06-12 21:28:24 +09:00
Tatsuhiro Tsujikawa
532bffdb01 nghttpx: Minimize critical section for shared ocsp response 2015-06-12 21:27:12 +09:00
Tatsuhiro Tsujikawa
c6c7145167 Fix compile warning with android NDK 2015-06-12 19:19:53 +09:00
Tatsuhiro Tsujikawa
b5717cd288 Fix bug that data are not consumed for connection in race condition
When we know that stream is closed at time we read DATA frame header,
we use NGHTTP2_IB_IGN_DATA, and consume data for connection if
nghttp2_option_set_no_auto_window_update() is used.  However, if
stream is closed while we are in NGHTTP2_IB_READ_DATA, those bytes are
not consumed for connection, nor notified to application via callback,
so it eventually fills up connection window and connection will
freeze.  This commit fixes this issue by consuming these data for
connection when stream is closed or does not exist.
2015-06-11 23:34:30 +09:00
Tatsuhiro Tsujikawa
d4d7597efb nghttpx: Delete SSL_CTX on quit 2015-06-10 21:31:58 +09:00
Tatsuhiro Tsujikawa
2952706b53 Fix scan-build error 2015-06-10 00:29:03 +09:00
Tatsuhiro Tsujikawa
9b0ccdef34 h2load: Code cleanup 2015-06-10 00:28:27 +09:00
Tatsuhiro Tsujikawa
41dd5f6897 nghttpx: Tokenize request method
We share the same method value with http-parser.  This commit also
returns 501 for unknown request method on HTTP/2 and SPDY frontend.
2015-06-09 23:33:14 +09:00
Tatsuhiro Tsujikawa
f9c60d5e9d nghttpx: Return 501 if invalid method is received on h1 frontend 2015-06-09 22:08:49 +09:00
Tatsuhiro Tsujikawa
c2ca04c1db python: Call on_close callback when connection is lost for server session 2015-06-07 16:17:48 +09:00
Tatsuhiro Tsujikawa
5fbb99e3d0 Check python without python bindings to get PYTHON variable
We use PYTHON variable to execute Python script, mainly to generate
documents.  Therefore it is better to always check python interpreter
even if we don't request python bindings
2015-06-07 13:14:31 +09:00
Tatsuhiro Tsujikawa
ba34313f9f mkapiref.py: Ensure better 2 and 3 support 2015-06-07 13:13:51 +09:00
Tatsuhiro Tsujikawa
aa6699435a make_bash_completion.py: Support Python 3.4 2015-06-07 13:01:02 +09:00
Tatsuhiro Tsujikawa
e857e99df8 help2rst.py: Support Python 3.4 2015-06-07 12:55:22 +09:00
Tatsuhiro Tsujikawa
6d537c419e nghttpx: Document failure case on bind() 2015-06-07 00:05:33 +09:00
Tatsuhiro Tsujikawa
4894e24dc8 nghttpx: Add error logging for listener socket creation failure 2015-06-07 00:02:30 +09:00
Tatsuhiro Tsujikawa
bbbddedb8f Fix compiler warning 2015-06-06 23:37:46 +09:00
Tatsuhiro Tsujikawa
163dfb3150 Fix make distcheck failure 2015-06-06 23:37:31 +09:00
Tatsuhiro Tsujikawa
4f3d20e024 Include script/README.rst in dist 2015-06-06 23:32:32 +09:00
Tatsuhiro Tsujikawa
b7ba1baf48 Translate fetch-ocsp-response into Python 2015-06-06 23:18:32 +09:00
Tatsuhiro Tsujikawa
00efa86fb6 nghttpx: Add --add-request-header option 2015-06-05 23:04:20 +09:00
Tatsuhiro Tsujikawa
43b3640836 Slight code cleanup 2015-06-05 22:06:49 +09:00
Tatsuhiro Tsujikawa
708eb2a217 Increase maximum number of streams in one dep tree including idle nodes 2015-06-05 22:06:14 +09:00
Tatsuhiro Tsujikawa
590a5c3ff3 Fix typo 2015-06-05 00:18:29 +09:00
Tatsuhiro Tsujikawa
28b528dc9e Merge branch 'vapier-master' 2015-06-04 23:45:49 +09:00
Mike Frysinger
a50f6e5d50 configure: fix bashism
The == operator is not in POSIX; use = like normal.

Reported-by: Mikael Magnusson <mikachu@gmail.com>
2015-06-04 00:10:00 -04:00
Tatsuhiro Tsujikawa
1534edd3f3 Update building android doc to include zlib build instruction 2015-06-01 23:14:38 +09:00
Tatsuhiro Tsujikawa
892c159d8f Remove unused clock_gettime and dlsym detection 2015-06-01 23:05:42 +09:00
Tatsuhiro Tsujikawa
0cb4750e3c libevent-client: Fix bug that path is broken if URI does not contain path part 2015-06-01 00:22:35 +09:00
Tatsuhiro Tsujikawa
ee4d53a9e4 More constexpr 2015-05-31 18:44:37 +09:00
Tatsuhiro Tsujikawa
ad150c3ab1 Merge branch 'fwiesel-client_certificate' 2015-05-31 18:28:16 +09:00
Fabian Wiesel
7eafebfeb9 Expose client certificate, if available
Client certificates can use used for authentication/authorization in the server,
so expose them similar to the remote address.
2015-05-31 10:55:10 +02:00
Tatsuhiro Tsujikawa
3d59c6c0b7 nghttpx: Use defined string iteral when defining long_options 2015-05-29 22:48:46 +09:00
Tatsuhiro Tsujikawa
34efc6b7a4 More constexpr 2015-05-29 22:36:05 +09:00
Tatsuhiro Tsujikawa
7582640fd5 nghttpx: Remove unused 2015-05-29 22:20:46 +09:00
Tatsuhiro Tsujikawa
ad265aa9d0 Build third-party if either examples or apps is enabled 2015-05-28 22:55:47 +09:00
Tatsuhiro Tsujikawa
1f7e6ea3fe Define NGHTTP2_EXTERN to __declspec(dllimport) when using nghttp2
The private global variable nghttp2_enable_strict_preface is also
marked as NGHTTP2_EXTERN, but it is test purpose only (test with
.dll), and not part of public API.  It could be removed in the future
release.
2015-05-28 22:36:43 +09:00
Tatsuhiro Tsujikawa
a0a5f4f93e tests: Break if all compressed header input processed in nghttp2_buf 2015-05-27 00:33:24 +09:00
Tatsuhiro Tsujikawa
59e6272ba4 integration: Add WebSocket upgrade test 2015-05-26 23:28:45 +09:00
Tatsuhiro Tsujikawa
323fc8c552 nghttpx: Make WebSocket upgrade work
This commit makes sure that WebSocket upgrade works for HTTP/1.1
frontend and backend pair.  Actually, this implementation probably
supports other upgrade as well, other than HTTP/2 Upgrade, which is
handled specially in other place.
2015-05-26 22:26:17 +09:00
Tatsuhiro Tsujikawa
cbb10aa80f Merge branch 'fwiesel-python3.4-on-macos' 2015-05-26 00:48:42 +09:00
Fabian Wiesel
abe4c7c92a Catch and log failure to set TCP_NODELAY
Setting TCP_NODELAY may fail. Instead of failing the routine, log it and continue.
It seems, that setting TCP_NODELAY in python on Mac OS X is not necessarily supported.
2015-05-25 17:39:54 +02:00
Tatsuhiro Tsujikawa
326b4c467b nghttpx: Fix bug that END_STREAM is not set in backend for POST with Upgrade 2015-05-26 00:00:11 +09:00
Tatsuhiro Tsujikawa
7e51a87111 nghttpx: Don't upgrade to HTTP/2 if we have non-final HTTP/1 response pending 2015-05-25 23:59:44 +09:00
Tatsuhiro Tsujikawa
5fdb36239a nghttpx: Don't send Expect header field twice 2015-05-25 23:59:18 +09:00
Tatsuhiro Tsujikawa
9f99cad9ab Bump up version number to 1.0.2-DEV 2015-05-24 19:50:35 +09:00
Tatsuhiro Tsujikawa
7c7d4700f1 Update README.rst about go spdy package 2015-05-24 19:26:53 +09:00
Tatsuhiro Tsujikawa
8e5c8430f1 Update man pages 2015-05-24 19:21:24 +09:00
Tatsuhiro Tsujikawa
92ecd3c0fb Bump up version number to 1.0.1, LT revision to 14:1:0 2015-05-24 19:11:18 +09:00
Tatsuhiro Tsujikawa
90eac0709d src: Make sure that empty param is error when parsing Link header field 2015-05-24 15:40:16 +09:00
Tatsuhiro Tsujikawa
791660ef8d Fix up OpenSSL initialization
Use the example presented at
http://en.wikibooks.org/wiki/OpenSSL/Initialization
2015-05-23 00:23:38 +09:00
Tatsuhiro Tsujikawa
1c06cfd29f integration: Use our own copy of golang spdy package
Official golang spdy package is done.  We made a copy of it until we
drop spdy support.
2015-05-23 00:01:45 +09:00
Tatsuhiro Tsujikawa
f0379aa428 Fix invalid memory free 2015-05-22 23:36:34 +09:00
Tatsuhiro Tsujikawa
9a0b9428da nghttpx: Fill request scheme in upstream
We may log before filling scheme in Downstream, so we leave
construct_absolute_request_uri as is.
2015-05-22 02:22:59 +09:00
Tatsuhiro Tsujikawa
b20abfc11a nghttpx: Allow HTTP Upgrade from POST request if response header was not sent 2015-05-22 01:59:40 +09:00
Tatsuhiro Tsujikawa
d983dd81ec Update http-parser to 39ff0975c220ef76a2d98c8ac61b0d36f4dce80f 2015-05-22 01:55:47 +09:00
Tatsuhiro Tsujikawa
bcf9e66dbc Update README.rst 2015-05-22 01:40:23 +09:00
Tatsuhiro Tsujikawa
890a10b216 nghttpx: Fix bug that PUSH_PROMISE is sent after associated response HEADERS 2015-05-22 00:53:02 +09:00
Tatsuhiro Tsujikawa
28adb2dad3 h2load: Fix bug that NPN fails if ALPN is enabled 2015-05-22 00:48:32 +09:00
Tatsuhiro Tsujikawa
c795018f29 Dockerfile.android: Update NDK ver, and ubuntu; build and link zlib 2015-05-21 00:45:01 +09:00
Tatsuhiro Tsujikawa
c1a663b577 Don't link zlib bundled with android NDK 2015-05-21 00:15:04 +09:00
Tatsuhiro Tsujikawa
2b450f26ba Comment out uninstall-local for python
This uninstall-local rule is too strong; it could delete unexpected
files, although they are likely nghttp2 related.
2015-05-20 22:50:58 +09:00
Tatsuhiro Tsujikawa
1ddff5bbf9 Include stdint.h instead of inttypes.h when compiled with MSVC < 2013 2015-05-20 22:33:57 +09:00
Tatsuhiro Tsujikawa
3a4c8bc8f1 Document about small write 2015-05-19 22:56:23 +09:00
Tatsuhiro Tsujikawa
fe752174a9 nghttpd: Close connection after settings timeout and GOAWAY was sent 2015-05-18 21:38:12 +09:00
Tatsuhiro Tsujikawa
494ed221b6 Merge branch 'alagoutte-scan-build' 2015-05-16 02:17:28 +09:00
Tatsuhiro Tsujikawa
14f971d71f Merge branch 'scan-build' of https://github.com/alagoutte/nghttp2 into alagoutte-scan-build 2015-05-16 02:15:38 +09:00
Alexis La Goutte
ddee5d3896 fix Value stored to 'rv' is never read found by Clang Analyzer 2015-05-15 18:11:59 +02:00
Tatsuhiro Tsujikawa
447e346b1e Bump up version number to 1.0.1-DEV 2015-05-16 00:25:34 +09:00
Tatsuhiro Tsujikawa
553d741f03 Fix migration version number 2015-05-16 00:15:00 +09:00
Tatsuhiro Tsujikawa
6bd728b3c2 Update man pages 2015-05-16 00:10:41 +09:00
Tatsuhiro Tsujikawa
a99085891a Bump up version number to 1.0.0, LT revision to 14:0:0 2015-05-16 00:03:08 +09:00
Tatsuhiro Tsujikawa
68d3724fad Update README.rst 2015-05-15 23:55:30 +09:00
Tatsuhiro Tsujikawa
fe39ec8697 doc: Update Resources 2015-05-15 23:36:51 +09:00
Tatsuhiro Tsujikawa
c896118747 Fix required spdylay version 2015-05-15 23:32:15 +09:00
Tatsuhiro Tsujikawa
b89140c311 Merge branch 'v1.0.0' 2015-05-15 23:30:59 +09:00
Tatsuhiro Tsujikawa
a869c39a2c Bump up version number to 1.0.0-DEV 2015-05-15 23:30:24 +09:00
Tatsuhiro Tsujikawa
0b27f005e0 Merge branch 'master' into v1.0.0
Conflicts:
	src/HttpServer.cc
2015-05-15 23:24:19 +09:00
Tatsuhiro Tsujikawa
92a20c76e6 Update bash_completion 2015-05-15 23:01:33 +09:00
Tatsuhiro Tsujikawa
42ccea806c Update man pages 2015-05-15 23:01:19 +09:00
Tatsuhiro Tsujikawa
805f36d134 Bump up version number to 0.7.15, LT revision to 13:4:8 2015-05-15 22:59:00 +09:00
Tatsuhiro Tsujikawa
e2c0a3e43b Retry finding jemalloc lib by je_malloc_stats_print
Fixes GH-233
2015-05-15 22:40:49 +09:00
Tatsuhiro Tsujikawa
3572e7c634 inflatehd: Fix crash if 'wire' value is not string
Fixes GH-235
2015-05-15 22:29:57 +09:00
Tatsuhiro Tsujikawa
0479f833fc Revert "nghttpx: Remove last write/read fields for TLS"
This reverts commit 585af93828.
2015-05-15 22:20:15 +09:00
Tatsuhiro Tsujikawa
252aeb43e1 Add test for GH-232 2015-05-15 01:00:09 +09:00
Tatsuhiro Tsujikawa
24fe24b37d Merge branch 'etcimon-patch-1' 2015-05-15 00:57:07 +09:00
Etienne Cimon
32603d7eff Access violation in buffers
When adding a large amount of data that spans to multiple chunks, the pointer is incremented by the wrong value.
2015-05-14 10:45:17 -04:00
Tatsuhiro Tsujikawa
53bfc70c9e Include inttypes.h (or cintypes for C++) instead of stdint.h
From autoconf manual, section 5.6.1 Portability of Headers, says:

"""
The C99 standard says that inttypes.h includes stdint.h, so there's no
need to include stdint.h separately in a standard environment. Some
implementations have inttypes.h but not stdint.h (e.g., Solaris 7),
but we don't know of any implementation that has stdint.h but not
inttypes.h.
"""
2015-05-14 00:17:45 +09:00
Tatsuhiro Tsujikawa
c4068cd404 Fix travis build error
Remove AC_PROG_RANLIB because it is rendered obsolete by LT_INIT.
Remove AC_CHECK_HEADER_STDBOOl, because travis does not have one.
2015-05-13 23:48:31 +09:00
Tatsuhiro Tsujikawa
0aa17f64c1 doc: Remove 'NGHTTP2_EXTERN' from api doc 2015-05-13 23:39:48 +09:00
Tatsuhiro Tsujikawa
38cfc5c47c Check more headers and funcs 2015-05-13 23:29:20 +09:00
Tatsuhiro Tsujikawa
91c8f085ef Update man pages 2015-05-13 00:44:37 +09:00
Tatsuhiro Tsujikawa
5da49989f8 nghttpd: Add --echo-upload option to send back request body 2015-05-13 00:38:28 +09:00
Tatsuhiro Tsujikawa
260131966d help2rst.py: Add comment to tell that this is a generated file 2015-05-12 23:30:17 +09:00
Tatsuhiro Tsujikawa
6862f66c23 Merge branch 'syohex-misspelling' 2015-05-12 23:25:33 +09:00
Tatsuhiro Tsujikawa
2f2a7ace81 Fix corresponding upstream source reported in previous commits accordingly 2015-05-12 23:24:18 +09:00
Syohei YOSHIDA
132719f752 Correct misspellings in document 2015-05-12 10:49:42 +09:00
Tatsuhiro Tsujikawa
64b1aae567 integration: Fix TestH2H1Upgrade test failure 2015-05-08 19:35:09 +09:00
Tatsuhiro Tsujikawa
a8625e15f0 clang-format 2015-05-08 19:24:17 +09:00
Tatsuhiro Tsujikawa
e63d6e490a Merge branch 'master' into v1.0.0
Conflicts:
	lib/nghttp2_option.h
	lib/nghttp2_session.h
	src/HttpServer.cc
2015-05-08 19:21:51 +09:00
Tatsuhiro Tsujikawa
7f60de0c51 Bump up version number to 0.7.15-DEV 2015-05-08 18:36:58 +09:00
Tatsuhiro Tsujikawa
3a46a2c0a4 Update man pages 2015-05-08 17:55:15 +09:00
Tatsuhiro Tsujikawa
fbff101165 Update bash_completion 2015-05-08 17:54:51 +09:00
Tatsuhiro Tsujikawa
526d2c727d Bump up version number to 0.7.14, LT revision to 13:3:8 2015-05-08 17:51:54 +09:00
Tatsuhiro Tsujikawa
6c232da679 Merge branch 'alagoutte-misc' 2015-05-07 23:40:22 +09:00
Alexis La Goutte
1241c951d6 rv is only used in an assert.
The assert only evaluates to code if NDEBUG is undefined. Protect rv and its use accordingly

Issue reported by Joerg Mayer
https://code.wireshark.org/review/8260
2015-05-07 15:20:24 +02:00
Tatsuhiro Tsujikawa
73e79130d1 Update doc 2015-05-07 21:14:21 +09:00
Tatsuhiro Tsujikawa
1a1902350b Update sphinx_rtd_theme 2015-05-07 21:09:57 +09:00
Tatsuhiro Tsujikawa
eec65826cf Update man pages 2015-05-07 20:55:10 +09:00
Tatsuhiro Tsujikawa
fc17c0a618 Fix global-buffer-overflow 2015-05-07 19:37:43 +09:00
Tatsuhiro Tsujikawa
2620992003 Document about time for connect and time for 1st byte in h2load man page 2015-05-07 18:58:32 +09:00
Tatsuhiro Tsujikawa
5a2069b55c Merge branch 'wzyboy-patch-upstart' 2015-05-06 15:56:57 +09:00
Tatsuhiro Tsujikawa
14adcb2d81 Substitute bindir in nghttpx-upstart.conf 2015-05-06 15:56:18 +09:00
Tatsuhiro Tsujikawa
13660edef2 Merge branch 'patch-upstart' of https://github.com/wzyboy/nghttp2 into wzyboy-patch-upstart 2015-05-06 15:54:42 +09:00
Tatsuhiro Tsujikawa
98034286ac Substitute bindir in nghttpx.service 2015-05-06 15:53:12 +09:00
Tatsuhiro Tsujikawa
2a37a28d72 Revert "Substitute bindir for nghttpx.service"
This reverts commit 7bb154f768.
2015-05-06 15:37:56 +09:00
Tatsuhiro Tsujikawa
7bb154f768 Substitute bindir for nghttpx.service
Use static pattern rules to use same recipe for nghttpx-init and
nghttpx.service.

Also rewrite how to produce nghttpx
2015-05-06 12:02:12 +09:00
Zhuoyun Wei
eb96aa261f Add Upstart configuration file 2015-05-06 10:38:24 +08:00
Tatsuhiro Tsujikawa
232d359cbb Add nghttpx.service to distribution 2015-05-06 11:02:51 +09:00
Tatsuhiro Tsujikawa
2d5d9d5d04 nghttpd: Add -m, --max-concurrent-streams option 2015-05-06 10:42:43 +09:00
Tatsuhiro Tsujikawa
7ecca39025 nghttpx: Fix heap-use-after-free bug in http/1 frontend
This is a regression introduced in
4be4d875f3
2015-05-05 23:45:39 +09:00
Tatsuhiro Tsujikawa
bc0190c19f Merge branch 'wzyboy-patch-systemd-service' 2015-05-05 22:37:40 +09:00
Tatsuhiro Tsujikawa
9a162b81f0 Merge branch 'patch-systemd-service' of https://github.com/wzyboy/nghttp2 into wzyboy-patch-systemd-service 2015-05-05 22:37:21 +09:00
Tatsuhiro Tsujikawa
a67a8fabff Merge branch 'wzyboy-patch-logrotate' 2015-05-05 22:36:06 +09:00
Zhuoyun Wei
989d381aab Add systemd service file 2015-05-04 23:56:09 +08:00
Zhuoyun Wei
1d65d82cb5 Improve logrotate configuration file
- Avoid changing file permissions
- Make sure all log files are reopened
- Remove non-sense prerotate script
- Send SIGUSR1 to all nghttpx processes
2015-05-04 23:17:27 +08:00
Tatsuhiro Tsujikawa
4be4d875f3 nghttpx: Log absolute URI for HTTP/2 or client proxy request 2015-05-04 23:24:33 +09:00
Tatsuhiro Tsujikawa
1ab707713f nghttpx: Accept reference instead of pointer by upstream_accesslog 2015-05-04 22:45:34 +09:00
Tatsuhiro Tsujikawa
cc46d363c5 h2load: Refactor statistics hanlding to scale more upcoming new metrics 2015-05-04 22:36:21 +09:00
Tatsuhiro Tsujikawa
fa082cbdd0 Merge branch 'alex-nalivko-include_pull_request' 2015-05-03 16:52:27 +09:00
Tatsuhiro Tsujikawa
016d40ea0f Merge branch 'include_pull_request' of https://github.com/alex-nalivko/nghttp2 into alex-nalivko-include_pull_request 2015-05-03 16:50:52 +09:00
Tatsuhiro Tsujikawa
fe6d065bb4 Merge branch 'ericcarlschwartz-finer_stats' 2015-05-03 16:47:52 +09:00
Tatsuhiro Tsujikawa
b4e8bea4b5 clang-format 2015-05-03 16:47:32 +09:00
Tatsuhiro Tsujikawa
555d5abac9 Merge branch 'finer_stats' of https://github.com/ericcarlschwartz/nghttp2 into ericcarlschwartz-finer_stats 2015-05-03 16:37:02 +09:00
Alex Nalivko
3137dc4a70 h2load_spdy_session errno include 2015-05-02 19:33:04 +00:00
es
4bba4bf66c update h2load to give connect time and ttfb stats
finer statistics for h2load: update per comments from tatsuhiro-t

finer stats for h2load: fixed formatting
2015-05-01 10:30:09 -07:00
Tatsuhiro Tsujikawa
7b3a33a313 README.rst: Fix formatting and remove trailing spaces 2015-05-01 13:29:43 +09:00
Tatsuhiro Tsujikawa
ee52290de7 Merge branch 'brk0v-typo' 2015-05-01 00:41:48 +09:00
Viacheslav Biriukov
8f0899a190 mages to images typo 2015-04-30 18:22:51 +03:00
Tatsuhiro Tsujikawa
f6cfd082c7 Merge branch 'alagoutte-misc' 2015-04-30 18:43:41 +09:00
Tatsuhiro Tsujikawa
9d81be4b35 Merge branch 'misc' of https://github.com/alagoutte/nghttp2 into alagoutte-misc 2015-04-30 18:42:17 +09:00
Alexis La Goutte
a62778d6b0 fix comma at end of enumerator list [-Wpedantic] 2015-04-30 07:49:55 +02:00
Tatsuhiro Tsujikawa
ea612a2dce Merge branch 'nghttpx-headers-size-option' 2015-04-29 22:55:30 +09:00
Tatsuhiro Tsujikawa
026521b097 integration: Add tests for --header-field-buffer and --max-header-fields 2015-04-29 22:54:25 +09:00
Tatsuhiro Tsujikawa
9dc5259593 nghttpx: Take into account request URI in header size in https frontend 2015-04-29 22:23:25 +09:00
Tatsuhiro Tsujikawa
ea8a566d98 nghttpx: Send 431 if header field size exceeded the configuration limit 2015-04-29 21:39:46 +09:00
Tatsuhiro Tsujikawa
8c6f9e899f nghttpx: Enforce header field buffer limit for SPDY frontend 2015-04-29 21:27:36 +09:00
Tatsuhiro Tsujikawa
552f675466 nghttpx: Add --header-field-buffer and --max-header-fields options 2015-04-29 21:10:59 +09:00
Tatsuhiro Tsujikawa
f9a50333d2 Fix doc for nghttp2_select_next_protocol
We have to return this error code to notify OpenSSL that we have not
filled any values in |*out| and |*outlen|.
2015-04-28 23:12:27 +09:00
Tatsuhiro Tsujikawa
de4735092a Fix doc formatting 2015-04-28 23:06:48 +09:00
Tatsuhiro Tsujikawa
1c4df1832b Update doc, mainly for RFC numbers 2015-04-28 23:05:00 +09:00
Tatsuhiro Tsujikawa
1ad1fe6005 Merge branch 'master' into v1.0.0 2015-04-28 22:48:34 +09:00
Tatsuhiro Tsujikawa
f05a4830c5 nghttp: Fix assertion error if very large value is given to -t 2015-04-28 21:51:28 +09:00
Tatsuhiro Tsujikawa
9e1b068a4b Fix bug that promised stream was not reset on decompression error 2015-04-28 21:38:52 +09:00
Tatsuhiro Tsujikawa
54bff91762 Bump up version number to 0.7.14-DEV 2015-04-28 00:01:09 +09:00
Tatsuhiro Tsujikawa
db4a68454a Merge branch 'master' into v1.0.0
Conflicts:
	lib/includes/nghttp2/nghttp2.h
2015-04-24 00:13:15 +09:00
Tatsuhiro Tsujikawa
5937b4b6f7 Merge branch 'master' into v1.0.0 2015-04-19 23:13:38 +09:00
Tatsuhiro Tsujikawa
90bfea77e0 doc: Remove nghttp2_submit_altsvc.rst 2015-04-08 18:12:54 +09:00
Tatsuhiro Tsujikawa
cf0576253f Merge branch 'master' into v1.0.0 2015-04-08 18:10:04 +09:00
Tatsuhiro Tsujikawa
59e3783f3f Update manual entry 2015-04-07 00:19:57 +09:00
Tatsuhiro Tsujikawa
084e4487ed Add migration section 2015-04-05 23:53:19 +09:00
Tatsuhiro Tsujikawa
24897aa50d Update README.rst 2015-04-05 23:15:20 +09:00
Tatsuhiro Tsujikawa
3e50ef439d Announce h2, final HTTP/2 ALPN identifier 2015-04-05 23:15:20 +09:00
Tatsuhiro Tsujikawa
87602e5d72 Use NGHTTP2_PROTOCOL_ERROR for NGHTTP2_ERR_HTTP_{HEADER,MESSAGING} 2015-04-05 23:15:20 +09:00
Tatsuhiro Tsujikawa
d0c27d5229 Send 24 bytes client magic byte string by library
Previously nghttp2_session_send() and nghttp2_session_mem_send() did
not send 24 bytes client magic byte string (MAGIC).  We made
nghttp2_session_recv() and nghttp2_session_mem_recv() process MAGIC by
default, so it is natural to make library send MAGIC as well.  This
commit makes nghttp2_session_send() and nghttp2_session_mem_send()
send MAGIC.  This commit also replace "connection preface" with
"client magic", since we call MAGIC as "connection preface" but it is
just a part of connection preface.  NGHTTP2_CLIENT_CONNECTION_PREFACE
macro was replaced with NGHTTP2_CLIENT_MAGIC.  The already deprecated
NGHTTP2_CLIENT_CONNECTION_HEADER macro was removed permanently.
nghttp2_option_set_no_recv_client_preface() was renamed as
nghttp2_option_set_no_recv_client_magic().  NGHTTP2_ERR_BAD_PREFACE
was renamed as NGHTTP2_ERR_BAD_CLIENT_MAGIC.
2015-04-05 23:15:20 +09:00
Tatsuhiro Tsujikawa
ebf214c8fc nghttp2_on_invalid_frame_recv_callback should have lib_error_code as param
nghttp2_error_code is HTTP/2 standard error code and is too coarse to
know what's going on.
2015-04-05 23:15:20 +09:00
Tatsuhiro Tsujikawa
250ea53e4b Deal with 24 bytes client connection preface by default
Since HTTP/2 spec requires for client to send connection preface, it
is reasonable to make this option enabled by default.  It is still a
use case to disable this, so replace this option with
nghttp2_option_set_no_recv_client_preface().
2015-04-05 23:15:20 +09:00
Tatsuhiro Tsujikawa
01af6ea70c Remove ALTSVC related code
HTTP/2 and HPACK are going to be published as RFC, but ALTSVC is still
in draft state.  To make our API stable, it would be better to remove
ALTSVC API for 1.0.0 release.
2015-04-05 23:15:20 +09:00
152 changed files with 4063 additions and 2013 deletions

View File

@@ -10,7 +10,7 @@
#
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
FROM ubuntu:trusty
FROM ubuntu:vivid
MAINTAINER Tatsuhiro Tsujikawa
@@ -30,12 +30,12 @@ RUN apt-get install -y make binutils autoconf automake autotools-dev libtool \
genisoimage libc6-i386 lib32stdc++6
WORKDIR /root/build
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin && \
chmod a+x android-ndk-r10c-linux-x86_64.bin && \
./android-ndk-r10c-linux-x86_64.bin && \
rm android-ndk-r10c-linux-x86_64.bin
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86_64.bin && \
chmod a+x android-ndk-r10d-linux-x86_64.bin && \
./android-ndk-r10d-linux-x86_64.bin && \
rm android-ndk-r10d-linux-x86_64.bin
WORKDIR /root/build/android-ndk-r10c
WORKDIR /root/build/android-ndk-r10d
RUN /bin/bash build/tools/make-standalone-toolchain.sh \
--install-dir=$ANDROID_HOME/toolchain \
--toolchain=arm-linux-androideabi-4.9 --llvm-version=3.5 \
@@ -86,6 +86,25 @@ RUN patch -p1 < ../libev-4.19-android.patch && \
LDFLAGS=-L$PREFIX/lib && \
make install
WORKDIR /root/build
RUN curl -L -O http://zlib.net/zlib-1.2.8.tar.gz && \
tar xf zlib-1.2.8.tar.gz && \
rm zlib-1.2.8.tar.gz
WORKDIR /root/build/zlib-1.2.8
RUN HOST=arm-linux-androideabi \
CC=$HOST-gcc \
AR=$HOST-ar \
LD=$HOST-ld \
RANLIB=$HOST-ranlib \
STRIP=$HOST-strip \
./configure \
--prefix=$PREFIX \
--libdir=$PREFIX/lib \
--includedir=$PREFIX/include \
--static && \
make install
WORKDIR /root/build
RUN git clone https://github.com/tatsuhiro-t/nghttp2
WORKDIR /root/build/nghttp2

View File

@@ -21,7 +21,7 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = lib third-party src examples python tests integration-tests \
doc contrib
doc contrib script
ACLOCAL_AMFLAGS = -I m4

View File

@@ -13,26 +13,18 @@ An HPACK encoder and decoder are available as a public API.
An experimental high level C++ library is also available.
We have Python bindings of this libary, but we do not have full
We have Python bindings of this library, but we do not have full
code coverage yet.
Development Status
------------------
We started to implement h2-14
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), and header
compression
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09).
We have implemented `RFC 7540 <https://tools.ietf.org/html/rfc7540>`_
HTTP/2 and `RFC 7541 <https://tools.ietf.org/html/rfc7541>`_ HPACK -
Header Compression for HTTP/2
The nghttp2 code base was forked from the spdylay project.
=========================== =======
HTTP/2 Features Support
=========================== =======
Core frames handling Yes
Dependency Tree Yes
Large header (CONTINUATION) Yes
=========================== =======
The nghttp2 code base was forked from the spdylay
(https://github.com/tatsuhiro-t/spdylay) project.
Public Test Server
------------------
@@ -46,9 +38,9 @@ implementation.
and ``http/1.1`` via ALPN/NPN and requires TLSv1.2 for HTTP/2
connection.
* http://nghttp2.org/ (Upgrade / Direct)
* http://nghttp2.org/ (HTTP Upgrade and HTTP/2 Direct)
``h2c-14`` and ``http/1.1``.
``h2c`` and ``http/1.1``.
Requirements
------------
@@ -79,7 +71,7 @@ ALPN support requires OpenSSL >= 1.0.2 (released 22 January 2015).
To enable the SPDY protocol in the application program ``nghttpx`` and
``h2load``, the following package is required:
* spdylay >= 1.3.0
* spdylay >= 1.3.2
To enable ``-a`` option (getting linked assets from the downloaded
resource) in ``nghttp``, the following package is required:
@@ -187,7 +179,7 @@ https://nghttp2.org/documentation/
Unit tests
----------
Unit tests are done by simply running `make check`.
Unit tests are done by simply running ``make check``.
Integration tests
-----------------
@@ -198,7 +190,8 @@ its testing framework. We depend on the following libraries:
* https://github.com/bradfitz/http2
* https://github.com/tatsuhiro-t/go-nghttp2
* https://golang.org/x/net/spdy
* https://github.com/tatsuhiro-t/spdy
* golang.org/x/net/websocket
To download the above packages, after settings ``GOPATH``, run the
following command under ``integration-tests`` directory::
@@ -212,6 +205,109 @@ To run the tests, run the following command under
Inside the tests, we use port 3009 to run the test subject server.
.. note::
github.com/tatsuhiro-t/spdy is a copy used to be available at
golang.org/x/net/spdy, but it is now gone.
Migration from v0.7.15 or earlier
---------------------------------
nghttp2 v1.0.0 introduced several backward incompatible changes. In
this section, we describe these changes and how to migrate to v1.0.0.
ALPN protocol ID is now ``h2`` and ``h2c``
++++++++++++++++++++++++++++++++++++++++++
Previously we announced ``h2-14`` and ``h2c-14``. v1.0.0 implements
final protocol version, and we changed ALPN ID to ``h2`` and ``h2c``.
The macros ``NGHTTP2_PROTO_VERSION_ID``,
``NGHTTP2_PROTO_VERSION_ID_LEN``,
``NGHTTP2_CLEARTEXT_PROTO_VERSION_ID``, and
``NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN`` have been updated to
reflect this change.
Basically, existing applications do not have to do anything, just
recompiling is enough for this change.
Use word "client magic" where we use "client connection preface"
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
We use "client connection preface" to mean first 24 bytes of client
connection preface. This is technically not correct, since client
connection preface is composed of 24 bytes client magic byte string
followed by SETTINGS frame. For clarification, we call "client magic"
for this 24 bytes byte string and updated API.
* ``NGHTTP2_CLIENT_CONNECTION_PREFACE`` was replaced with
``NGHTTP2_CLIENT_MAGIC``.
* ``NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN`` was replaced with
``NGHTTP2_CLIENT_MAGIC_LEN``.
* ``NGHTTP2_BAD_PREFACE`` was renamed as ``NGHTTP2_BAD_CLIENT_MAGIC``
The alreay deprecated ``NGHTTP2_CLIENT_CONNECTION_HEADER`` and
``NGHTTP2_CLIENT_CONNECTION_HEADER_LEN`` were removed.
If application uses these macros, just replace old ones with new ones.
Since v1.0.0, client magic is sent by library (see next subsection),
so client application may just remove these macro use.
Client magic is sent by library
+++++++++++++++++++++++++++++++
Previously nghttp2 library did not send client magic, which is first
24 bytes byte string of client connection preface, and client
applications have to send it by themselves. Since v1.0.0, client
magic is sent by library via first call of ``nghttp2_session_send()``
or ``nghttp2_session_mem_send()``.
The client applications which send client magic must remove the
relevant code.
Remove HTTP Alternative Services (Alt-Svc) related code
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alt-Svc specification is not finalized yet. To make our API stable,
we have decided to remove all Alt-Svc related API from nghttp2.
* ``NGHTTP2_EXT_ALTSVC`` was removed.
* ``nghttp2_ext_altsvc`` was removed.
We have already removed the functionality of Alt-Svc in v0.7 series
and they have been essentially noop. The application using these
macro and struct, remove those lines.
Use nghttp2_error in nghttp2_on_invalid_frame_recv_callback
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Previously ``nghttp2_on_invalid_frame_recv_cb_called`` took the
``error_code``, defined in ``nghttp2_error_code``, as parameter. But
they are not detailed enough to debug. Therefore, we decided to use
more detailed ``nghttp2_error`` values instead.
The application using this callback should update the callback
signature. If it treats ``error_code`` as HTTP/2 error code, update
the code so that it is treated as ``nghttp2_error``.
Receive client magic by default
+++++++++++++++++++++++++++++++
Previously nghttp2 did not process client magic (24 bytes byte
string). To make it deal with it, we had to use
``nghttp2_option_set_recv_client_preface()``. Since v1.0.0, nghttp2
processes client magic by default and
``nghttp2_option_set_recv_client_preface()`` was removed.
Some application may want to disable this behaviour, so we added
``nghttp2_option_set_no_recv_client_magic()`` to achieve this.
The application using ``nghttp2_option_set_recv_client_preface()``
with nonzero value, just remove it.
The application using ``nghttp2_option_set_recv_client_preface()``
with zero value or not using it must use
``nghttp2_option_set_no_recv_client_magic()`` with nonzero value.
Client, Server and Proxy programs
---------------------------------
@@ -227,140 +323,180 @@ It has verbose output mode for framing information. Here is sample
output from ``nghttp`` client::
$ nghttp -nv https://nghttp2.org
[ 0.033][NPN] server offers:
* h2-14
* spdy/3.1
* http/1.1
The negotiated protocol: h2-14
[ 0.068] send SETTINGS frame <length=15, flags=0x00, stream_id=0>
(niv=3)
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
[SETTINGS_COMPRESS_DATA(5):1]
[ 0.068] send HEADERS frame <length=46, flags=0x05, stream_id=1>
; END_STREAM | END_HEADERS
(padlen=0)
[ 0.190] Connected
The negotiated protocol: h2
[ 0.212] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0.212] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0.212] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
(dep_stream_id=0, weight=201, exclusive=0)
[ 0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
(dep_stream_id=0, weight=101, exclusive=0)
[ 0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
(dep_stream_id=0, weight=1, exclusive=0)
[ 0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
(dep_stream_id=7, weight=1, exclusive=0)
[ 0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
(dep_stream_id=3, weight=1, exclusive=0)
[ 0.212] send HEADERS frame <length=39, flags=0x25, stream_id=13>
; END_STREAM | END_HEADERS | PRIORITY
(padlen=0, dep_stream_id=11, weight=16, exclusive=0)
; Open new stream
:authority: nghttp2.org
:method: GET
:path: /
:scheme: https
:authority: nghttp2.org
accept: */*
accept-encoding: gzip, deflate
user-agent: nghttp2/0.4.0-DEV
[ 0.068] recv SETTINGS frame <length=10, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
[ 0.068] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
user-agent: nghttp2/1.0.1-DEV
[ 0.221] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.079] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.080] (stream_id=1, noind=0) :status: 200
[ 0.080] (stream_id=1, noind=0) accept-ranges: bytes
[ 0.080] (stream_id=1, noind=0) age: 15
[ 0.080] (stream_id=1, noind=0) content-length: 40243
[ 0.080] (stream_id=1, noind=0) content-type: text/html
[ 0.080] (stream_id=1, noind=0) date: Wed, 14 May 2014 15:14:30 GMT
[ 0.080] (stream_id=1, noind=0) etag: "535d0eea-9d33"
[ 0.080] (stream_id=1, noind=0) last-modified: Sun, 27 Apr 2014 14:06:34 GMT
[ 0.080] (stream_id=1, noind=0) server: nginx/1.4.6 (Ubuntu)
[ 0.080] (stream_id=1, noind=0) x-varnish: 2114900538 2114900537
[ 0.080] (stream_id=1, noind=0) via: 1.1 varnish, 1.1 nghttpx
[ 0.080] (stream_id=1, noind=0) strict-transport-security: max-age=31536000
[ 0.080] recv HEADERS frame <length=162, flags=0x04, stream_id=1>
[ 0.221] recv (stream_id=13) :method: GET
[ 0.221] recv (stream_id=13) :scheme: https
[ 0.221] recv (stream_id=13) :path: /stylesheets/screen.css
[ 0.221] recv (stream_id=13) :authority: nghttp2.org
[ 0.221] recv (stream_id=13) accept-encoding: gzip, deflate
[ 0.222] recv (stream_id=13) user-agent: nghttp2/1.0.1-DEV
[ 0.222] recv PUSH_PROMISE frame <length=50, flags=0x04, stream_id=13>
; END_HEADERS
(padlen=0, promised_stream_id=2)
[ 0.222] recv (stream_id=13) :status: 200
[ 0.222] recv (stream_id=13) date: Thu, 21 May 2015 16:38:14 GMT
[ 0.222] recv (stream_id=13) content-type: text/html
[ 0.222] recv (stream_id=13) last-modified: Fri, 15 May 2015 15:38:06 GMT
[ 0.222] recv (stream_id=13) etag: W/"555612de-19f6"
[ 0.222] recv (stream_id=13) link: </stylesheets/screen.css>; rel=preload; as=stylesheet
[ 0.222] recv (stream_id=13) content-encoding: gzip
[ 0.222] recv (stream_id=13) server: nghttpx nghttp2/1.0.1-DEV
[ 0.222] recv (stream_id=13) via: 1.1 nghttpx
[ 0.222] recv (stream_id=13) strict-transport-security: max-age=31536000
[ 0.222] recv HEADERS frame <length=166, flags=0x04, stream_id=13>
; END_HEADERS
(padlen=0)
; First response header
[ 0.080] recv DATA frame <length=3786, flags=0x00, stream_id=1>
[ 0.080] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.081] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.093] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.093] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.094] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.094] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.094] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.096] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.096] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=36554)
[ 0.096] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=1>
(window_size_increment=36554)
[ 0.108] recv DATA frame <length=3689, flags=0x00, stream_id=1>
[ 0.108] recv DATA frame <length=0, flags=0x01, stream_id=1>
[ 0.222] recv DATA frame <length=2601, flags=0x01, stream_id=13>
; END_STREAM
[ 0.108] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
[ 0.222] recv (stream_id=2) :status: 200
[ 0.222] recv (stream_id=2) date: Thu, 21 May 2015 16:38:14 GMT
[ 0.222] recv (stream_id=2) content-type: text/css
[ 0.222] recv (stream_id=2) last-modified: Fri, 15 May 2015 15:38:06 GMT
[ 0.222] recv (stream_id=2) etag: W/"555612de-9845"
[ 0.222] recv (stream_id=2) content-encoding: gzip
[ 0.222] recv (stream_id=2) server: nghttpx nghttp2/1.0.1-DEV
[ 0.222] recv (stream_id=2) via: 1.1 nghttpx
[ 0.222] recv (stream_id=2) strict-transport-security: max-age=31536000
[ 0.222] recv HEADERS frame <length=32, flags=0x04, stream_id=2>
; END_HEADERS
(padlen=0)
; First push response header
[ 0.228] recv DATA frame <length=8715, flags=0x01, stream_id=2>
; END_STREAM
[ 0.228] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])
The HTTP Upgrade is performed like this::
The HTTP Upgrade is performed like so::
$ nghttp -nvu http://nghttp2.org
[ 0.013] HTTP Upgrade request
[ 0.011] Connected
[ 0.011] HTTP Upgrade request
GET / HTTP/1.1
Host: nghttp2.org
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c-14
HTTP2-Settings: AwAAAGQEAAD__wUAAAAB
Upgrade: h2c
HTTP2-Settings: AAMAAABkAAQAAP__
Accept: */*
User-Agent: nghttp2/0.4.0-DEV
User-Agent: nghttp2/1.0.1-DEV
[ 0.024] HTTP Upgrade response
[ 0.018] HTTP Upgrade response
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c-14
Upgrade: h2c
[ 0.024] HTTP Upgrade success
[ 0.024] send SETTINGS frame <length=15, flags=0x00, stream_id=0>
(niv=3)
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
[SETTINGS_COMPRESS_DATA(5):1]
[ 0.024] recv SETTINGS frame <length=10, flags=0x00, stream_id=0>
[ 0.018] HTTP Upgrade success
[ 0.018] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
[ 0.024] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0.018] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0.018] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.024] (stream_id=1, noind=0) :status: 200
[ 0.024] (stream_id=1, noind=0) accept-ranges: bytes
[ 0.024] (stream_id=1, noind=0) age: 10
[ 0.024] (stream_id=1, noind=0) content-length: 40243
[ 0.024] (stream_id=1, noind=0) content-type: text/html
[ 0.024] (stream_id=1, noind=0) date: Wed, 14 May 2014 15:16:34 GMT
[ 0.024] (stream_id=1, noind=0) etag: "535d0eea-9d33"
[ 0.024] (stream_id=1, noind=0) last-modified: Sun, 27 Apr 2014 14:06:34 GMT
[ 0.024] (stream_id=1, noind=0) server: nginx/1.4.6 (Ubuntu)
[ 0.024] (stream_id=1, noind=0) x-varnish: 2114900541 2114900540
[ 0.024] (stream_id=1, noind=0) via: 1.1 varnish, 1.1 nghttpx
[ 0.024] recv HEADERS frame <length=148, flags=0x04, stream_id=1>
[ 0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
(dep_stream_id=0, weight=201, exclusive=0)
[ 0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
(dep_stream_id=0, weight=101, exclusive=0)
[ 0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
(dep_stream_id=0, weight=1, exclusive=0)
[ 0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
(dep_stream_id=7, weight=1, exclusive=0)
[ 0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
(dep_stream_id=3, weight=1, exclusive=0)
[ 0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=1>
(dep_stream_id=11, weight=16, exclusive=0)
[ 0.019] recv (stream_id=1) :method: GET
[ 0.019] recv (stream_id=1) :scheme: http
[ 0.019] recv (stream_id=1) :path: /stylesheets/screen.css
[ 0.019] recv (stream_id=1) host: nghttp2.org
[ 0.019] recv (stream_id=1) user-agent: nghttp2/1.0.1-DEV
[ 0.019] recv PUSH_PROMISE frame <length=49, flags=0x04, stream_id=1>
; END_HEADERS
(padlen=0, promised_stream_id=2)
[ 0.019] recv (stream_id=1) :status: 200
[ 0.019] recv (stream_id=1) date: Thu, 21 May 2015 16:39:16 GMT
[ 0.019] recv (stream_id=1) content-type: text/html
[ 0.019] recv (stream_id=1) content-length: 6646
[ 0.019] recv (stream_id=1) last-modified: Fri, 15 May 2015 15:38:06 GMT
[ 0.019] recv (stream_id=1) etag: "555612de-19f6"
[ 0.019] recv (stream_id=1) link: </stylesheets/screen.css>; rel=preload; as=stylesheet
[ 0.019] recv (stream_id=1) accept-ranges: bytes
[ 0.019] recv (stream_id=1) server: nghttpx nghttp2/1.0.1-DEV
[ 0.019] recv (stream_id=1) via: 1.1 nghttpx
[ 0.019] recv HEADERS frame <length=157, flags=0x04, stream_id=1>
; END_HEADERS
(padlen=0)
; First response header
[ 0.024] recv DATA frame <length=3786, flags=0x00, stream_id=1>
[ 0.025] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.031] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.031] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.032] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.032] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.033] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.033] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.033] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=33164)
[ 0.033] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=1>
(window_size_increment=33164)
[ 0.038] recv DATA frame <length=4096, flags=0x00, stream_id=1>
[ 0.038] recv DATA frame <length=3689, flags=0x00, stream_id=1>
[ 0.038] recv DATA frame <length=0, flags=0x01, stream_id=1>
[ 0.019] recv DATA frame <length=6646, flags=0x01, stream_id=1>
; END_STREAM
[ 0.038] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
[ 0.019] recv (stream_id=2) :status: 200
[ 0.019] recv (stream_id=2) date: Thu, 21 May 2015 16:39:16 GMT
[ 0.019] recv (stream_id=2) content-type: text/css
[ 0.019] recv (stream_id=2) content-length: 38981
[ 0.019] recv (stream_id=2) last-modified: Fri, 15 May 2015 15:38:06 GMT
[ 0.019] recv (stream_id=2) etag: "555612de-9845"
[ 0.019] recv (stream_id=2) accept-ranges: bytes
[ 0.019] recv (stream_id=2) server: nghttpx nghttp2/1.0.1-DEV
[ 0.019] recv (stream_id=2) via: 1.1 nghttpx
[ 0.019] recv HEADERS frame <length=36, flags=0x04, stream_id=2>
; END_HEADERS
(padlen=0)
; First push response header
[ 0.026] recv DATA frame <length=16384, flags=0x00, stream_id=2>
[ 0.027] recv DATA frame <length=7952, flags=0x00, stream_id=2>
[ 0.027] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=33343)
[ 0.032] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=2>
(window_size_increment=33707)
[ 0.032] recv DATA frame <length=14645, flags=0x01, stream_id=2>
; END_STREAM
[ 0.032] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.038] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
[ 0.032] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])
Using the ``-s`` option, ``nghttp`` prints out some timing information for
requests, sorted by completion time::
@@ -369,24 +505,26 @@ requests, sorted by completion time::
***** Statistics *****
Request timing:
complete: relative time from protocol handshake to stream close
request: relative time from protocol handshake to request
transmission. If '*' is shown, this was pushed by server.
process: time for request and response
responseEnd: the time when last byte of response was received
relative to connectEnd
requestStart: the time just before first byte of request was sent
relative to connectEnd. If '*' is shown, this was
pushed by server.
process: responseEnd - requestStart
code: HTTP status code
size: number of bytes received as response body without
inflation.
URI: request URI
see http://www.w3.org/TR/resource-timing/#processing-model
sorted by 'complete'
complete request process code size request path
+11.07ms +120us 10.95ms 200 9K /
+16.77ms * +8.80ms 7.98ms 200 8K /stylesheets/screen.css
+27.00ms +11.16ms 15.84ms 200 3K /javascripts/octopress.js
+27.40ms +11.16ms 16.24ms 200 3K /javascripts/modernizr-2.0.js
+76.14ms +11.17ms 64.97ms 200 171K /images/posts/with-pri-blog.png
+88.52ms +11.17ms 77.36ms 200 174K /images/posts/without-pri-blog.png
id responseEnd requestStart process code size request path
13 +37.19ms +280us 36.91ms 200 2K /
2 +72.65ms * +36.38ms 36.26ms 200 8K /stylesheets/screen.css
17 +77.43ms +38.67ms 38.75ms 200 3K /javascripts/octopress.js
15 +78.12ms +38.66ms 39.46ms 200 3K /javascripts/modernizr-2.0.js
Using the ``-r`` option, ``nghttp`` writes more detailed timing data to
the given file in HAR format.
@@ -408,58 +546,65 @@ Just like ``nghttp``, it has a verbose output mode for framing
information. Here is sample output from ``nghttpd``::
$ nghttpd --no-tls -v 8080
IPv4: listen on port 8080
IPv6: listen on port 8080
[id=1] [ 15.921] send SETTINGS frame <length=10, flags=0x00, stream_id=0>
IPv4: listen 0.0.0.0:8080
IPv6: listen :::8080
[id=1] [ 1.521] send SETTINGS frame <length=6, flags=0x00, stream_id=0>
(niv=1)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[id=1] [ 1.521] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
[SETTINGS_COMPRESS_DATA(5):1]
[id=1] [ 15.921] recv SETTINGS frame <length=15, flags=0x00, stream_id=0>
(niv=3)
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
[SETTINGS_COMPRESS_DATA(5):1]
[id=1] [ 15.921] (stream_id=1, noind=0) :authority: localhost:8080
[id=1] [ 15.921] (stream_id=1, noind=0) :method: GET
[id=1] [ 15.921] (stream_id=1, noind=0) :path: /
[id=1] [ 15.921] (stream_id=1, noind=0) :scheme: http
[id=1] [ 15.921] (stream_id=1, noind=0) accept: */*
[id=1] [ 15.921] (stream_id=1, noind=0) accept-encoding: gzip, deflate
[id=1] [ 15.921] (stream_id=1, noind=0) user-agent: nghttp2/0.4.0-DEV
[id=1] [ 15.921] recv HEADERS frame <length=48, flags=0x05, stream_id=1>
; END_STREAM | END_HEADERS
(padlen=0)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[id=1] [ 1.521] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[id=1] [ 1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=3>
(dep_stream_id=0, weight=201, exclusive=0)
[id=1] [ 1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=5>
(dep_stream_id=0, weight=101, exclusive=0)
[id=1] [ 1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=7>
(dep_stream_id=0, weight=1, exclusive=0)
[id=1] [ 1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=9>
(dep_stream_id=7, weight=1, exclusive=0)
[id=1] [ 1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=11>
(dep_stream_id=3, weight=1, exclusive=0)
[id=1] [ 1.521] recv (stream_id=13) :method: GET
[id=1] [ 1.521] recv (stream_id=13) :path: /
[id=1] [ 1.521] recv (stream_id=13) :scheme: http
[id=1] [ 1.521] recv (stream_id=13) :authority: localhost:8080
[id=1] [ 1.521] recv (stream_id=13) accept: */*
[id=1] [ 1.521] recv (stream_id=13) accept-encoding: gzip, deflate
[id=1] [ 1.521] recv (stream_id=13) user-agent: nghttp2/1.0.0-DEV
[id=1] [ 1.521] recv HEADERS frame <length=41, flags=0x25, stream_id=13>
; END_STREAM | END_HEADERS | PRIORITY
(padlen=0, dep_stream_id=11, weight=16, exclusive=0)
; Open new stream
[id=1] [ 15.921] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
[id=1] [ 1.521] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[id=1] [ 15.921] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[id=1] [ 15.921] send HEADERS frame <length=82, flags=0x04, stream_id=1>
[id=1] [ 1.521] send HEADERS frame <length=86, flags=0x04, stream_id=13>
; END_HEADERS
(padlen=0)
; First response header
:status: 200
server: nghttpd nghttp2/1.0.0-DEV
content-length: 10
cache-control: max-age=3600
content-length: 612
date: Wed, 14 May 2014 15:19:03 GMT
last-modified: Sat, 08 Mar 2014 16:04:06 GMT
server: nghttpd nghttp2/0.4.0-DEV
[id=1] [ 15.922] send DATA frame <length=381, flags=0x20, stream_id=1>
; COMPRESSED
[id=1] [ 15.922] send DATA frame <length=0, flags=0x01, stream_id=1>
date: Fri, 15 May 2015 14:49:04 GMT
last-modified: Tue, 30 Sep 2014 12:40:52 GMT
[id=1] [ 1.522] send DATA frame <length=10, flags=0x01, stream_id=13>
; END_STREAM
[id=1] [ 15.922] stream_id=1 closed
[id=1] [ 15.922] recv GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
[id=1] [ 15.922] closed
[id=1] [ 1.522] stream_id=13 closed
[id=1] [ 1.522] recv GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=0, error_code=NO_ERROR(0x00), opaque_data(0)=[])
[id=1] [ 1.522] closed
nghttpx - proxy
+++++++++++++++
``nghttpx`` is a multi-threaded reverse proxy for ``h2-14``, SPDY and
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server push.
``nghttpx`` is a multi-threaded reverse proxy for HTTP/2, SPDY and
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server
push.
``nghttpx`` implements `important performance-oriented features
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
@@ -480,8 +625,8 @@ default mode HTTP/2, SPDY, HTTP/1.1 (TLS) HTTP/1.1 Reverse proxy
================== ============================ ============== =============
The interesting mode at the moment is the default mode. It works like
a reverse proxy and listens for ``h2-14``, SPDY and HTTP/1.1 and can
be deployed as a SSL/TLS terminator for existing web server.
a reverse proxy and listens for HTTP/2, SPDY and HTTP/1.1 and can be
deployed as a SSL/TLS terminator for existing web server.
The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
SSL/TLS in the frontend connection by default. To disable SSL/TLS,
@@ -490,7 +635,7 @@ disabled in the frontend and incoming HTTP/1.1 connections can be
upgraded to HTTP/2 through HTTP Upgrade.
The ``--http2-bridge``, ``--client`` and ``--client-proxy`` modes use
SSL/TLS in the backend connection by deafult. To disable SSL/TLS, use
SSL/TLS in the backend connection by default. To disable SSL/TLS, use
the ``--backend-no-tls`` option.
``nghttpx`` supports a configuration file. See the ``--conf`` option and
@@ -582,6 +727,7 @@ follows::
spawning thread #0: 100 concurrent clients, 100000 total requests
Protocol: TLSv1.2
Cipher: ECDHE-RSA-AES128-GCM-SHA256
Server Temp Key: ECDH P-256 256 bits
progress: 10% done
progress: 20% done
progress: 30% done
@@ -593,12 +739,14 @@ follows::
progress: 90% done
progress: 100% done
finished in 7.10s, 14092 req/s, 55.67MB/s
finished in 771.26ms, 129658 req/s, 4.71MB/s
requests: 100000 total, 100000 started, 100000 done, 100000 succeeded, 0 failed, 0 errored
status codes: 100000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 414200800 bytes total, 2723100 bytes headers, 409600000 bytes data
traffic: 3812300 bytes total, 1009900 bytes headers, 1000000 bytes data
min max mean sd +/- sd
time for request: 283.86ms 1.46s 659.70ms 150.87ms 84.68%
time for request: 25.12ms 124.55ms 51.07ms 15.36ms 84.87%
time for connect: 208.94ms 254.67ms 241.38ms 7.95ms 63.00%
time to 1st byte: 209.11ms 254.80ms 241.51ms 7.94ms 63.00%
The above example issued total 100,000 requests, using 100 concurrent
clients (in other words, 100 HTTP/2 sessions), and a maximum of 100 streams
@@ -785,7 +933,7 @@ max_deflate_size
The maximum header table size the encoder uses. This can be smaller
than ``max_size``. In this case, the encoder only uses up to first
``max_deflate_size`` buffer. Since the header table size is still
``max_size``, the encoder has to keep track of entries ouside the
``max_size``, the encoder has to keep track of entries outside the
``max_deflate_size`` but inside the ``max_size`` and make sure
that they are no longer referenced.

View File

@@ -25,29 +25,16 @@ 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], [0.7.13], [t-tujikawa@users.sourceforge.net])
AC_INIT([nghttp2], [1.0.2], [t-tujikawa@users.sourceforge.net])
AC_USE_SYSTEM_EXTENSIONS
LT_PREREQ([2.2.6])
LT_INIT()
dnl See versioning rule:
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 13)
AC_SUBST(LT_REVISION, 2)
AC_SUBST(LT_AGE, 8)
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"`
patch=`echo $PACKAGE_VERSION |cut -d. -f3 | cut -d- -f1 | sed -e "s/[^0-9]//g"`
PACKAGE_VERSION_NUM=`printf "0x%02x%02x%02x" "$major" "$minor" "$patch"`
AC_SUBST(PACKAGE_VERSION_NUM)
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
AC_CANONICAL_TARGET
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([subdir-objects])
# comment out for now since this requires automake 1.13 or higher and
# travis has older one.
@@ -55,8 +42,23 @@ AM_INIT_AUTOMAKE([subdir-objects])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
dnl See versioning rule:
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 14)
AC_SUBST(LT_REVISION, 2)
AC_SUBST(LT_AGE, 0)
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"`
patch=`echo $PACKAGE_VERSION |cut -d. -f3 | cut -d- -f1 | sed -e "s/[^0-9]//g"`
PACKAGE_VERSION_NUM=`printf "0x%02x%02x%02x" "$major" "$minor" "$patch"`
AC_SUBST(PACKAGE_VERSION_NUM)
dnl Checks for command-line options
AC_ARG_ENABLE([werror],
[AS_HELP_STRING([--enable-werror],
@@ -129,14 +131,17 @@ AC_ARG_VAR([CYTHON], [the Cython executable])
dnl Checks for programs
AC_PROG_CC
AC_PROG_CXX
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
AM_PROG_CC_C_O
AC_PROG_MKDIR_P
PKG_PROG_PKG_CONFIG([0.20])
AM_PATH_PYTHON([2.7],, [:])
if [test "x$request_python_bindings" != "xno"]; then
AM_PATH_PYTHON([2.7],, [:])
AX_PYTHON_DEVEL([>= '2.7'])
fi
@@ -226,20 +231,6 @@ TESTLDADD=
# Additional libraries required for programs under src directory.
APPLDFLAGS=
LIBS_OLD=$LIBS
# Search for dlsym function, which is used in tests. Linux needs -ldl,
# but netbsd does not need it.
AC_SEARCH_LIBS([dlsym], [dl])
TESTLDADD="$LIBS $TESTLDADD"
LIBS=$LIBS_OLD
LIBS_OLD=$LIBS
AC_SEARCH_LIBS([clock_gettime], [rt],
[AC_DEFINE([HAVE_CLOCK_GETTIME], [1],
[Define to 1 if you have the `clock_gettime`.])])
APPLDFLAGS="$LIBS $APPLDFLAGS"
LIBS=$LIBS_OLD
case "$host" in
*android*)
android_build=yes
@@ -253,16 +244,10 @@ case "$host" in
esac
# zlib
if test "x$android_build" = "xyes"; then
# Use zlib provided by NDK
APPLDFLAGS="-lz $APPLDFLAGS"
have_zlib=yes
else
PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.3], [have_zlib=yes], [have_zlib=no])
PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.3], [have_zlib=yes], [have_zlib=no])
if test "x${have_zlib}" = "xno"; then
if test "x${have_zlib}" = "xno"; then
AC_MSG_NOTICE($ZLIB_PKG_ERRORS)
fi
fi
# cunit
@@ -328,7 +313,7 @@ fi
# jansson (for src/nghttp, src/deflatehd and src/inflatehd)
PKG_CHECK_MODULES([JANSSON], [jansson >= 2.5],
[have_jansson=yes], [have_jansson=no])
if test "x${have_jansson}" == "xyes"; then
if test "x${have_jansson}" = "xyes"; then
AC_DEFINE([HAVE_JANSSON], [1],
[Define to 1 if you have `libjansson` library.])
else
@@ -358,9 +343,23 @@ if test "x${request_jemalloc}" != "xno"; then
AC_SEARCH_LIBS([malloc_stats_print], [jemalloc], [have_jemalloc=yes], [],
[$PTHREAD_LDFLAGS])
LIBS=$LIBS_OLD
if test "x${have_jemalloc}" = "xyes"; then
jemalloc_libs=${ac_cv_search_malloc_stats_print}
else
# On Darwin, malloc_stats_print is je_malloc_stats_print
AC_SEARCH_LIBS([je_malloc_stats_print], [jemalloc], [have_jemalloc=yes], [],
[$PTHREAD_LDFLAGS])
LIBS=$LIBS_OLD
if test "x${have_jemalloc}" = "xyes"; then
jemalloc_libs=${ac_cv_search_je_malloc_stats_print}
fi
fi
if test "x${have_jemalloc}" = "xyes" &&
test "x${ac_cv_search_malloc_stats_print}" != "xnone required"; then
JEMALLOC_LIBS=${ac_cv_search_malloc_stats_print}
test "x${jemalloc_libs}" != "xnone required"; then
JEMALLOC_LIBS=${jemalloc_libs}
AC_SUBST([JEMALLOC_LIBS])
fi
fi
@@ -465,6 +464,16 @@ fi
AM_CONDITIONAL([ENABLE_EXAMPLES], [ test "x${enable_examples}" = "xyes" ])
# third-party only be built if either enable_examples or enable_app is
# yes
enable_third_party=no
if test "x${enable_examples}" = "xyes" || test "x${enable_app}" = "xyes"; then
enable_third_party=yes
fi
AM_CONDITIONAL([ENABLE_THIRD_PARTY], [ test "x${enable_third_party}" = "xyes" ])
# Python bindings
enable_python_bindings=no
if test "x${request_python_bindings}" != "xno" &&
@@ -498,12 +507,19 @@ AM_CONDITIONAL([ENABLE_FAILMALLOC], [ test "x${enable_failmalloc}" = "xyes" ])
AC_HEADER_ASSERT
AC_CHECK_HEADERS([ \
arpa/inet.h \
fcntl.h \
inttypes.h \
limits.h \
netdb.h \
netinet/in.h \
pwd.h \
stddef.h \
stdint.h \
stdlib.h \
string.h \
sys/socket.h \
sys/time.h \
syslog.h \
time.h \
unistd.h \
])
@@ -515,8 +531,16 @@ AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AC_TYPE_INT8_T
AC_TYPE_INT16_T
AC_TYPE_INT32_T
AC_TYPE_INT64_T
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_UID_T
AC_CHECK_TYPES([ptrdiff_t])
AC_C_BIGENDIAN
AC_C_INLINE
AC_SYS_LARGEFILE
AC_CHECK_MEMBER([struct tm.tm_gmtoff], [have_struct_tm_tm_gmtoff=yes],
@@ -535,12 +559,34 @@ AC_CHECK_SIZEOF([int *])
if test "x$cross_compiling" != "xyes"; then
AC_FUNC_MALLOC
fi
AC_FUNC_CHOWN
AC_FUNC_ERROR_AT_LINE
AC_FUNC_FORK
# Don't check realloc, since LeakSanitizer detects memory leak during check
# AC_FUNC_REALLOC
AC_FUNC_STRERROR_R
AC_FUNC_STRNLEN
AC_CHECK_FUNCS([ \
_Exit \
accept4 \
dup2 \
getcwd \
getpwnam \
localtime_r \
memchr \
memmove \
memset \
socket \
sqrt \
strchr \
strdup \
strerror \
strndup \
strstr \
strtol \
strtoul \
timegm \
])
@@ -650,6 +696,7 @@ AC_CONFIG_FILES([
doc/asio_http2_client.h.rst
doc/contribute.rst
contrib/Makefile
script/Makefile
])
AC_OUTPUT
@@ -688,6 +735,7 @@ AC_MSG_NOTICE([summary of build options:
Spdylay: ${have_spdylay}
Jansson: ${have_jansson}
Jemalloc: ${have_jemalloc}
Zlib: ${have_zlib}
Boost CPPFLAGS: ${BOOST_CPPFLAGS}
Boost LDFLAGS: ${BOOST_LDFLAGS}
Boost::ASIO: ${BOOST_ASIO_LIB}
@@ -700,4 +748,5 @@ AC_MSG_NOTICE([summary of build options:
Examples: ${enable_examples}
Python bindings:${enable_python_bindings}
Threading: ${enable_threads}
Third-party: ${enable_third_party}
])

2
contrib/.gitignore vendored
View File

@@ -1 +1,3 @@
nghttpx-init
nghttpx.service
nghttpx-upstart.conf

View File

@@ -21,19 +21,24 @@
# 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 = nghttpx-init.in nghttpx-logrotate
configfiles = nghttpx-init nghttpx.service nghttpx-upstart.conf
EXTRA_DIST = $(configfiles:%=%.in) nghttpx-logrotate
edit = sed -e 's|@bindir[@]|$(bindir)|g'
nghttpx-init: Makefile
nghttpx-init: %: $(srcdir)/%.in
rm -f $@ $@.tmp
$(edit) $(srcdir)/$@.in > $@.tmp
$(edit) $< > $@.tmp
chmod +x $@.tmp
mv $@.tmp $@
nghttpx-init: $(srcdir)/nghttpx-init.in
nghttpx.service nghttpx-upstart.conf: %: $(srcdir)/%.in
$(edit) $< > $@
all-local: nghttpx-init
$(configfiles): Makefile
all-local: $(configfiles)
clean-local:
-rm -f nghttpx-init nghttpx-init.tmp
-rm -f nghttpx-init.tmp $(configfiles)

View File

@@ -1,18 +1,11 @@
/var/log/nghttpx/*.log {
weekly
missingok
rotate 52
missingok
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi \
endscript
postrotate
[ -s /run/nghttpx.pid ] && kill -USR1 `cat /run/nghttpx.pid`
killall -USR1 nghttpx 2> /dev/null || true
endscript
}

View File

@@ -0,0 +1,8 @@
# vim: ft=upstart:
description "HTTP/2 reverse proxy"
start on runlevel [2]
stop on runlevel [016]
exec @bindir@/nghttpx

View File

@@ -0,0 +1,10 @@
[Unit]
Description=HTTP/2 experimental proxy
After=network.target
[Service]
Type=simple
ExecStart=@bindir@/nghttpx --errorlog-syslog
[Install]
WantedBy=multi-user.target

View File

@@ -49,7 +49,7 @@ APIDOCS= \
nghttp2_option_set_no_auto_window_update.rst \
nghttp2_option_set_no_http_messaging.rst \
nghttp2_option_set_peer_max_concurrent_streams.rst \
nghttp2_option_set_recv_client_preface.rst \
nghttp2_option_set_no_recv_client_magic.rst \
nghttp2_pack_settings_payload.rst \
nghttp2_priority_spec_check_default.rst \
nghttp2_priority_spec_default_init.rst \
@@ -108,7 +108,6 @@ APIDOCS= \
nghttp2_session_want_read.rst \
nghttp2_session_want_write.rst \
nghttp2_strerror.rst \
nghttp2_submit_altsvc.rst \
nghttp2_submit_data.rst \
nghttp2_submit_goaway.rst \
nghttp2_submit_headers.rst \

View File

@@ -5,7 +5,7 @@ From https://github.com/ryan-roemer/sphinx-bootstrap-theme.
"""
import os
VERSION = (0, 1, 7)
VERSION = (0, 1, 8)
__version__ = ".".join(str(v) for v in VERSION)
__version_full__ = __version__

View File

@@ -6,6 +6,7 @@
{% endfor %}
<li>{{ title }}</li>
<li class="wy-breadcrumbs-aside">
{% if pagename != "search" %}
{% if display_github %}
<a href="https://{{ github_host|default("github.com") }}/{{ github_user }}/{{ github_repo }}/blob/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-github"> Edit on GitHub</a>
{% elif display_bitbucket %}
@@ -15,6 +16,7 @@
{% elif show_source and has_source and sourcename %}
<a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow"> View page source</a>
{% endif %}
{% endif %}
</li>
</ul>
<hr/>

View File

@@ -2,10 +2,10 @@
{% if next or prev %}
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
{% if next %}
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}">Next <span class="fa fa-arrow-circle-right"></span></a>
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
{% endif %}
{% if prev %}
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}"><span class="fa fa-arrow-circle-left"></span> Previous</a>
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
{% endif %}
</div>
{% endif %}

View File

@@ -107,7 +107,7 @@
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
{% block menu %}
{% set toctree = toctree(maxdepth=2, collapse=False, includehidden=True) %}
{% set toctree = toctree(maxdepth=4, collapse=False, includehidden=True) %}
{% if toctree %}
{{ toctree }}
{% else %}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,50 +1,113 @@
$( document ).ready(function() {
function toggleCurrent (elem) {
var parent_li = elem.closest('li');
parent_li.siblings('li.current').removeClass('current');
parent_li.siblings().find('li.current').removeClass('current');
parent_li.find('> ul li.current').removeClass('current');
parent_li.toggleClass('current');
}
$(document).ready(function() {
// Shift nav in mobile when clicking the menu.
$(document).on('click', "[data-toggle='wy-nav-top']", function() {
$("[data-toggle='wy-nav-shift']").toggleClass("shift");
$("[data-toggle='rst-versions']").toggleClass("shift");
});
// Close menu when you click a link.
// Nav menu link click operations
$(document).on('click', ".wy-menu-vertical .current ul li a", function() {
var target = $(this);
// Close menu when you click a link.
$("[data-toggle='wy-nav-shift']").removeClass("shift");
$("[data-toggle='rst-versions']").toggleClass("shift");
// Handle dynamic display of l3 and l4 nav lists
toggleCurrent(target);
if (typeof(window.SphinxRtdTheme) != 'undefined') {
window.SphinxRtdTheme.StickyNav.hashChange();
}
});
$(document).on('click', "[data-toggle='rst-current-version']", function() {
$("[data-toggle='rst-versions']").toggleClass("shift-up");
});
// Make tables responsive
$("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>");
// Add expand links to all parents of nested ul
$('.wy-menu-vertical ul').siblings('a').each(function () {
var link = $(this);
expand = $('<span class="toctree-expand"></span>');
expand.on('click', function (ev) {
toggleCurrent(link);
ev.stopPropagation();
return false;
});
link.prepend(expand);
});
});
// Sphinx theme state
window.SphinxRtdTheme = (function (jquery) {
var stickyNav = (function () {
var navBar,
win,
stickyNavCssClass = 'stickynav',
winScroll = false,
linkScroll = false,
winPosition = 0,
enable = function () {
navBar.addClass(stickyNavCssClass);
win.on('scroll', function() { // set flag on scroll event
init();
reset();
win.on('hashchange', reset);
// Set scrolling
win.on('scroll', function () {
if (!linkScroll) {
winScroll = true;
}
});
// use setInterval to only handle a subset of scroll events so we don't kill scroll performance
setInterval(function() {
setInterval(function () {
if (winScroll) {
winScroll = false;
navBar.scrollTop(win.scrollTop());
var newWinPosition = win.scrollTop(),
navPosition = navBar.scrollTop(),
newNavPosition = navPosition + (newWinPosition - winPosition);
navBar.scrollTop(newNavPosition);
winPosition = newWinPosition;
}
}, 100);
}, 25);
},
init = function () {
navBar = jquery('nav.wy-nav-side:first');
win = jquery(window);
},
reset = function () {
// Get anchor from URL and open up nested nav
var anchor = encodeURI(window.location.hash);
if (anchor) {
try {
var link = $('.wy-menu-vertical')
.find('[href="' + anchor + '"]');
$('.wy-menu-vertical li.toctree-l1 li.current')
.removeClass('current');
link.closest('li.toctree-l2').addClass('current');
link.closest('li.toctree-l3').addClass('current');
link.closest('li.toctree-l4').addClass('current');
}
catch (err) {
console.log("Error expanding nav for anchor", err);
}
}
},
hashChange = function () {
linkScroll = true;
win.one('hashchange', function () {
linkScroll = false;
});
};
jquery(init);
return {
enable : enable
enable: enable,
hashChange: hashChange
};
}());
return {
StickyNav : stickyNav
StickyNav: stickyNav
};
}($));

View File

@@ -1,7 +1,10 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import print_function
import subprocess
from StringIO import StringIO
import io
import re
import sys
import os.path
@@ -14,10 +17,10 @@ class Option:
def get_all_options(cmd):
opt_pattern = re.compile(r' (?:(-.), )?(--[^\s\[=]+)(\[)?')
proc = subprocess.Popen([cmd, "--help"], stdout=subprocess.PIPE)
stdoutdata, stderrdata = proc.communicate()
stdoutdata, _ = proc.communicate()
cur_option = None
opts = {}
for line in StringIO(stdoutdata):
for line in io.StringIO(stdoutdata.decode('utf-8')):
match = opt_pattern.match(line)
if not match:
continue
@@ -45,7 +48,7 @@ _{name}()
-*)
COMPREPLY=( $( compgen -W '\
''')
for opt in opts.itervalues():
for opt in opts.values():
out.write(opt.long_opt)
out.write(' ')
@@ -66,8 +69,8 @@ complete -F _{name} {name}
if __name__ == '__main__':
if len(sys.argv) < 2:
print "Generates bash_completion using `/path/to/cmd --help'"
print "Usage: make_bash_completion.py /path/to/cmd"
print("Generates bash_completion using `/path/to/cmd --help'")
print("Usage: make_bash_completion.py /path/to/cmd")
exit(1)
name = os.path.basename(sys.argv[1])
opts = get_all_options(sys.argv[1])

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "H2LOAD" "1" "April 27, 2015" "0.7.13" "nghttp2"
.TH "H2LOAD" "1" "June 12, 2015" "1.0.2" "nghttp2"
.SH NAME
h2load \- HTTP/2 benchmarking tool
.
@@ -71,7 +71,7 @@ Default: \fB1\fP
.INDENT 0.0
.TP
.B \-i, \-\-input\-file=<FILE>
Path of a file with multiple URIs are seperated by EOLs.
Path of a file with multiple URIs are separated by EOLs.
This option will disable URIs getting from command\-line.
If \(aq\-\(aq is given as <FILE>, URIs will be read from stdin.
URIs are used in this order for each client. All URIs
@@ -116,9 +116,9 @@ Add/Override a header to the requests.
.B \-p, \-\-no\-tls\-proto=<PROTOID>
Specify ALPN identifier of the protocol to be used when
accessing http URI without SSL/TLS.
Available protocols: spdy/2, spdy/3, spdy/3.1 and h2c\-14
Available protocols: spdy/2, spdy/3, spdy/3.1 and h2c
.sp
Default: \fBh2c\-14\fP
Default: \fBh2c\fP
.UNINDENT
.INDENT 0.0
.TP
@@ -205,12 +205,55 @@ The maximum time taken for request and response.
The mean time taken for request and response.
.TP
.B sd
The standard deviation of the time for request and response.
The standard deviation of the time taken for request and response.
.TP
.B +/\- sd
The fraction of the number of requests within standard deviation
range (mean +/\- sd) against total number of successful requests.
.UNINDENT
.TP
.B time for connect
.INDENT 7.0
.TP
.B min
The minimum time taken to connect to a server.
.TP
.B max
The maximum time taken to connect to a server.
.TP
.B mean
The mean time taken to connect to a server.
.TP
.B sd
The standard deviation of the time taken to connect to a server.
.TP
.B +/\- sd
The fraction of the number of connections within standard
deviation range (mean +/\- sd) against total number of successful
connections.
.UNINDENT
.TP
.B time for 1st byte (of (decrypted in case of TLS) application data)
.INDENT 7.0
.TP
.B min
The minimum time taken to get 1st byte from a server.
.TP
.B max
The maximum time taken to get 1st byte from a server.
.TP
.B mean
The mean time taken to get 1st byte from a server.
.TP
.B sd
The standard deviation of the time taken to get 1st byte from a
server.
.TP
.B +/\- sd
The fraction of the number of connections within standard
deviation range (mean +/\- sd) against total number of successful
connections.
.UNINDENT
.UNINDENT
.SH FLOW CONTROL
.sp

View File

@@ -1,4 +1,6 @@
.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
.. program:: h2load
h2load(1)
@@ -46,7 +48,7 @@ OPTIONS
.. option:: -i, --input-file=<FILE>
Path of a file with multiple URIs are seperated by EOLs.
Path of a file with multiple URIs are separated by EOLs.
This option will disable URIs getting from command-line.
If '-' is given as <FILE>, URIs will be read from stdin.
URIs are used in this order for each client. All URIs
@@ -86,9 +88,9 @@ OPTIONS
Specify ALPN identifier of the protocol to be used when
accessing http URI without SSL/TLS.
Available protocols: spdy/2, spdy/3, spdy/3.1 and h2c-14
Available protocols: spdy/2, spdy/3, spdy/3.1 and h2c
Default: ``h2c-14``
Default: ``h2c``
.. option:: -d, --data=<FILE>
@@ -153,11 +155,40 @@ time for request
mean
The mean time taken for request and response.
sd
The standard deviation of the time for request and response.
The standard deviation of the time taken for request and response.
+/- sd
The fraction of the number of requests within standard deviation
range (mean +/- sd) against total number of successful requests.
time for connect
min
The minimum time taken to connect to a server.
max
The maximum time taken to connect to a server.
mean
The mean time taken to connect to a server.
sd
The standard deviation of the time taken to connect to a server.
+/- sd
The fraction of the number of connections within standard
deviation range (mean +/- sd) against total number of successful
connections.
time for 1st byte (of (decrypted in case of TLS) application data)
min
The minimum time taken to get 1st byte from a server.
max
The maximum time taken to get 1st byte from a server.
mean
The mean time taken to get 1st byte from a server.
sd
The standard deviation of the time taken to get 1st byte from a
server.
+/- sd
The fraction of the number of connections within standard
deviation range (mean +/- sd) against total number of successful
connections.
FLOW CONTROL
------------

View File

@@ -44,11 +44,40 @@ time for request
mean
The mean time taken for request and response.
sd
The standard deviation of the time for request and response.
The standard deviation of the time taken for request and response.
+/- sd
The fraction of the number of requests within standard deviation
range (mean +/- sd) against total number of successful requests.
time for connect
min
The minimum time taken to connect to a server.
max
The maximum time taken to connect to a server.
mean
The mean time taken to connect to a server.
sd
The standard deviation of the time taken to connect to a server.
+/- sd
The fraction of the number of connections within standard
deviation range (mean +/- sd) against total number of successful
connections.
time for 1st byte (of (decrypted in case of TLS) application data)
min
The minimum time taken to get 1st byte from a server.
max
The maximum time taken to get 1st byte from a server.
mean
The mean time taken to get 1st byte from a server.
sd
The standard deviation of the time taken to get 1st byte from a
server.
+/- sd
The fraction of the number of connections within standard
deviation range (mean +/- sd) against total number of successful
connections.
FLOW CONTROL
------------

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2012 Tatsuhiro Tsujikawa
@@ -23,6 +24,8 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Generates API reference from C source code.
from __future__ import unicode_literals
from __future__ import print_function # At least python 2.6 is required
import re, sys, argparse, os.path
@@ -222,6 +225,7 @@ def process_function(domain, infile):
func_proto = ''.join(func_proto)
func_proto = re.sub(r';\n$', '', func_proto)
func_proto = re.sub(r'\s+', ' ', func_proto)
func_proto = re.sub(r'NGHTTP2_EXTERN ', '', func_proto)
return FunctionDoc(func_proto, content, domain)
def read_content(infile):

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTP" "1" "April 27, 2015" "0.7.13" "nghttp2"
.TH "NGHTTP" "1" "June 12, 2015" "1.0.2" "nghttp2"
.SH NAME
nghttp \- HTTP/2 experimental client
.
@@ -64,8 +64,9 @@ yet.
.UNINDENT
.INDENT 0.0
.TP
.B \-t, \-\-timeout=<SEC>
Timeout each request after <SEC> seconds.
.B \-t, \-\-timeout=<DURATION>
Timeout each request after <DURATION>. Set 0 to disable
timeout.
.UNINDENT
.INDENT 0.0
.TP
@@ -215,6 +216,11 @@ Display this help and exit.
.sp
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).
.sp
The <DURATION> argument is an integer and an optional unit (e.g., 1s
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit.
.SH DEPENDENCY BASED PRIORITY
.sp
nghttp sends priority hints to server by default unless

View File

@@ -1,4 +1,6 @@
.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
.. program:: nghttp
nghttp(1)
@@ -38,9 +40,10 @@ OPTIONS
'index.html' is used as a filename. Not implemented
yet.
.. option:: -t, --timeout=<SEC>
.. option:: -t, --timeout=<DURATION>
Timeout each request after <SEC> seconds.
Timeout each request after <DURATION>. Set 0 to disable
timeout.
.. option:: -w, --window-bits=<N>
@@ -168,6 +171,11 @@ OPTIONS
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).
The <DURATION> argument is an integer and an optional unit (e.g., 1s
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit.
DEPENDENCY BASED PRIORITY
-------------------------

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPD" "1" "April 27, 2015" "0.7.13" "nghttp2"
.TH "NGHTTPD" "1" "June 12, 2015" "1.0.2" "nghttp2"
.SH NAME
nghttpd \- HTTP/2 experimental server
.
@@ -119,6 +119,14 @@ Specify 0 to disable padding.
.UNINDENT
.INDENT 0.0
.TP
.B \-m, \-\-max\-concurrent\-streams=<N>
Set the maximum number of the concurrent streams in one
HTTP/2 session.
.sp
Default: \fB100\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-n, \-\-workers=<N>
Set the number of worker threads.
.sp
@@ -159,6 +167,11 @@ are used.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-echo\-upload
Send back uploaded content if method is POST or PUT.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-version
Display version information and exit.
.UNINDENT

View File

@@ -1,4 +1,6 @@
.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
.. program:: nghttpd
nghttpd(1)
@@ -85,6 +87,13 @@ OPTIONS
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
.. option:: -m, --max-concurrent-streams=<N>
Set the maximum number of the concurrent streams in one
HTTP/2 session.
Default: ``100``
.. option:: -n, --workers=<N>
Set the number of worker threads.
@@ -119,6 +128,10 @@ OPTIONS
hex+ASCII display). If SSL/TLS is used, decrypted data
are used.
.. option:: --echo-upload
Send back uploaded content if method is POST or PUT.
.. option:: --version
Display version information and exit.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPX" "1" "April 27, 2015" "0.7.13" "nghttp2"
.TH "NGHTTPX" "1" "June 12, 2015" "1.0.2" "nghttp2"
.SH NAME
nghttpx \- HTTP/2 experimental proxy
.
@@ -690,10 +690,19 @@ will not be altered regardless of this option.
.B \-\-altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
Specify protocol ID, port, host and origin of
alternative service. <HOST> and <ORIGIN> are optional.
They are advertised in alt\-svc header field or HTTP/2
ALTSVC frame. This option can be used multiple times to
specify multiple alternative services. Example:
\fI\%\-\-altsvc\fP=h2,443
They are advertised in alt\-svc header field only in
HTTP/1.1 frontend. This option can be used multiple
times to specify multiple alternative services.
Example: \fI\%\-\-altsvc\fP=h2,443
.UNINDENT
.INDENT 0.0
.TP
.B \-\-add\-request\-header=<HEADER>
Specify additional header field to add to request header
set. This option just appends header field and won\(aqt
replace anything already set. This option can be used
several times to specify multiple header fields.
Example: \fI\%\-\-add\-request\-header\fP="foo: bar"
.UNINDENT
.INDENT 0.0
.TP
@@ -704,6 +713,23 @@ won\(aqt replace anything already set. This option can be
used several times to specify multiple header fields.
Example: \fI\%\-\-add\-response\-header\fP="foo: bar"
.UNINDENT
.INDENT 0.0
.TP
.B \-\-header\-field\-buffer=<SIZE>
Set maximum buffer size for incoming HTTP header field
list. This is the sum of header name and value in
bytes.
.sp
Default: \fB64K\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-max\-header\-fields=<N>
Set maximum number of incoming HTTP header fields, which
appear in one request or response header field list.
.sp
Default: \fB100\fP
.UNINDENT
.SS Debug
.INDENT 0.0
.TP
@@ -795,7 +821,7 @@ argument in the configuration file. Specify \fByes\fP as an argument
ignored.
.sp
To specify private key and certificate file which are given as
positional arguments in commnad\-line, use \fBprivate\-key\-file\fP and
positional arguments in command\-line, use \fBprivate\-key\-file\fP and
\fBcertificate\-file\fP\&.
.sp
\fI\%\-\-conf\fP option cannot be used in the configuration file and

View File

@@ -1,4 +1,6 @@
.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
.. program:: nghttpx
nghttpx(1)
@@ -606,10 +608,18 @@ HTTP
Specify protocol ID, port, host and origin of
alternative service. <HOST> and <ORIGIN> are optional.
They are advertised in alt-svc header field or HTTP/2
ALTSVC frame. This option can be used multiple times to
specify multiple alternative services. Example:
:option:`--altsvc`\=h2,443
They are advertised in alt-svc header field only in
HTTP/1.1 frontend. This option can be used multiple
times to specify multiple alternative services.
Example: :option:`--altsvc`\=h2,443
.. option:: --add-request-header=<HEADER>
Specify additional header field to add to request header
set. This option just appends header field and won't
replace anything already set. This option can be used
several times to specify multiple header fields.
Example: :option:`--add-request-header`\="foo: bar"
.. option:: --add-response-header=<HEADER>
@@ -619,6 +629,21 @@ HTTP
used several times to specify multiple header fields.
Example: :option:`--add-response-header`\="foo: bar"
.. option:: --header-field-buffer=<SIZE>
Set maximum buffer size for incoming HTTP header field
list. This is the sum of header name and value in
bytes.
Default: ``64K``
.. option:: --max-header-fields=<N>
Set maximum number of incoming HTTP header fields, which
appear in one request or response header field list.
Default: ``100``
Debug
~~~~~
@@ -712,7 +737,7 @@ FILES
ignored.
To specify private key and certificate file which are given as
positional arguments in commnad-line, use ``private-key-file`` and
positional arguments in command-line, use ``private-key-file`` and
``certificate-file``.
:option:`--conf` option cannot be used in the configuration file and

View File

@@ -19,7 +19,7 @@ FILES
ignored.
To specify private key and certificate file which are given as
positional arguments in commnad-line, use ``private-key-file`` and
positional arguments in command-line, use ``private-key-file`` and
``certificate-file``.
:option:`--conf` option cannot be used in the configuration file and

View File

@@ -20,17 +20,15 @@ nghttp2 callback functions directly or indirectly. It will lead to the
crash. You can submit requests or frames in the callbacks then call
these functions outside the callbacks.
Currently, `nghttp2_session_send()` and `nghttp2_session_mem_send()`
do not send client connection preface
(:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`). The applications are
responsible to send it before sending any HTTP/2 frames using these
functions if :type:`nghttp2_session` is configured as client.
Similarly, `nghttp2_session_recv()` and `nghttp2_session_mem_recv()`
do not consume client connection preface unless
`nghttp2_option_set_recv_client_preface()` is used with nonzero option
value. The applications are responsible to receive it before calling
these functions if :type:`nghttp2_session` is configured as server and
`nghttp2_option_set_recv_client_preface()` is not used.
`nghttp2_session_send()` and `nghttp2_session_mem_send()` send first
24 bytes of client magic string (MAGIC)
(:macro:`NGHTTP2_CLIENT_MAGIC`) on client configuration. The
applications are responsible to send SETTINGS frame as part of
connection preface using `nghttp2_submit_settings()`. Similarly,
`nghttp2_session_recv()` and `nghttp2_session_mem_recv()` consume
MAGIC on server configuration unless
`nghttp2_option_set_no_recv_client_magic()` is used with nonzero
option value.
.. _http-messaging:

View File

@@ -36,8 +36,9 @@ with the toolchain and installed under ``$ANDROID_HOME/usr/local``.
We recommend to build these libraries as static library to make the
deployment easier. libxml2 support is currently disabled.
We use zlib which comes with Android NDK, so we don't have to build it
by ourselves.
Although zlib comes with Android NDK, it seems not to be a part of
public API, so we have to built it for our own. That also provides us
proper .pc file as a bonus.
If SPDY support is required for nghttpx and h2load, build and install
spdylay as well.
@@ -95,10 +96,41 @@ patch, to configure libev, use the following script:
And run ``make install`` to build and install.
To configure zlib, use the following script:
.. code-block:: sh
#!/bin/sh -e
if [ -z "$ANDROID_HOME" ]; then
echo 'No $ANDROID_HOME specified.'
exit 1
fi
PREFIX=$ANDROID_HOME/usr/local
TOOLCHAIN=$ANDROID_HOME/toolchain
PATH=$TOOLCHAIN/bin:$PATH
HOST=arm-linux-androideabi
CC=$HOST-gcc \
AR=$HOST-ar \
LD=$HOST-ld \
RANLIB=$HOST-ranlib \
STRIP=$HOST-strip \
./configure \
--prefix=$PREFIX \
--libdir=$PREFIX/lib \
--includedir=$PREFIX/include \
--static
And run ``make install`` to build and install.
To configure spdylay, use the following script:
.. code-block:: sh
#!/bin/sh -e
if [ -z "$ANDROID_HOME" ]; then
echo 'No $ANDROID_HOME specified.'
exit 1
@@ -119,11 +151,7 @@ To configure spdylay, use the following script:
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-L$PREFIX/lib"
And run ``make install`` to build and install. After spdylay
installation, edit $ANDROID_HOME/usr/local/lib/pkgconfig/libspdylay.pc
and remove the following line::
Requires.private: zlib
And run ``make install`` to build and install.
After prerequisite libraries are prepared, run ``android-config`` and
then ``android-make`` to compile nghttp2 source files.

View File

@@ -87,5 +87,5 @@ If multiple URIs are specified, they are used in round robin manner.
.. note::
Please note that h2load uses sheme, host and port in the first URI
Please note that h2load uses scheme, host and port in the first URI
and ignores those parts in the rest of the URIs.

View File

@@ -49,5 +49,5 @@ https://github.com/tatsuhiro-t/nghttp2/releases
Resources
---------
* http://tools.ietf.org/html/draft-ietf-httpbis-http2-14
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09
* HTTP/2 https://tools.ietf.org/html/rfc7540
* HPACK https://tools.ietf.org/html/rfc7541

View File

@@ -80,7 +80,7 @@ status code, in the above example, which is 200. The second argument,
which is omitted in the above example, is additional header fields to
send.
``nghttp2::asio_http2::server::response::end`` sends responde body.
``nghttp2::asio_http2::server::response::end`` sends response body.
In the above example, we send string "hello, world".
The life time of req and res object ends after the callback set by
@@ -277,7 +277,7 @@ response header fields and response body to the console screen:
``boost::asio::io_service`` object and remote server address. When
connection is made, the callback function passed to
``nghttp2::asio_http2::client::on_connect`` is invoked with connected
address as its paramter. After this callback call, use
address as its parameter. After this callback call, use
``nghttp2::asio_http2::session::submit`` to send request to the
server. You can submit multiple requests at once without waiting for
the completion of previous request.

View File

@@ -21,7 +21,7 @@ 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
fontend protocol selection will is done via ALPN or NPN.
frontend protocol selection will is done via ALPN or NPN.
With ``--frontend-no-tls`` option, user can turn off SSL/TLS in
frontend connection. In this case, SPDY protocol is not available
@@ -243,7 +243,7 @@ Read/write rate limit
---------------------
nghttpx supports transfer rate limiting on frontend connections. You
can do rate limit per frontend connection for reading and writeing
can do rate limit per frontend connection for reading and writing
individually.
To perform rate limit for reading, use ``--read-rate`` and

View File

@@ -267,7 +267,7 @@ HTTP/2 servers
(byte string could be ``None``), :py:data:`DATA_EOF` must be
returned as flag. If there is no data available right now, but
additional data are anticipated, return tuple (``None``,
:py:data:`DATA_DEFERRD`). When data arrived, call
:py:data:`DATA_DEFERRED`). When data arrived, call
:py:meth:`resume()` and restart response body transmission.
Only the body generator can pause response body generation;

View File

@@ -65,11 +65,11 @@ its stream specific data in ``http2_stream_data`` structure and the
defined as follows::
typedef struct {
/* The NULL-terminated URI string to retreive. */
/* The NULL-terminated URI string to retrieve. */
const char *uri;
/* Parsed result of the |uri| */
struct http_parser_url *u;
/* The authroity portion of the |uri|, not NULL-terminated */
/* The authority portion of the |uri|, not NULL-terminated */
char *authority;
/* The path portion of the |uri|, including query, not
NULL-terminated */
@@ -184,9 +184,9 @@ its bufferevent, so it closes underlying connection as well. It also
calls `nghttp2_session_del()` to delete nghttp2 session object.
We begin HTTP/2 communication by sending client connection preface,
which is 24 bytes magic byte sequence
(:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`) and SETTINGS frame. The
transmission of client connection header is done in
which is 24 bytes magic byte string (:macro:`NGHTTP2_CLIENT_MAGIC`)
followed by SETTINGS frame. First 24 bytes magic string is
automatically sent by nghttp2 library. We send SETTINGS frame in
``send_client_connection_header()``::
static void send_client_connection_header(http2_session_data *session_data) {
@@ -194,8 +194,7 @@ transmission of client connection header is done in
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
bufferevent_write(session_data->bev, NGHTTP2_CLIENT_CONNECTION_PREFACE,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
/* client 24 bytes magic string will be sent by nghttp2 library */
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv));
if (rv != 0) {
@@ -204,7 +203,7 @@ transmission of client connection header is done in
}
Here we specify SETTINGS_MAX_CONCURRENT_STREAMS to 100, which is
really not needed for this tiny example progoram, but we are
really not needed for this tiny example program, but we are
demonstrating the use of SETTINGS frame. To queue the SETTINGS frame
for the transmission, we use `nghttp2_submit_settings()`. Note that
`nghttp2_submit_settings()` function only queues the frame and not
@@ -388,7 +387,7 @@ After all name/value pairs are emitted for a frame,
}
In this tutorial, we are just interested in the HTTP response
HEADERS. We check te frame type and its category (it should be
HEADERS. We check the frame type and its category (it should be
:macro:`NGHTTP2_HCAT_RESPONSE` for HTTP response HEADERS). Also check
its stream ID.
@@ -407,7 +406,7 @@ of data is received from the remote peer::
}
In our case, a chunk of data is response body. After checking stream
ID, we just write the recieved data to the stdout. Note that the
ID, we just write the received data to the stdout. Note that the
output in the terminal may be corrupted if the response body contains
some binary data.

View File

@@ -51,7 +51,7 @@ bound of encoded result, use `nghttp2_hd_deflate_bound()` function::
size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
const nghttp2_nv *nva, size_t nvlen);
Pass this function with the same paramters *deflater*, *nva* and
Pass this function with the same parameters *deflater*, *nva* and
*nvlen* which will be passed to `nghttp2_hd_deflate_hd()`.
The subsequent call of `nghttp2_hd_deflate_hd()` will use current

View File

@@ -194,15 +194,8 @@ We initialize a nghttp2 session object which is done in
``initialize_nghttp2_session()``::
static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_option *option;
nghttp2_session_callbacks *callbacks;
nghttp2_option_new(&option);
/* Tells nghttp2_session object that it handles client connection
preface */
nghttp2_option_set_recv_client_preface(option, 1);
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
@@ -219,20 +212,15 @@ We initialize a nghttp2 session object which is done in
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
nghttp2_session_server_new2(&session_data->session, callbacks, session_data,
option);
nghttp2_session_server_new(&session_data->session, callbacks, session_data);
nghttp2_session_callbacks_del(callbacks);
nghttp2_option_del(option);
}
Since we are creating a server and uses options, the nghttp2 session
object is created using `nghttp2_session_server_new2()` function. We
registers five callbacks for nghttp2 session object. We'll talk about
these callbacks later. Our server only speaks HTTP/2. In this case,
we use `nghttp2_option_set_recv_client_preface()` to make
:type:`nghttp2_session` object handle client connection preface, which
saves some lines of application code.
these callbacks later.
After initialization of the nghttp2 session object, we are going to send
a server connection header in ``send_server_connection_header()``::

View File

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

View File

@@ -28,16 +28,26 @@
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* !HAVE_CONFIG_H */
#endif /* HAVE_CONFIG_H */
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif /* HAVE_NETDB_H */
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h>
#include <poll.h>
#include <signal.h>
@@ -528,14 +538,6 @@ static void fetch_uri(const struct URI *uri) {
connection.ssl = ssl;
connection.want_io = IO_NONE;
/* Send connection header in blocking I/O mode */
rv = SSL_write(ssl, NGHTTP2_CLIENT_CONNECTION_PREFACE,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
if (rv <= 0) {
dief("SSL_write failed: could not send connection preface",
ERR_error_string(ERR_get_error(), NULL));
}
/* Here make file descriptor non-block */
make_non_block(fd);
set_tcp_nodelay(fd);
@@ -687,10 +689,10 @@ int main(int argc, char **argv) {
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, 0);
OPENSSL_config(NULL);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
rv = parse_uri(&uri, argv[1]);
if (rv != 0) {

View File

@@ -24,12 +24,18 @@
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* !HAVE_CONFIG_H */
#endif /* HAVE_CONFIG_H */
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h>
#include <err.h>
#include <signal.h>
@@ -50,11 +56,11 @@
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
typedef struct {
/* The NULL-terminated URI string to retreive. */
/* The NULL-terminated URI string to retrieve. */
const char *uri;
/* Parsed result of the |uri| */
struct http_parser_url *u;
/* The authroity portion of the |uri|, not NULL-terminated */
/* The authority portion of the |uri|, not NULL-terminated */
char *authority;
/* The path portion of the |uri|, including query, not
NULL-terminated */
@@ -94,7 +100,8 @@ static http2_stream_data *create_http2_stream_data(const char *uri,
":%u", u->port);
}
stream_data->pathlen = 0;
/* If we don't have path in URI, we use "/" as path. */
stream_data->pathlen = 1;
if (u->field_set & (1 << UF_PATH)) {
stream_data->pathlen = u->field_data[UF_PATH].len;
}
@@ -102,19 +109,22 @@ static http2_stream_data *create_http2_stream_data(const char *uri,
/* +1 for '?' character */
stream_data->pathlen += u->field_data[UF_QUERY].len + 1;
}
if (stream_data->pathlen > 0) {
stream_data->path = malloc(stream_data->pathlen);
if (u->field_set & (1 << UF_PATH)) {
memcpy(stream_data->path, &uri[u->field_data[UF_PATH].off],
u->field_data[UF_PATH].len);
} else {
stream_data->path[0] = '/';
}
if (u->field_set & (1 << UF_QUERY)) {
memcpy(stream_data->path + u->field_data[UF_PATH].len + 1,
stream_data->path[stream_data->pathlen - u->field_data[UF_QUERY].len - 1] =
'?';
memcpy(stream_data->path + stream_data->pathlen -
u->field_data[UF_QUERY].len,
&uri[u->field_data[UF_QUERY].off], u->field_data[UF_QUERY].len);
}
} else {
stream_data->path = NULL;
}
return stream_data;
}
@@ -344,8 +354,7 @@ static void send_client_connection_header(http2_session_data *session_data) {
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
bufferevent_write(session_data->bev, NGHTTP2_CLIENT_CONNECTION_PREFACE,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
/* client 24 bytes magic string will be sent by nghttp2 library */
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv));
if (rv != 0) {
@@ -546,10 +555,10 @@ int main(int argc, char **argv) {
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, NULL);
OPENSSL_config(NULL);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
run(argv[1]);
return 0;

View File

@@ -24,17 +24,27 @@
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* !HAVE_CONFIG_H */
#endif /* HAVE_CONFIG_H */
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif /* HAVE_NETDB_H */
#include <signal.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <sys/stat.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#include <ctype.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h>
#include <err.h>
@@ -537,15 +547,8 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
}
static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_option *option;
nghttp2_session_callbacks *callbacks;
nghttp2_option_new(&option);
/* Tells nghttp2_session object that it handles client connection
preface */
nghttp2_option_set_recv_client_preface(option, 1);
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
@@ -562,11 +565,9 @@ static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
nghttp2_session_server_new2(&session_data->session, callbacks, session_data,
option);
nghttp2_session_server_new(&session_data->session, callbacks, session_data);
nghttp2_session_callbacks_del(callbacks);
nghttp2_option_del(option);
}
/* Send HTTP/2 client connection header, which includes 24 bytes
@@ -723,10 +724,10 @@ int main(int argc, char **argv) {
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, NULL);
OPENSSL_config(NULL);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
run(argv[1], argv[2], argv[3]);
return 0;

View File

@@ -30,18 +30,30 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* !HAVE_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/stat.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif /* HAVE_NETDB_H */
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <stdlib.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif /* HAVE_TIME_H */
#include <string.h>
#include <stdio.h>
#include <errno.h>
@@ -153,7 +165,6 @@ const char *docroot;
size_t docrootlen;
nghttp2_session_callbacks *shared_callbacks;
nghttp2_option *shared_option;
static int handle_accept(io_loop *loop, uint32_t events, void *ptr);
static int handle_connection(io_loop *loop, uint32_t events, void *ptr);
@@ -190,7 +201,7 @@ typedef enum {
NGHTTP2_TOKEN__METHOD,
NGHTTP2_TOKEN__PATH,
NGHTTP2_TOKEN__SCHEME,
NGHTTP2_TOKEN_HOST,
NGHTTP2_TOKEN_HOST
} nghttp2_token;
/* Inspired by h2o header lookup. https://github.com/h2o/h2o */
@@ -388,8 +399,7 @@ static connection *connection_new(int fd) {
conn = malloc(sizeof(connection));
rv = nghttp2_session_server_new2(&conn->session, shared_callbacks, conn,
shared_option);
rv = nghttp2_session_server_new(&conn->session, shared_callbacks, conn);
if (rv != 0) {
goto cleanup;
@@ -1310,14 +1320,6 @@ int main(int argc, char **argv) {
nghttp2_session_callbacks_set_send_data_callback(shared_callbacks,
send_data_callback);
rv = nghttp2_option_new(&shared_option);
if (rv != 0) {
fprintf(stderr, "nghttp2_option_new: %s", nghttp2_strerror(rv));
exit(EXIT_FAILURE);
}
nghttp2_option_set_recv_client_preface(shared_option, 1);
rv = io_loop_add(&loop, serv.fd, EPOLLIN, &serv);
if (rv != 0) {
@@ -1334,7 +1336,6 @@ int main(int argc, char **argv) {
io_loop_run(&loop, &serv);
nghttp2_option_del(shared_option);
nghttp2_session_callbacks_del(shared_callbacks);
return 0;

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env python
from gentokenlookup import gentokenlookup
HEADERS = [
':authority',
':method',
@@ -34,70 +36,5 @@ HEADERS = [
'upgrade'
]
def to_enum_hd(k):
res = 'HD_'
for c in k.upper():
if c == ':' or c == '-':
res += '_'
continue
res += c
return res
def build_header(headers):
res = {}
for k in headers:
size = len(k)
if size not in res:
res[size] = {}
ent = res[size]
c = k[-1]
if c not in ent:
ent[c] = []
ent[c].append(k)
return res
def gen_enum():
print '''\
enum {'''
for k in sorted(HEADERS):
print '''\
{},'''.format(to_enum_hd(k))
print '''\
HD_MAXIDX,
};'''
def gen_index_header():
print '''\
int lookup_token(const uint8_t *name, size_t namelen) {
switch (namelen) {'''
b = build_header(HEADERS)
for size in sorted(b.keys()):
ents = b[size]
print '''\
case {}:'''.format(size)
print '''\
switch (name[{}]) {{'''.format(size - 1)
for c in sorted(ents.keys()):
headers = sorted(ents[c])
print '''\
case '{}':'''.format(c)
for k in headers:
print '''\
if (util::streq_l("{}", name, {})) {{
return {};
}}'''.format(k[:-1], size - 1, to_enum_hd(k))
print '''\
break;'''
print '''\
}
break;'''
print '''\
}
return -1;
}'''
if __name__ == '__main__':
gen_enum()
print ''
gen_index_header()
gentokenlookup(HEADERS, 'HD')

53
genmethodfunc.py Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python
from __future__ import unicode_literals
from io import StringIO
from gentokenlookup import gentokenlookup
# copied from http-parser/http_parser.h, and stripped trailing spaces
# and backslashes.
SRC = '''
XX(0, DELETE, DELETE)
XX(1, GET, GET)
XX(2, HEAD, HEAD)
XX(3, POST, POST)
XX(4, PUT, PUT)
/* pathological */
XX(5, CONNECT, CONNECT)
XX(6, OPTIONS, OPTIONS)
XX(7, TRACE, TRACE)
/* webdav */
XX(8, COPY, COPY)
XX(9, LOCK, LOCK)
XX(10, MKCOL, MKCOL)
XX(11, MOVE, MOVE)
XX(12, PROPFIND, PROPFIND)
XX(13, PROPPATCH, PROPPATCH)
XX(14, SEARCH, SEARCH)
XX(15, UNLOCK, UNLOCK)
/* subversion */
XX(16, REPORT, REPORT)
XX(17, MKACTIVITY, MKACTIVITY)
XX(18, CHECKOUT, CHECKOUT)
XX(19, MERGE, MERGE)
/* upnp */
XX(20, MSEARCH, M-SEARCH)
XX(21, NOTIFY, NOTIFY)
XX(22, SUBSCRIBE, SUBSCRIBE)
XX(23, UNSUBSCRIBE, UNSUBSCRIBE)
/* RFC-5789 */
XX(24, PATCH, PATCH)
XX(25, PURGE, PURGE)
/* CalDAV */
XX(26, MKCALENDAR, MKCALENDAR)
'''
if __name__ == '__main__':
methods = []
for line in StringIO(SRC):
line = line.strip()
if not line.startswith('XX'):
continue
_, m, _ = line.split(',', 2)
methods.append(m.strip())
gentokenlookup(methods, 'HTTP')

69
gentokenlookup.py Normal file
View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python
def to_enum_hd(k, prefix):
res = prefix + '_'
for c in k.upper():
if c == ':' or c == '-':
res += '_'
continue
res += c
return res
def build_header(headers):
res = {}
for k in headers:
size = len(k)
if size not in res:
res[size] = {}
ent = res[size]
c = k[-1]
if c not in ent:
ent[c] = []
ent[c].append(k)
return res
def gen_enum(tokens, prefix):
print '''\
enum {'''
for k in sorted(tokens):
print '''\
{},'''.format(to_enum_hd(k, prefix))
print '''\
{}_MAXIDX,
}};'''.format(prefix)
def gen_index_header(tokens, prefix):
print '''\
int lookup_token(const uint8_t *name, size_t namelen) {
switch (namelen) {'''
b = build_header(tokens)
for size in sorted(b.keys()):
ents = b[size]
print '''\
case {}:'''.format(size)
print '''\
switch (name[{}]) {{'''.format(size - 1)
for c in sorted(ents.keys()):
headers = sorted(ents[c])
print '''\
case '{}':'''.format(c)
for k in headers:
print '''\
if (util::streq_l("{}", name, {})) {{
return {};
}}'''.format(k[:-1], size - 1, to_enum_hd(k, prefix))
print '''\
break;'''
print '''\
}
break;'''
print '''\
}
return -1;
}'''
def gentokenlookup(tokens, prefix):
gen_enum(tokens, prefix)
print ''
gen_index_header(tokens, prefix)

View File

@@ -4,6 +4,7 @@
# script to produce rst file from program's help output.
from __future__ import unicode_literals
from __future__ import print_function
import sys
import re
import argparse
@@ -44,8 +45,8 @@ def help2man(infile):
line = infile.readline().strip()
m = re.match(r'^Usage: (.*)', line)
if not m:
print 'usage line is invalid. Expected following lines:'
print 'Usage: cmdname ...'
print('usage line is invalid. Expected following lines:')
print('Usage: cmdname ...')
sys.exit(1)
synopsis = m.group(1).split(' ', 1)
if len(synopsis) == 2:
@@ -60,7 +61,9 @@ def help2man(infile):
break
description.append(line)
print '''
print('''
.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
.. program:: {cmdname}
{cmdname}(1)
@@ -77,7 +80,7 @@ DESCRIPTION
{description}
'''.format(cmdname=cmdname, args=args,
cmdnameunderline='=' * (len(cmdname) + 3),
synopsis=synopsis, description=format_text('\n'.join(description)))
synopsis=synopsis, description=format_text('\n'.join(description))))
in_arg = False
in_footer = False
@@ -86,16 +89,16 @@ DESCRIPTION
line = line.rstrip()
if not line.strip() and in_arg:
print ''
print()
continue
if line.startswith(' ') and in_arg:
if not line.startswith(arg_indent):
sys.stderr.write('warning: argument description is not indented correctly. We need {} spaces as indentation.\n'.format(len(arg_indent)))
print '{}'.format(format_arg_text(line[len(arg_indent):]))
print('{}'.format(format_arg_text(line[len(arg_indent):])))
continue
if in_arg:
print ''
print()
in_arg = False
if line == '--':
@@ -103,22 +106,22 @@ DESCRIPTION
continue
if in_footer:
print line.strip()
print(line.strip())
continue
if line == 'Options:':
print 'OPTIONS'
print '-------'
print ''
print('OPTIONS')
print('-------')
print()
continue
if line.startswith(' <'):
# positional argument
m = re.match(r'^(?:\s+)([a-zA-Z0-9-_<>]+)(.*)', line)
argname, rest = m.group(1), m.group(2)
print '.. describe:: {}'.format(argname)
print ''
print '{}'.format(format_arg_text(rest.strip()))
print('.. describe:: {}'.format(argname))
print()
print('{}'.format(format_arg_text(rest.strip())))
in_arg = True
continue
@@ -126,9 +129,9 @@ DESCRIPTION
# positional argument
m = re.match(r'^(?:\s+)(\([a-zA-Z0-9-_<> ]+\))(.*)', line)
argname, rest = m.group(1), m.group(2)
print '.. describe:: {}'.format(argname)
print ''
print '{}'.format(format_arg_text(rest.strip()))
print('.. describe:: {}'.format(argname))
print()
print('{}'.format(format_arg_text(rest.strip())))
in_arg = True
continue
@@ -138,23 +141,23 @@ DESCRIPTION
r'^(?:\s+)(-\S+?(?:, -\S+?)*)($| .*)',
line)
argname, rest = m.group(1), m.group(2)
print '.. option:: {}'.format(argname)
print ''
print('.. option:: {}'.format(argname))
print()
rest = rest.strip()
if len(rest):
print '{}'.format(format_arg_text(rest))
print('{}'.format(format_arg_text(rest)))
in_arg = True
continue
if not line.startswith(' ') and line.endswith(':'):
# subsection
subsec = line.strip()[:-1]
print '{}'.format(subsec)
print '{}'.format('~' * len(subsec))
print ''
print('{}'.format(subsec))
print('{}'.format('~' * len(subsec)))
print()
continue
print line.strip()
print(line.strip())
def format_text(text):
# escape *
@@ -184,6 +187,6 @@ if __name__ == '__main__':
args = parser.parse_args()
help2man(sys.stdin)
if args.include:
print ''
print()
with open(args.include) as f:
sys.stdout.write(f.read())

View File

@@ -37,7 +37,8 @@ EXTRA_DIST = \
itprep:
go get -d -v github.com/bradfitz/http2
go get -d -v github.com/tatsuhiro-t/go-nghttp2
go get -d -v golang.org/x/net/spdy
go get -d -v github.com/tatsuhiro-t/spdy
go get -d -v golang.org/x/net/websocket
it:
sh setenv go test -v

View File

@@ -2,8 +2,10 @@ package nghttp2
import (
"bufio"
"bytes"
"fmt"
"github.com/bradfitz/http2/hpack"
"golang.org/x/net/websocket"
"io"
"net/http"
"syscall"
@@ -50,6 +52,27 @@ func TestH1H1PlainGETClose(t *testing.T) {
}
}
// TestH1H1InvalidMethod tests that server rejects invalid method with
// 501 status code
func TestH1H1InvalidMethod(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward this request")
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1InvalidMethod",
method: "get",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 501; got != want {
t.Errorf("status = %v; want %v", got, want)
}
}
// TestH1H1MultipleRequestCL tests that server rejects request which
// contains multiple Content-Length header fields.
func TestH1H1MultipleRequestCL(t *testing.T) {
@@ -246,6 +269,92 @@ func TestH1H1RequestTrailer(t *testing.T) {
}
}
// TestH1H1HeaderFieldBufferPath tests that request with request path
// larger than configured buffer size is rejected.
func TestH1H1HeaderFieldBufferPath(t *testing.T) {
// The value 100 is chosen so that sum of header fields bytes
// does not exceed it. We use > 100 bytes URI to exceed this
// limit.
st := newServerTester([]string{"--header-field-buffer=100"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1HeaderFieldBufferPath",
path: "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1HeaderFieldBuffer tests that request with header fields
// larger than configured buffer size is rejected.
func TestH1H1HeaderFieldBuffer(t *testing.T) {
st := newServerTester([]string{"--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1HeaderFieldBuffer",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1HeaderFields tests that request with header fields more
// than configured number is rejected.
func TestH1H1HeaderFields(t *testing.T) {
st := newServerTester([]string{"--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1HeaderFields",
header: []hpack.HeaderField{
// Add extra header field to ensure that
// header field limit exceeds
pair("Connection", "close"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1Websocket tests that HTTP Upgrade to WebSocket works.
func TestH1H1Websocket(t *testing.T) {
st := newServerTesterHandler(nil, t, websocket.Handler(func(ws *websocket.Conn) {
io.Copy(ws, ws)
}))
defer st.Close()
content := []byte("hello world")
res, err := st.websocket(requestParam{
name: "TestH1H1Websocket",
body: content,
})
if err != nil {
t.Fatalf("Error st.websocket() = %v", err)
}
if got, want := res.body, content; !bytes.Equal(got, want) {
t.Errorf("echo: %q; want %q", got, want)
}
}
// TestH1H2ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/2 backend failed.
func TestH1H2ConnectFailure(t *testing.T) {

View File

@@ -404,6 +404,26 @@ func TestH2H1ConnectFailure(t *testing.T) {
}
}
// TestH2H1InvalidMethod tests that server rejects invalid method with
// 501.
func TestH2H1InvalidMethod(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward this request")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1InvalidMethod",
method: "get",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 501; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1AssembleCookies tests that crumbled cookies in HTTP/2
// request is assembled into 1 when forwarding to HTTP/1 backend link.
func TestH2H1AssembleCookies(t *testing.T) {
@@ -558,6 +578,46 @@ func TestH2H1RequestTrailer(t *testing.T) {
}
}
// TestH2H1HeaderFieldBuffer tests that request with header fields
// larger than configured buffer size is rejected.
func TestH2H1HeaderFieldBuffer(t *testing.T) {
st := newServerTester([]string{"--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1HeaderFieldBuffer",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1HeaderFields tests that request with header fields more
// than configured number is rejected.
func TestH2H1HeaderFields(t *testing.T) {
st := newServerTester([]string{"--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1HeaderFields",
// we have at least 4 pseudo-header fields sent, and
// that ensures that buffer limit exceeds.
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1Upgrade tests HTTP Upgrade to HTTP/2
func TestH2H1Upgrade(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {})
@@ -567,7 +627,7 @@ func TestH2H1Upgrade(t *testing.T) {
name: "TestH2H1Upgrade",
header: []hpack.HeaderField{
pair("Connection", "Upgrade, HTTP2-Settings"),
pair("Upgrade", "h2c-14"),
pair("Upgrade", "h2c"),
pair("HTTP2-Settings", "AAMAAABkAAQAAP__"),
},
})

View File

@@ -2,7 +2,7 @@ package nghttp2
import (
"github.com/bradfitz/http2/hpack"
"golang.org/x/net/spdy"
"github.com/tatsuhiro-t/spdy"
"net/http"
"testing"
)
@@ -170,6 +170,66 @@ func TestS3H1NoVia(t *testing.T) {
}
}
// TestS3H1HeaderFieldBuffer tests that request with header fields
// larger than configured buffer size is rejected.
func TestS3H1HeaderFieldBuffer(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1HeaderFieldBuffer",
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
if got, want := res.spdyRstErrCode, spdy.InternalError; got != want {
t.Errorf("res.spdyRstErrCode: %v; want %v", got, want)
}
}
// TestS3H1HeaderFields tests that request with header fields more
// than configured number is rejected.
func TestS3H1HeaderFields(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1HeaderFields",
// we have at least 5 pseudo-header fields sent, and
// that ensures that buffer limit exceeds.
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
if got, want := res.spdyRstErrCode, spdy.InternalError; got != want {
t.Errorf("res.spdyRstErrCode: %v; want %v", got, want)
}
}
// TestS3H1InvalidMethod tests that server rejects invalid method with
// 501.
func TestS3H1InvalidMethod(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward this request")
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1InvalidMethod",
method: "get",
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
if got, want := res.status, 501; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestS3H2ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/2 backend failed.
func TestS3H2ConnectFailure(t *testing.T) {

View File

@@ -9,7 +9,8 @@ import (
"github.com/bradfitz/http2"
"github.com/bradfitz/http2/hpack"
"github.com/tatsuhiro-t/go-nghttp2"
"golang.org/x/net/spdy"
"github.com/tatsuhiro-t/spdy"
"golang.org/x/net/websocket"
"io"
"io/ioutil"
"net"
@@ -66,6 +67,10 @@ func newServerTester(args []string, t *testing.T, handler http.HandlerFunc) *ser
return newServerTesterInternal(args, t, handler, false, nil)
}
func newServerTesterHandler(args []string, t *testing.T, handler http.Handler) *serverTester {
return newServerTesterInternal(args, t, handler, false, nil)
}
// newServerTester creates test context for TLS frontend connection.
func newServerTesterTLS(args []string, t *testing.T, handler http.HandlerFunc) *serverTester {
return newServerTesterInternal(args, t, handler, true, nil)
@@ -79,7 +84,7 @@ func newServerTesterTLSConfig(args []string, t *testing.T, handler http.HandlerF
// newServerTesterInternal creates test context. If frontendTLS is
// true, set up TLS frontend connection.
func newServerTesterInternal(args []string, t *testing.T, handler http.HandlerFunc, frontendTLS bool, clientConfig *tls.Config) *serverTester {
func newServerTesterInternal(args []string, t *testing.T, handler http.Handler, frontendTLS bool, clientConfig *tls.Config) *serverTester {
ts := httptest.NewUnstartedServer(handler)
backendTLS := false
@@ -279,6 +284,41 @@ func (cbr *chunkedBodyReader) Read(p []byte) (n int, err error) {
return cbr.body.Read(p)
}
func (st *serverTester) websocket(rp requestParam) (*serverResponse, error) {
urlstring := st.url + "/echo"
config, err := websocket.NewConfig(urlstring, st.url)
if err != nil {
st.t.Fatalf("websocket.NewConfig(%q, %q) returned error: %v", urlstring, st.url, err)
}
config.Header.Add("Test-Case", rp.name)
for _, h := range rp.header {
config.Header.Add(h.Name, h.Value)
}
ws, err := websocket.NewClient(config, st.conn)
if err != nil {
st.t.Fatalf("Error creating websocket client: %v", err)
}
if _, err := ws.Write(rp.body); err != nil {
st.t.Fatalf("ws.Write() returned error: %v", err)
}
msg := make([]byte, 1024)
var n int
if n, err = ws.Read(msg); err != nil {
st.t.Fatalf("ws.Read() returned error: %v", err)
}
res := &serverResponse{
body: msg[:n],
}
return res, nil
}
func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
method := "GET"
if rp.method != "" {
@@ -297,7 +337,19 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
body = cbr
}
}
req, err := http.NewRequest(method, st.url, body)
reqURL := st.url
if rp.path != "" {
u, err := url.Parse(st.url)
if err != nil {
st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err)
}
u.Path = rp.path
reqURL = u.String()
}
req, err := http.NewRequest(method, reqURL, body)
if err != nil {
return nil, err
}

View File

@@ -25,7 +25,8 @@ SUBDIRS = includes
EXTRA_DIST = Makefile.msvc
AM_CFLAGS = $(WARNCFLAGS)
AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes @DEFS@
AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \
@DEFS@
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libnghttp2.pc

View File

@@ -36,7 +36,14 @@ extern "C" {
#endif
#include <stdlib.h>
#if defined(_MSC_VER) && (_MSC_VER < 1800)
/* MSVC < 2013 does not have inttypes.h because it is not C99
compliant. See compiler macros and version number in
https://sourceforge.net/p/predef/wiki/Compilers/ */
#include <stdint.h>
#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
#include <inttypes.h>
#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
#include <sys/types.h>
#include <nghttp2/nghttp2ver.h>
@@ -44,7 +51,11 @@ extern "C" {
#ifdef NGHTTP2_STATICLIB
#define NGHTTP2_EXTERN
#elif defined(WIN32)
#ifdef BUILDING_NGHTTP2
#define NGHTTP2_EXTERN __declspec(dllexport)
#else /* !BUILDING_NGHTTP2 */
#define NGHTTP2_EXTERN __declspec(dllimport)
#endif /* !BUILDING_NGHTTP2 */
#else /* !defined(WIN32) */
#define NGHTTP2_EXTERN
#endif /* !defined(WIN32) */
@@ -55,13 +66,13 @@ extern "C" {
* The protocol version identification string of this library
* supports. This identifier is used if HTTP/2 is used over TLS.
*/
#define NGHTTP2_PROTO_VERSION_ID "h2-14"
#define NGHTTP2_PROTO_VERSION_ID "h2"
/**
* @macro
*
* The length of :macro:`NGHTTP2_PROTO_VERSION_ID`.
*/
#define NGHTTP2_PROTO_VERSION_ID_LEN 5
#define NGHTTP2_PROTO_VERSION_ID_LEN 2
/**
* @macro
@@ -72,7 +83,7 @@ extern "C" {
* extension <https://tools.ietf.org/html/rfc7301>`_. This is useful
* to process incoming ALPN tokens in wire format.
*/
#define NGHTTP2_PROTO_ALPN "\x5h2-14"
#define NGHTTP2_PROTO_ALPN "\x2h2"
/**
* @macro
@@ -88,14 +99,14 @@ extern "C" {
* supports. This identifier is used if HTTP/2 is used over cleartext
* TCP.
*/
#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "h2c-14"
#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "h2c"
/**
* @macro
*
* The length of :macro:`NGHTTP2_CLEARTEXT_PROTO_VERSION_ID`.
*/
#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN 6
#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN 3
struct nghttp2_session;
/**
@@ -194,32 +205,17 @@ typedef struct {
/**
* @macro
*
* The client connection preface.
* The client magic string, which is the first 24 bytes byte string of
* client connection preface.
*/
#define NGHTTP2_CLIENT_CONNECTION_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
#define NGHTTP2_CLIENT_MAGIC "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
/**
* @macro
*
* The length of :macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`.
* The length of :macro:`NGHTTP2_CLIENT_MAGIC`.
*/
#define NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN 24
/**
* @macro
*
* The client connection header. This macro is obsoleted by
* NGHTTP2_CLIENT_CONNECTION_PREFACE.
*/
#define NGHTTP2_CLIENT_CONNECTION_HEADER NGHTTP2_CLIENT_CONNECTION_PREFACE
/**
* @macro
*
* The length of :macro:`NGHTTP2_CLIENT_CONNECTION_HEADER`.
*/
#define NGHTTP2_CLIENT_CONNECTION_HEADER_LEN \
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
#define NGHTTP2_CLIENT_MAGIC_LEN 24
/**
* @enum
@@ -368,6 +364,18 @@ typedef enum {
* closed.
*/
NGHTTP2_ERR_HTTP_HEADER = -531,
/**
* Violation in HTTP messaging rule.
*/
NGHTTP2_ERR_HTTP_MESSAGING = -532,
/**
* Stream was refused.
*/
NGHTTP2_ERR_REFUSED_STREAM = -533,
/**
* Unexpected internal error, but recovered.
*/
NGHTTP2_ERR_INTERNAL = -534,
/**
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
* under unexpected condition and processing was terminated (e.g.,
@@ -386,10 +394,10 @@ typedef enum {
*/
NGHTTP2_ERR_CALLBACK_FAILURE = -902,
/**
* Invalid connection preface was received and further processing is
* not possible.
* Invalid client magic (see :macro:`NGHTTP2_CLIENT_MAGIC`) was
* received and further processing is not possible.
*/
NGHTTP2_ERR_BAD_PREFACE = -903
NGHTTP2_ERR_BAD_CLIENT_MAGIC = -903
} nghttp2_error;
/**
@@ -496,21 +504,6 @@ typedef enum {
NGHTTP2_CONTINUATION = 0x09
} nghttp2_frame_type;
/**
* @enum
*
* The extension frame types.
*
* TODO: The assigned frame types were carried from draft-12, and now
* actually TBD.
*/
typedef enum {
/**
* The ALTSVC extension frame.
*/
NGHTTP2_EXT_ALTSVC = 0x0a
} nghttp2_ext_frame_type;
/**
* @enum
*
@@ -1079,52 +1072,12 @@ typedef struct {
* The pointer to extension payload. The exact pointer type is
* determined by hd.type.
*
* If hd.type == :enum:`NGHTTP2_EXT_ALTSVC`, it is a pointer to
* :type:`nghttp2_ext_altsvc`.
* Currently, no extension is supported. This is a place holder for
* the future extensions.
*/
void *payload;
} nghttp2_extension;
/**
* @struct
*
* The ALTSVC extension frame payload. It has following members:
*/
typedef struct {
/**
* Protocol ID
*/
uint8_t *protocol_id;
/**
* Host
*/
uint8_t *host;
/**
* Origin
*/
uint8_t *origin;
/**
* The length of |protocol_id|
*/
size_t protocol_id_len;
/**
* The length of |host|
*/
size_t host_len;
/**
* The length of |origin|
*/
size_t origin_len;
/**
* Max-Age
*/
uint32_t max_age;
/**
* Port
*/
uint16_t port;
} nghttp2_ext_altsvc;
/**
* @union
*
@@ -1199,6 +1152,15 @@ typedef union {
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_send_callback()`.
*
* .. note::
*
* The |length| may be very small. If that is the case, and
* application disables Nagle algorithm (``TCP_NODELAY``), then just
* writing |data| to the network stack leads to very small packet,
* and it is very inefficient. An application should be responsible
* to buffer up small chunks of data as necessary to avoid this
* situation.
*/
typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session,
const uint8_t *data, size_t length,
@@ -1316,11 +1278,11 @@ typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session,
*
* Callback function invoked by `nghttp2_session_recv()` and
* `nghttp2_session_mem_recv()` when an invalid non-DATA frame is
* received. The |error_code| indicates the error. It is usually one
* of the :enum:`nghttp2_error_code` but that is not guaranteed. When
* this callback function is invoked, the library automatically
* submits either RST_STREAM or GOAWAY frame. The |user_data| pointer
* is the third argument passed in to the call to
* received. The error is indicated by the |lib_error_code|, which is
* one of the values defined in :type:`nghttp2_error`. When this
* callback function is invoked, the library automatically submits
* either RST_STREAM or GOAWAY frame. The |user_data| pointer is the
* third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
*
* If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``
@@ -1336,7 +1298,7 @@ typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session,
* `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`.
*/
typedef int (*nghttp2_on_invalid_frame_recv_callback)(
nghttp2_session *session, const nghttp2_frame *frame, uint32_t error_code,
nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code,
void *user_data);
/**
@@ -2036,31 +1998,33 @@ nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
/**
* @function
*
* By default, nghttp2 library only handles HTTP/2 frames and does not
* recognize first 24 bytes of client connection preface. This design
* choice is done due to the fact that server may want to detect the
* application protocol based on first few bytes on clear text
* communication. But for simple servers which only speak HTTP/2, it
* is easier for developers if nghttp2 library takes care of client
* connection preface.
* By default, nghttp2 library, if configured as server, requires
* first 24 bytes of client magic byte string (MAGIC). In most cases,
* this will simplify the implementation of server. But sometimes
* server may want to detect the application protocol based on first
* few bytes on clear text communication.
*
* If this option is used with nonzero |val|, nghttp2 library checks
* first 24 bytes client connection preface. If it is not a valid
* one, `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` will
* return error :enum:`NGHTTP2_ERR_BAD_PREFACE`, which is fatal error.
* If this option is used with nonzero |val|, nghttp2 library does not
* handle MAGIC. It still checks following SETTINGS frame. This
* means that applications should deal with MAGIC by themselves.
*
* If this option is not used or used with zero value, if MAGIC does
* not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()`
* and `nghttp2_session_mem_recv()` will return error
* :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error.
*/
NGHTTP2_EXTERN void
nghttp2_option_set_recv_client_preface(nghttp2_option *option, int val);
nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val);
/**
* @function
*
* By default, nghttp2 library enforces subset of HTTP Messaging rules
* described in `HTTP/2 specification, section 8
* <https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-8>`_.
* See :ref:`http-messaging` section for details. For those
* applications who use nghttp2 library as non-HTTP use, give nonzero
* to |val| to disable this enforcement.
* <https://tools.ietf.org/html/rfc7540#section-8>`_. See
* :ref:`http-messaging` section for details. For those applications
* who use nghttp2 library as non-HTTP use, give nonzero to |val| to
* disable this enforcement.
*/
NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option,
int val);
@@ -2305,6 +2269,15 @@ NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session);
*
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*
* .. note::
*
* This function may produce very small byte string. If that is the
* case, and application disables Nagle algorithm (``TCP_NODELAY``),
* then writing this small chunk leads to very small packet, and it
* is very inefficient. An application should be responsible to
* buffer up small chunks of data as necessary to avoid this
* situation.
*/
NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session,
const uint8_t **data_ptr);
@@ -2367,10 +2340,11 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session,
* Out of memory.
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed.
* :enum:`NGHTTP2_ERR_BAD_PREFACE`
* Invalid client preface was detected. This error only returns
* :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
* Invalid client magic was detected. This error only returns
* when |session| was configured as server and
* `nghttp2_option_set_recv_client_preface()` is used.
* `nghttp2_option_set_no_recv_client_magic()` is not used with
* nonzero value.
*/
NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
@@ -2402,10 +2376,11 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
* Out of memory.
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed.
* :enum:`NGHTTP2_ERR_BAD_PREFACE`
* Invalid client preface was detected. This error only returns
* :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
* Invalid client magic was detected. This error only returns
* when |session| was configured as server and
* `nghttp2_option_set_recv_client_preface()` is used.
* `nghttp2_option_set_no_recv_client_magic()` is not used with
* nonzero value.
*/
NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
const uint8_t *in,
@@ -2949,13 +2924,13 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* If |data_prd| is not ``NULL``, it provides data which will be sent
* in subsequent DATA frames. In this case, a method that allows
* request message bodies
* (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9) must
* be specified with ``:method`` key in |nva| (e.g. ``POST``). This
* function does not take ownership of the |data_prd|. The function
* copies the members of the |data_prd|. If |data_prd| is ``NULL``,
* HEADERS have END_STREAM set. The |stream_user_data| is data
* associated to the stream opened by this request and can be an
* arbitrary pointer, which can be retrieved later by
* (https://tools.ietf.org/html/rfc7231#section-4) must be specified
* with ``:method`` key in |nva| (e.g. ``POST``). This function does
* not take ownership of the |data_prd|. The function copies the
* members of the |data_prd|. If |data_prd| is ``NULL``, HEADERS have
* END_STREAM set. The |stream_user_data| is data associated to the
* stream opened by this request and can be an arbitrary pointer,
* which can be retrieved later by
* `nghttp2_session_get_stream_user_data()`.
*
* This function returns assigned stream ID if it succeeds, or one of
@@ -3488,20 +3463,6 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
int32_t stream_id,
int32_t window_size_increment);
/**
* @function
*
* This function previously submits ALTSVC frame with given
* parameters, but is deprecated and will be removed in a future
* release. This function does nothing and just return 0.
*/
NGHTTP2_EXTERN int
nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
int32_t stream_id, uint32_t max_age, uint16_t port,
const uint8_t *protocol_id, size_t protocol_id_len,
const uint8_t *host, size_t host_len,
const uint8_t *origin, size_t origin_len);
/**
* @function
*
@@ -3520,14 +3481,14 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
* A helper function for dealing with NPN in client side or ALPN in
* server side. The |in| contains peer's protocol list in preferable
* order. The format of |in| is length-prefixed and not
* null-terminated. For example, ``HTTP-draft-04/2.0`` and
* null-terminated. For example, ``h2`` and
* ``http/1.1`` stored in |in| like this::
*
* in[0] = 17
* in[1..17] = "HTTP-draft-04/2.0"
* in[18] = 8
* in[19..26] = "http/1.1"
* inlen = 27
* in[0] = 2
* in[1..2] = "h2"
* in[3] = 8
* in[4..11] = "http/1.1"
* inlen = 12
*
* The selection algorithm is as follows:
*
@@ -3541,12 +3502,10 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
* non-overlap case). In this case, |out| and |outlen| are left
* untouched.
*
* Selecting ``HTTP-draft-04/2.0`` means that ``HTTP-draft-04/2.0`` is
* written into |*out| and its length (which is 17) is assigned to
* |*outlen|.
* Selecting ``h2`` means that ``h2`` is written into |*out| and its
* length (which is 2) is assigned to |*outlen|.
*
* For ALPN, refer to
* https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-05
* For ALPN, refer to https://tools.ietf.org/html/rfc7301
*
* See http://technotes.googlecode.com/git/nextprotoneg.html for more
* details about NPN.
@@ -3562,7 +3521,10 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
* {
* int rv;
* rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
* if(rv == 1) {
* if (rv == -1) {
* return SSL_TLSEXT_ERR_NOACK;
* }
* if (rv == 1) {
* ((MyType*)arg)->http2_selected = 1;
* }
* return SSL_TLSEXT_ERR_OK;
@@ -3593,7 +3555,7 @@ NGHTTP2_EXTERN nghttp2_info *nghttp2_version(int least_version);
* Returns nonzero if the :type:`nghttp2_error` library error code
* |lib_error| is fatal.
*/
NGHTTP2_EXTERN int nghttp2_is_fatal(int lib_error);
NGHTTP2_EXTERN int nghttp2_is_fatal(int lib_error_code);
/**
* @function

View File

@@ -320,7 +320,7 @@ int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) {
}
buf->last = nghttp2_cpymem(buf->last, p, nwrite);
p += len;
p += nwrite;
len -= nwrite;
}

View File

@@ -75,7 +75,7 @@
#define NGHTTP2_MAX_PADLEN 256
/* Union of extension frame payload */
typedef union { nghttp2_ext_altsvc altsvc; } nghttp2_ext_frame_payload;
typedef union { int dummy; } nghttp2_ext_frame_payload;
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);

View File

@@ -544,7 +544,8 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
return 0;
fail2:
if (flags & NGHTTP2_HD_FLAG_NAME_ALLOC) {
if ((flags & NGHTTP2_HD_FLAG_NAME_ALLOC) &&
(flags & NGHTTP2_HD_FLAG_NAME_GIFT) == 0) {
nghttp2_mem_free(mem, ent->nv.name);
}
fail:
@@ -1157,15 +1158,11 @@ static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context,
}
static int name_eq(const nghttp2_nv *a, const nghttp2_nv *b) {
return a->namelen == b->namelen &&
a->name[a->namelen - 1] == b->name[a->namelen - 1] &&
memeq(a->name, b->name, a->namelen);
return a->namelen == b->namelen && memeq(a->name, b->name, a->namelen);
}
static int value_eq(const nghttp2_nv *a, const nghttp2_nv *b) {
return a->valuelen == b->valuelen &&
a->value[a->valuelen - 1] == b->value[a->valuelen - 1] &&
memeq(a->value, b->value, a->valuelen);
return a->valuelen == b->valuelen && memeq(a->value, b->value, a->valuelen);
}
typedef struct {
@@ -1733,7 +1730,9 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
static int hd_inflate_remove_bufs_with_name(nghttp2_hd_inflater *inflater,
nghttp2_nv *nv,
nghttp2_hd_entry *ent_name) {
#ifndef NDEBUG
size_t rv;
#endif
size_t buflen;
uint8_t *buf;
nghttp2_mem *mem;
@@ -1751,7 +1750,10 @@ static int hd_inflate_remove_bufs_with_name(nghttp2_hd_inflater *inflater,
/* Copy including terminal NULL */
memcpy(buf, ent_name->nv.name, ent_name->nv.namelen + 1);
rv = nghttp2_bufs_remove_copy(&inflater->nvbufs,
#ifndef NDEBUG
rv =
#endif
nghttp2_bufs_remove_copy(&inflater->nvbufs,
buf + ent_name->nv.namelen + 1);
assert(ent_name->nv.namelen + 1 + rv == buflen);
@@ -1893,7 +1895,11 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
return 0;
}
if (inflater->index < NGHTTP2_STATIC_TABLE_LENGTH) {
nghttp2_mem_free(mem, nv.value);
} else {
nghttp2_mem_free(mem, nv.name);
}
return NGHTTP2_ERR_NOMEM;
}

View File

@@ -109,7 +109,7 @@ typedef enum {
NGHTTP2_TOKEN_CONNECTION,
NGHTTP2_TOKEN_KEEP_ALIVE,
NGHTTP2_TOKEN_PROXY_CONNECTION,
NGHTTP2_TOKEN_UPGRADE,
NGHTTP2_TOKEN_UPGRADE
} nghttp2_token;
typedef enum {

View File

@@ -297,12 +297,18 @@ const char *nghttp2_strerror(int error_code) {
return "The current session is closing";
case NGHTTP2_ERR_HTTP_HEADER:
return "Invalid HTTP header field was received";
case NGHTTP2_ERR_HTTP_MESSAGING:
return "Violation in HTTP messaging rule";
case NGHTTP2_ERR_REFUSED_STREAM:
return "Stream was refused";
case NGHTTP2_ERR_INTERNAL:
return "Internal error";
case NGHTTP2_ERR_NOMEM:
return "Out of memory";
case NGHTTP2_ERR_CALLBACK_FAILURE:
return "The user callback function failed";
case NGHTTP2_ERR_BAD_PREFACE:
return "Received bad connection preface";
case NGHTTP2_ERR_BAD_CLIENT_MAGIC:
return "Received bad clinet magic byte string";
default:
return "Unknown error code";
}

View File

@@ -47,9 +47,9 @@ void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
option->peer_max_concurrent_streams = val;
}
void nghttp2_option_set_recv_client_preface(nghttp2_option *option, int val) {
option->opt_set_mask |= NGHTTP2_OPT_RECV_CLIENT_PREFACE;
option->recv_client_preface = val;
void nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val) {
option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC;
option->no_recv_client_magic = val;
}
void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) {

View File

@@ -57,8 +57,8 @@ typedef enum {
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
*/
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
NGHTTP2_OPT_RECV_CLIENT_PREFACE = 1 << 2,
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3
} nghttp2_option_flag;
/**
@@ -79,9 +79,9 @@ struct nghttp2_option {
*/
uint8_t no_auto_window_update;
/**
* NGHTTP2_OPT_RECV_CLIENT_PREFACE
* NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC
*/
uint8_t recv_client_preface;
uint8_t no_recv_client_magic;
/**
* NGHTTP2_OPT_NO_HTTP_MESSAGING
*/

View File

@@ -81,7 +81,7 @@ typedef enum {
/* indicates that this GOAWAY is just a notification for graceful
shutdown. No nghttp2_session.goaway_flags should be updated on
the reaction to this frame. */
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2,
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2
} nghttp2_goaway_aux_flag;
/* struct used for GOAWAY frame */

View File

@@ -71,11 +71,13 @@ session_is_incoming_concurrent_streams_pending_max(nghttp2_session *session) {
/*
* Returns non-zero if |lib_error| is non-fatal error.
*/
static int is_non_fatal(int lib_error) {
return lib_error < 0 && lib_error > NGHTTP2_ERR_FATAL;
static int is_non_fatal(int lib_error_code) {
return lib_error_code < 0 && lib_error_code > NGHTTP2_ERR_FATAL;
}
int nghttp2_is_fatal(int lib_error) { return lib_error < NGHTTP2_ERR_FATAL; }
int nghttp2_is_fatal(int lib_error_code) {
return lib_error_code < NGHTTP2_ERR_FATAL;
}
static int session_enforce_http_messaging(nghttp2_session *session) {
return (session->opt_flags & NGHTTP2_OPTMASK_NO_HTTP_MESSAGING) == 0;
@@ -303,9 +305,10 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
aob->state = NGHTTP2_OB_POP_ITEM;
}
/* This global variable exists for tests where we want to disable this
check. */
int nghttp2_enable_strict_first_settings_check = 1;
/* The global variable for tests where we want to disable strict
preface handling. */
/* Specify NGHTTP2_EXTERN, so that we can test using Win build dll. */
NGHTTP2_EXTERN int nghttp2_enable_strict_preface = 1;
static int session_new(nghttp2_session **session_ptr,
const nghttp2_session_callbacks *callbacks,
@@ -395,10 +398,10 @@ static int session_new(nghttp2_session **session_ptr,
option->peer_max_concurrent_streams;
}
if ((option->opt_set_mask & NGHTTP2_OPT_RECV_CLIENT_PREFACE) &&
option->recv_client_preface) {
if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC) &&
option->no_recv_client_magic) {
(*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE;
(*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC;
}
if ((option->opt_set_mask & NGHTTP2_OPT_NO_HTTP_MESSAGING) &&
@@ -413,19 +416,25 @@ static int session_new(nghttp2_session **session_ptr,
session_inbound_frame_reset(*session_ptr);
if (nghttp2_enable_strict_preface) {
nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe;
if (server &&
((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE)) {
nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe;
iframe->state = NGHTTP2_IB_READ_CLIENT_PREFACE;
iframe->payloadleft = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN;
} else if (nghttp2_enable_strict_first_settings_check) {
nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe;
((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) ==
0) {
iframe->state = NGHTTP2_IB_READ_CLIENT_MAGIC;
iframe->payloadleft = NGHTTP2_CLIENT_MAGIC_LEN;
} else {
iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS;
}
if (!server) {
(*session_ptr)->aob.state = NGHTTP2_OB_SEND_CLIENT_MAGIC;
nghttp2_bufs_add(&(*session_ptr)->aob.framebufs, NGHTTP2_CLIENT_MAGIC,
NGHTTP2_CLIENT_MAGIC_LEN);
}
}
return 0;
fail_aob_framebuf:
@@ -2852,6 +2861,25 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
break;
}
case NGHTTP2_OB_SEND_CLIENT_MAGIC: {
size_t datalen;
nghttp2_buf *buf;
buf = &framebufs->cur->buf;
if (buf->pos == buf->last) {
DEBUGF(fprintf(stderr, "send: end transmission of client magic\n"));
active_outbound_item_reset(aob, mem);
break;
}
*data_ptr = buf->pos;
datalen = nghttp2_buf_len(buf);
buf->pos += datalen;
return datalen;
}
}
}
}
@@ -2866,6 +2894,7 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
return len;
}
if (session->aob.item) {
/* We have to call session_after_frame_sent1 here to handle stream
closure upon transmission of frames. Otherwise, END_STREAM may
be reached to client before we call nghttp2_session_mem_send
@@ -2875,6 +2904,7 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
assert(nghttp2_is_fatal(rv));
return (ssize_t)rv;
}
}
return len;
}
@@ -3006,18 +3036,40 @@ static int session_handle_frame_size_error(nghttp2_session *session,
return nghttp2_session_terminate_session(session, NGHTTP2_FRAME_SIZE_ERROR);
}
static int get_error_code_from_lib_error_code(int lib_error_code) {
switch (lib_error_code) {
case NGHTTP2_ERR_STREAM_CLOSED:
return NGHTTP2_STREAM_CLOSED;
case NGHTTP2_ERR_HEADER_COMP:
return NGHTTP2_COMPRESSION_ERROR;
case NGHTTP2_ERR_FRAME_SIZE_ERROR:
return NGHTTP2_FRAME_SIZE_ERROR;
case NGHTTP2_ERR_FLOW_CONTROL:
return NGHTTP2_FLOW_CONTROL_ERROR;
case NGHTTP2_ERR_REFUSED_STREAM:
return NGHTTP2_REFUSED_STREAM;
case NGHTTP2_ERR_PROTO:
case NGHTTP2_ERR_HTTP_HEADER:
case NGHTTP2_ERR_HTTP_MESSAGING:
return NGHTTP2_PROTOCOL_ERROR;
default:
return NGHTTP2_INTERNAL_ERROR;
}
}
static int session_handle_invalid_stream2(nghttp2_session *session,
int32_t stream_id,
nghttp2_frame *frame,
uint32_t error_code) {
int lib_error_code) {
int rv;
rv = nghttp2_session_add_rst_stream(session, stream_id, error_code);
rv = nghttp2_session_add_rst_stream(
session, stream_id, get_error_code_from_lib_error_code(lib_error_code));
if (rv != 0) {
return rv;
}
if (session->callbacks.on_invalid_frame_recv_callback) {
if (session->callbacks.on_invalid_frame_recv_callback(
session, frame, error_code, session->user_data) != 0) {
session, frame, lib_error_code, session->user_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
@@ -3026,16 +3078,16 @@ static int session_handle_invalid_stream2(nghttp2_session *session,
static int session_handle_invalid_stream(nghttp2_session *session,
nghttp2_frame *frame,
uint32_t error_code) {
int lib_error_code) {
return session_handle_invalid_stream2(session, frame->hd.stream_id, frame,
error_code);
lib_error_code);
}
static int session_inflate_handle_invalid_stream(nghttp2_session *session,
nghttp2_frame *frame,
uint32_t error_code) {
int lib_error_code) {
int rv;
rv = session_handle_invalid_stream(session, frame, error_code);
rv = session_handle_invalid_stream(session, frame, lib_error_code);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -3047,24 +3099,25 @@ static int session_inflate_handle_invalid_stream(nghttp2_session *session,
*/
static int session_handle_invalid_connection(nghttp2_session *session,
nghttp2_frame *frame,
uint32_t error_code,
int lib_error_code,
const char *reason) {
if (session->callbacks.on_invalid_frame_recv_callback) {
if (session->callbacks.on_invalid_frame_recv_callback(
session, frame, error_code, session->user_data) != 0) {
session, frame, lib_error_code, session->user_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
return nghttp2_session_terminate_session_with_reason(session, error_code,
reason);
return nghttp2_session_terminate_session_with_reason(
session, get_error_code_from_lib_error_code(lib_error_code), reason);
}
static int session_inflate_handle_invalid_connection(nghttp2_session *session,
nghttp2_frame *frame,
uint32_t error_code,
int lib_error_code,
const char *reason) {
int rv;
rv = session_handle_invalid_connection(session, frame, error_code, reason);
rv =
session_handle_invalid_connection(session, frame, lib_error_code, reason);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -3131,12 +3184,12 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
}
if (proclen < 0) {
if (session->iframe.state == NGHTTP2_IB_READ_HEADER_BLOCK) {
if (stream && stream->state != NGHTTP2_STREAM_CLOSING) {
if (subject_stream && subject_stream->state != NGHTTP2_STREAM_CLOSING) {
/* Adding RST_STREAM here is very important. It prevents
from invoking subsequent callbacks for the same stream
ID. */
rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id,
NGHTTP2_COMPRESSION_ERROR);
rv = nghttp2_session_add_rst_stream(
session, subject_stream->stream_id, NGHTTP2_COMPRESSION_ERROR);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -3170,7 +3223,7 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
rv =
session_handle_invalid_stream2(session, subject_stream->stream_id,
frame, NGHTTP2_PROTOCOL_ERROR);
frame, NGHTTP2_ERR_HTTP_HEADER);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -3345,7 +3398,7 @@ static int session_after_header_block_received(nghttp2_session *session) {
call_cb = 0;
rv = session_handle_invalid_stream2(session, stream_id, frame,
NGHTTP2_PROTOCOL_ERROR);
NGHTTP2_ERR_HTTP_MESSAGING);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -3384,8 +3437,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
nghttp2_stream *stream;
if (frame->hd.stream_id == 0) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
"request HEADERS: stream_id == 0");
session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: stream_id == 0");
}
/* If client recieves idle stream from server, it is invalid
@@ -3394,7 +3446,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
if (!session->server) {
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
session, frame, NGHTTP2_ERR_PROTO,
"request HEADERS: client received request");
}
@@ -3411,7 +3463,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
just ignore HEADERS for now. */
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
session, frame, NGHTTP2_ERR_PROTO,
"request HEADERS: invalid stream_id");
}
@@ -3426,19 +3478,18 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
if (session_is_incoming_concurrent_streams_max(session)) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
session, frame, NGHTTP2_ERR_PROTO,
"request HEADERS: max concurrent streams exceeded");
}
if (frame->headers.pri_spec.stream_id == frame->hd.stream_id) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
"request HEADERS: depend on itself");
session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: depend on itself");
}
if (session_is_incoming_concurrent_streams_pending_max(session)) {
return session_inflate_handle_invalid_stream(session, frame,
NGHTTP2_REFUSED_STREAM);
NGHTTP2_ERR_REFUSED_STREAM);
}
stream = nghttp2_session_open_stream(
@@ -3465,8 +3516,7 @@ int nghttp2_session_on_response_headers_received(nghttp2_session *session,
nghttp2_session_is_my_stream_id(session, frame->hd.stream_id));
if (frame->hd.stream_id == 0) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
"response HEADERS: stream_id == 0");
session, frame, NGHTTP2_ERR_PROTO, "response HEADERS: stream_id == 0");
}
if (stream->shut_flags & NGHTTP2_SHUT_RD) {
/* half closed (remote): from the spec:
@@ -3476,7 +3526,7 @@ int nghttp2_session_on_response_headers_received(nghttp2_session *session,
5.4.2) of type STREAM_CLOSED.
*/
return session_inflate_handle_invalid_stream(session, frame,
NGHTTP2_STREAM_CLOSED);
NGHTTP2_ERR_STREAM_CLOSED);
}
stream->state = NGHTTP2_STREAM_OPENED;
rv = session_call_on_begin_headers(session, frame);
@@ -3493,7 +3543,7 @@ int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
assert(stream->state == NGHTTP2_STREAM_RESERVED);
if (frame->hd.stream_id == 0) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
session, frame, NGHTTP2_ERR_PROTO,
"push response HEADERS: stream_id == 0");
}
if (session->goaway_flags) {
@@ -3503,12 +3553,12 @@ int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
if (session_is_incoming_concurrent_streams_max(session)) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
session, frame, NGHTTP2_ERR_PROTO,
"push response HEADERS: max concurrent streams exceeded");
}
if (session_is_incoming_concurrent_streams_pending_max(session)) {
return session_inflate_handle_invalid_stream(session, frame,
NGHTTP2_REFUSED_STREAM);
NGHTTP2_ERR_REFUSED_STREAM);
}
nghttp2_stream_promise_fulfilled(stream);
@@ -3526,7 +3576,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
int rv = 0;
if (frame->hd.stream_id == 0) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "HEADERS: stream_id == 0");
session, frame, NGHTTP2_ERR_PROTO, "HEADERS: stream_id == 0");
}
if (stream->state == NGHTTP2_STREAM_RESERVED) {
/* reserved. The valid push response HEADERS is processed by
@@ -3534,7 +3584,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
generic HEADERS is called invalid cases for HEADERS against
reserved state. */
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "HEADERS: stream in reserved");
session, frame, NGHTTP2_ERR_PROTO, "HEADERS: stream in reserved");
}
if ((stream->shut_flags & NGHTTP2_SHUT_RD)) {
/* half closed (remote): from the spec:
@@ -3544,7 +3594,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
5.4.2) of type STREAM_CLOSED.
*/
return session_inflate_handle_invalid_stream(session, frame,
NGHTTP2_STREAM_CLOSED);
NGHTTP2_ERR_STREAM_CLOSED);
}
if (nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
if (stream->state == NGHTTP2_STREAM_OPENED) {
@@ -3560,7 +3610,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
return NGHTTP2_ERR_IGN_HEADER_BLOCK;
} else {
return session_inflate_handle_invalid_stream(session, frame,
NGHTTP2_PROTOCOL_ERROR);
NGHTTP2_ERR_PROTO);
}
}
/* If this is remote peer initiated stream, it is OK unless it
@@ -3620,8 +3670,8 @@ int nghttp2_session_on_priority_received(nghttp2_session *session,
nghttp2_stream *stream;
if (frame->hd.stream_id == 0) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "PRIORITY: stream_id == 0");
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"PRIORITY: stream_id == 0");
}
if (!session->server) {
@@ -3672,14 +3722,14 @@ int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
int rv;
nghttp2_stream *stream;
if (frame->hd.stream_id == 0) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "RST_STREAM: stream_id == 0");
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"RST_STREAM: stream_id == 0");
}
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
if (!stream) {
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "RST_STREAM: stream in idle");
session, frame, NGHTTP2_ERR_PROTO, "RST_STREAM: stream in idle");
}
}
@@ -3899,18 +3949,18 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
mem = &session->mem;
if (frame->hd.stream_id != 0) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "SETTINGS: stream_id != 0");
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"SETTINGS: stream_id != 0");
}
if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
if (frame->settings.niv != 0) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_FRAME_SIZE_ERROR,
session, frame, NGHTTP2_ERR_FRAME_SIZE_ERROR,
"SETTINGS: ACK and payload != 0");
}
if (session->inflight_niv == -1) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "SETTINGS: unexpected ACK");
session, frame, NGHTTP2_ERR_PROTO, "SETTINGS: unexpected ACK");
}
rv = nghttp2_session_update_local_settings(session, session->inflight_iv,
session->inflight_niv);
@@ -3918,15 +3968,10 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
session->inflight_iv = NULL;
session->inflight_niv = -1;
if (rv != 0) {
uint32_t error_code = NGHTTP2_INTERNAL_ERROR;
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (rv == NGHTTP2_ERR_HEADER_COMP) {
error_code = NGHTTP2_COMPRESSION_ERROR;
}
return session_handle_invalid_connection(session, frame, error_code,
NULL);
return session_handle_invalid_connection(session, frame, rv, NULL);
}
return session_call_on_frame_received(session, frame);
}
@@ -3939,7 +3984,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
if (entry->value > NGHTTP2_MAX_HEADER_TABLE_SIZE) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_COMPRESSION_ERROR,
session, frame, NGHTTP2_ERR_HEADER_COMP,
"SETTINGS: too large SETTINGS_HEADER_TABLE_SIZE");
}
@@ -3950,7 +3995,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
return rv;
} else {
return session_handle_invalid_connection(
session, frame, NGHTTP2_COMPRESSION_ERROR, NULL);
session, frame, NGHTTP2_ERR_HEADER_COMP, NULL);
}
}
@@ -3961,13 +4006,13 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
if (entry->value != 0 && entry->value != 1) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
session, frame, NGHTTP2_ERR_PROTO,
"SETTINGS: invalid SETTINGS_ENBLE_PUSH");
}
if (!session->server && entry->value != 0) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
session, frame, NGHTTP2_ERR_PROTO,
"SETTINGS: server attempted to enable push");
}
@@ -3985,7 +4030,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
/* Check that initial_window_size < (1u << 31) */
if (entry->value > NGHTTP2_MAX_WINDOW_SIZE) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_FLOW_CONTROL_ERROR,
session, frame, NGHTTP2_ERR_FLOW_CONTROL,
"SETTINGS: too large SETTINGS_INITIAL_WINDOW_SIZE");
}
@@ -3997,7 +4042,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
if (rv != 0) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_FLOW_CONTROL_ERROR, NULL);
session, frame, NGHTTP2_ERR_FLOW_CONTROL, NULL);
}
session->remote_settings.initial_window_size = entry->value;
@@ -4008,7 +4053,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
if (entry->value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
entry->value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
session, frame, NGHTTP2_ERR_PROTO,
"SETTINGS: invalid SETTINGS_MAX_FRAME_SIZE");
}
@@ -4032,7 +4077,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
}
return session_handle_invalid_connection(session, frame,
NGHTTP2_INTERNAL_ERROR, NULL);
NGHTTP2_ERR_INTERNAL, NULL);
}
}
@@ -4085,11 +4130,11 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
if (frame->hd.stream_id == 0) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "PUSH_PROMISE: stream_id == 0");
session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream_id == 0");
}
if (session->server || session->local_settings.enable_push == 0) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "PUSH_PROMISE: push disabled");
session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: push disabled");
}
if (session->goaway_flags) {
/* We just dicard PUSH_PROMISE after GOAWAY is sent or
@@ -4099,8 +4144,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
if (!nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
"PUSH_PROMISE: invalid stream_id");
session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: invalid stream_id");
}
if (!session_is_new_peer_stream_id(session,
@@ -4109,7 +4153,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
illegal stream ID is subject to a connection error of type
PROTOCOL_ERROR. */
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
session, frame, NGHTTP2_ERR_PROTO,
"PUSH_PROMISE: invalid promised_stream_id");
}
session->last_recv_stream_id = frame->push_promise.promised_stream_id;
@@ -4119,8 +4163,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
if (!stream) {
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
"PUSH_PROMISE: stream in idle");
session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream in idle");
}
}
rv = nghttp2_session_add_rst_stream(session,
@@ -4189,8 +4232,8 @@ int nghttp2_session_on_ping_received(nghttp2_session *session,
nghttp2_frame *frame) {
int rv = 0;
if (frame->hd.stream_id != 0) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "PING: stream_id != 0");
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"PING: stream_id != 0");
}
if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0 &&
!session_is_closing(session)) {
@@ -4219,8 +4262,8 @@ int nghttp2_session_on_goaway_received(nghttp2_session *session,
int rv;
if (frame->hd.stream_id != 0) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR, "GOAWAY: stream_id != 0");
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"GOAWAY: stream_id != 0");
}
/* Spec says Endpoints MUST NOT increase the value they send in the
last stream identifier. */
@@ -4228,8 +4271,7 @@ int nghttp2_session_on_goaway_received(nghttp2_session *session,
!nghttp2_session_is_my_stream_id(session,
frame->goaway.last_stream_id)) ||
session->remote_last_stream_id < frame->goaway.last_stream_id) {
return session_handle_invalid_connection(session, frame,
NGHTTP2_PROTOCOL_ERROR,
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"GOAWAY: invalid last_stream_id");
}
@@ -4265,14 +4307,14 @@ session_on_connection_window_update_received(nghttp2_session *session,
nghttp2_frame *frame) {
/* Handle connection-level flow control */
if (frame->window_update.window_size_increment == 0) {
return session_handle_invalid_connection(session, frame,
NGHTTP2_PROTOCOL_ERROR, NULL);
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
NULL);
}
if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment <
session->remote_window_size) {
return session_handle_invalid_connection(session, frame,
NGHTTP2_FLOW_CONTROL_ERROR, NULL);
NGHTTP2_ERR_FLOW_CONTROL, NULL);
}
session->remote_window_size += frame->window_update.window_size_increment;
@@ -4286,25 +4328,22 @@ static int session_on_stream_window_update_received(nghttp2_session *session,
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
if (!stream) {
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
return session_handle_invalid_connection(session, frame,
NGHTTP2_PROTOCOL_ERROR,
"WINDOW_UPDATE to idle stream");
return session_handle_invalid_connection(
session, frame, NGHTTP2_ERR_PROTO, "WINDOW_UPDATE to idle stream");
}
return 0;
}
if (state_reserved_remote(session, stream)) {
return session_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
"WINDOW_UPADATE to reserved stream");
session, frame, NGHTTP2_ERR_PROTO, "WINDOW_UPADATE to reserved stream");
}
if (frame->window_update.window_size_increment == 0) {
return session_handle_invalid_stream(session, frame,
NGHTTP2_PROTOCOL_ERROR);
return session_handle_invalid_stream(session, frame, NGHTTP2_ERR_PROTO);
}
if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment <
stream->remote_window_size) {
return session_handle_invalid_stream(session, frame,
NGHTTP2_FLOW_CONTROL_ERROR);
NGHTTP2_ERR_FLOW_CONTROL);
}
stream->remote_window_size += frame->window_update.window_size_increment;
@@ -4340,18 +4379,6 @@ static int session_process_window_update_frame(nghttp2_session *session) {
return nghttp2_session_on_window_update_received(session, frame);
}
/* static int get_error_code_from_lib_error_code(int lib_error_code) */
/* { */
/* switch(lib_error_code) { */
/* case NGHTTP2_ERR_HEADER_COMP: */
/* return NGHTTP2_COMPRESSION_ERROR; */
/* case NGHTTP2_ERR_FRAME_SIZE_ERROR: */
/* return NGHTTP2_FRAME_SIZE_ERROR; */
/* default: */
/* return NGHTTP2_PROTOCOL_ERROR; */
/* } */
/* } */
int nghttp2_session_on_data_received(nghttp2_session *session,
nghttp2_frame *frame) {
int rv = 0;
@@ -4789,14 +4816,13 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
for (;;) {
switch (iframe->state) {
case NGHTTP2_IB_READ_CLIENT_PREFACE:
case NGHTTP2_IB_READ_CLIENT_MAGIC:
readlen = nghttp2_min(inlen, iframe->payloadleft);
if (memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE +
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN -
if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN -
iframe->payloadleft,
in, readlen) != 0) {
return NGHTTP2_ERR_BAD_PREFACE;
return NGHTTP2_ERR_BAD_CLIENT_MAGIC;
}
iframe->payloadleft -= readlen;
@@ -5734,7 +5760,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) {
return rv;
}
}
data_readlen = inbound_frame_effective_readlen(
iframe, iframe->payloadleft, readlen);
@@ -5753,11 +5778,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
DEBUGF(fprintf(stderr, "recv: data_readlen=%zd\n", data_readlen));
if (stream && data_readlen > 0) {
if (data_readlen > 0) {
if (session_enforce_http_messaging(session)) {
if (nghttp2_http_on_data_chunk(stream, data_readlen) != 0) {
rv = nghttp2_session_add_rst_stream(
session, iframe->frame.hd.stream_id, NGHTTP2_PROTOCOL_ERROR);
rv = nghttp2_session_add_rst_stream(session,
iframe->frame.hd.stream_id,
NGHTTP2_PROTOCOL_ERROR);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -5779,6 +5805,15 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
}
}
}
} else if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
/* stream was closed or does not exist. Consume all data
for connection immediately here */
rv = session_update_connection_consumed_size(session, readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
}
}
if (iframe->payloadleft) {

View File

@@ -46,14 +46,15 @@
*/
typedef enum {
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2
} nghttp2_optmask;
typedef enum {
NGHTTP2_OB_POP_ITEM,
NGHTTP2_OB_SEND_DATA,
NGHTTP2_OB_SEND_NO_COPY
NGHTTP2_OB_SEND_NO_COPY,
NGHTTP2_OB_SEND_CLIENT_MAGIC
} nghttp2_outbound_state;
typedef struct {
@@ -69,7 +70,7 @@ typedef struct {
/* Internal state when receiving incoming frame */
typedef enum {
/* Receiving frame header */
NGHTTP2_IB_READ_CLIENT_PREFACE,
NGHTTP2_IB_READ_CLIENT_MAGIC,
NGHTTP2_IB_READ_FIRST_SETTINGS,
NGHTTP2_IB_READ_HEAD,
NGHTTP2_IB_READ_NBYTE,
@@ -84,7 +85,7 @@ typedef enum {
NGHTTP2_IB_READ_PAD_DATA,
NGHTTP2_IB_READ_DATA,
NGHTTP2_IB_IGN_DATA,
NGHTTP2_IB_IGN_ALL,
NGHTTP2_IB_IGN_ALL
} nghttp2_inbound_state;
#define NGHTTP2_INBOUND_NUM_IV 7
@@ -136,7 +137,7 @@ typedef enum {
/* Flag means GOAWAY was sent */
NGHTTP2_GOAWAY_SENT = 0x4,
/* Flag means GOAWAY was received */
NGHTTP2_GOAWAY_RECV = 0x8,
NGHTTP2_GOAWAY_RECV = 0x8
} nghttp2_goaway_flag;
struct nghttp2_session {

View File

@@ -202,10 +202,10 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
if (si->dpri != NGHTTP2_STREAM_DPRI_REST) {
si->effective_weight =
nghttp2_stream_dep_distributed_effective_weight(stream, si->weight);
}
stream_update_dep_effective_weight(si);
}
}
}
static void stream_update_dep_set_rest(nghttp2_stream *stream) {
@@ -311,7 +311,6 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
*/
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) {
nghttp2_stream *si;
int rv;
stream->sum_norest_weight = 0;
@@ -323,17 +322,14 @@ static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) {
return 0;
}
rv = 0;
for (si = stream->dep_next; si; si = si->sib_next) {
if (stream_update_dep_sum_norest_weight(si)) {
rv = 1;
stream->sum_norest_weight += si->weight;
}
}
return rv;
return stream->sum_norest_weight > 0;
}
static int stream_update_dep_on_attach_item(nghttp2_stream *stream,

View File

@@ -38,7 +38,7 @@
/*
* Maximum number of streams in one dependency tree.
*/
#define NGHTTP2_MAX_DEP_TREE_LENGTH 100
#define NGHTTP2_MAX_DEP_TREE_LENGTH 120
/*
* If local peer is stream initiator:
@@ -133,7 +133,7 @@ typedef enum {
/* "http" or "https" scheme */
NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 12,
/* set if final response is expected */
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 13,
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 13
} nghttp2_http_flag;
typedef enum {

View File

@@ -376,15 +376,6 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
return 0;
}
int nghttp2_submit_altsvc(nghttp2_session *session _U_, uint8_t flags _U_,
int32_t stream_id _U_, uint32_t max_age _U_,
uint16_t port _U_, const uint8_t *protocol_id _U_,
size_t protocol_id_len _U_, const uint8_t *host _U_,
size_t host_len _U_, const uint8_t *origin _U_,
size_t origin_len _U_) {
return 0;
}
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
const nghttp2_data_provider *data_prd) {
uint8_t flags = NGHTTP2_FLAG_NONE;

View File

@@ -36,7 +36,8 @@ install-exec-local:
$(PYTHON) setup.py install --prefix=$(DESTDIR)$(prefix)
uninstall-local:
rm -rf $(DESTDIR)$(libdir)/python*/site-packages/*nghttp2*
rm -f $(DESTDIR)$(libdir)/python*/site-packages/nghttp2.so
rm -f $(DESTDIR)$(libdir)/python*/site-packages/python_nghttp2-*.egg-info
clean-local:
$(PYTHON) setup.py clean --all

View File

@@ -698,6 +698,7 @@ cdef class _HTTP2SessionCoreBase:
handler.stream_id = stream_id
handler.http2 = self
handler.remote_address = self._get_remote_address()
handler.client_certificate = self._get_client_certificate()
self.handlers.add(handler)
def _rst_stream(self, stream_id,
@@ -713,6 +714,13 @@ cdef class _HTTP2SessionCoreBase:
def _get_remote_address(self):
return self.transport.get_extra_info('peername')
def _get_client_certificate(self):
sock = self.transport.get_extra_info('socket')
try:
return sock.getpeercert()
except AttributeError:
return None
def _start_settings_timer(self):
loop = asyncio.get_event_loop()
self.settings_timer = loop.call_later(self.SETTINGS_TIMEOUT,
@@ -875,6 +883,11 @@ cdef class _HTTP2SessionCore(_HTTP2SessionCoreBase):
return promised_handler
def connection_lost(self):
for handler in self.handlers:
handler.on_close(cnghttp2.NGHTTP2_INTERNAL_ERROR)
self.handlers = set()
cdef class _HTTP2ClientSessionCore(_HTTP2SessionCoreBase):
def __cinit__(self, *args, **kwargs):
cdef cnghttp2.nghttp2_session_callbacks *callbacks
@@ -1030,6 +1043,9 @@ if asyncio:
Contains a tuple of the form (host, port) referring to the client's
address.
client_certificate
May contain the client certifcate in its non-binary form
stream_id
Stream ID of this stream
@@ -1058,6 +1074,8 @@ if asyncio:
self.http2 = http2
# address of the client
self.remote_address = self.http2._get_remote_address()
# certificate of the client
self._client_certificate = self.http2._get_client_certificate()
# :scheme header field in request
self.scheme = None
# :method header field in request
@@ -1075,6 +1093,10 @@ if asyncio:
def client_address(self):
return self.remote_address
@property
def client_certificate(self):
return self._client_certificate
def on_headers(self):
'''Called when request HEADERS is arrived.
@@ -1237,9 +1259,11 @@ if asyncio:
logging.info('connection_made, address:%s, port:%s', address[0], address[1])
self.transport = transport
self.connection_header = cnghttp2.NGHTTP2_CLIENT_CONNECTION_PREFACE
sock = self.transport.get_extra_info('socket')
try:
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
except OSError as e:
logging.info('failed to set tcp-nodelay: %s', str(e))
ssl_ctx = self.transport.get_extra_info('sslcontext')
if ssl_ctx:
protocol = sock.selected_npn_protocol()
@@ -1247,19 +1271,7 @@ if asyncio:
if protocol.encode('utf-8') != \
cnghttp2.NGHTTP2_PROTO_VERSION_ID:
self.transport.abort()
def connection_lost(self, exc):
logging.info('connection_lost')
if self.http2:
self.http2 = None
def data_received(self, data):
nread = min(len(data), len(self.connection_header))
if self.connection_header.startswith(data[:nread]):
data = data[nread:]
self.connection_header = self.connection_header[nread:]
if len(self.connection_header) == 0:
return
try:
self.http2 = _HTTP2SessionCore\
(self.transport,
@@ -1269,13 +1281,14 @@ if asyncio:
self.transport.abort()
return
self.data_received = self.data_received2
self.resume_writing = self.resume_writing2
self.data_received(data)
else:
self.transport.abort()
def data_received2(self, data):
def connection_lost(self, exc):
logging.info('connection_lost')
if self.http2:
self.http2.connection_lost()
self.http2 = None
def data_received(self, data):
try:
self.http2.data_received(data)
except Exception as err:
@@ -1283,7 +1296,7 @@ if asyncio:
self.transport.close()
return
def resume_writing2(self):
def resume_writing(self):
try:
self.http2.send_data()
except Exception as err:
@@ -1350,7 +1363,8 @@ if asyncio:
When whole response is received, on_response_done() is invoked.
When stream is closed, on_close(error_code) is called.
When stream is closed or underlying connection is lost,
on_close(error_code) is called.
The application can send follow up requests using HTTP2Client.send_request() method.
@@ -1490,8 +1504,6 @@ if asyncio:
cnghttp2.NGHTTP2_PROTO_VERSION_ID:
self.transport.abort()
# Send preamble
self.transport.write(cnghttp2.NGHTTP2_CLIENT_CONNECTION_PREFACE)
self.http2 = _HTTP2ClientSessionCore(self.transport)
# Clear pending requests

25
script/Makefile.am Normal file
View File

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

10
script/README.rst Normal file
View File

@@ -0,0 +1,10 @@
fetch-ocsp-response is a Python script which performs OCSP query and
get response. It uses openssl command under the hood. nghttpx uses
it to enable OCSP stapling feature.
fetch-ocsp-response is a translation from original fetch-ocsp-response
written in Perl and which has been developed as part of h2o project
(https://github.com/h2o/h2o).
fetch-ocsp-response is usually installed under $(pkgdatadir), which is
$(prefix)/share/nghttp2.

241
script/fetch-ocsp-response Executable file
View File

@@ -0,0 +1,241 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2015 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.
# This program was translated from the program originally developed by
# h2o project (https://github.com/h2o/h2o), written in Perl. It had
# the following copyright notice:
# Copyright (c) 2015 DeNA Co., Ltd.
#
# 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.
from __future__ import unicode_literals
import argparse
import io
import os
import os.path
import re
import shutil
import subprocess
import sys
import tempfile
# make this program work for both Python 3 and Python 2.
try:
from urllib.parse import urlparse
stdout_bwrite = sys.stdout.buffer.write
except ImportError:
from urlparse import urlparse
stdout_bwrite = sys.stdout.write
def die(msg):
sys.stderr.write(msg)
sys.stderr.write('\n')
sys.exit(255)
def tempfail(msg):
sys.stderr.write(msg)
sys.stderr.write('\n')
sys.exit(os.EX_TEMPFAIL)
def run_openssl(args, allow_tempfail=False):
buf = io.BytesIO()
try:
p = subprocess.Popen(args, stdout=subprocess.PIPE)
except Exception as e:
die('failed to invoke {}:{}'.format(args, e))
try:
while True:
data = p.stdout.read()
if len(data) == 0:
break
buf.write(data)
if p.wait() != 0:
raise Exception('nonzero return code {}'.format(p.returncode))
return buf.getvalue()
except Exception as e:
msg = 'OpenSSL exitted abnormally: {}:{}'.format(args, e)
tempfail(msg) if allow_tempfail else die(msg)
def read_file(path):
with open(path, 'rb') as f:
return f.read()
def write_file(path, data):
with open(path, 'wb') as f:
f.write(data)
def detect_openssl_version(cmd):
return run_openssl([cmd, 'version']).decode('utf-8').strip()
def extract_ocsp_uri(cmd, cert_fn):
# obtain ocsp uri
ocsp_uri = run_openssl(
[cmd, 'x509', '-in', cert_fn, '-noout',
'-ocsp_uri']).decode('utf-8').strip()
if not re.match(r'^https?://', ocsp_uri):
die('failed to extract ocsp URI from {}'.format(cert_fn))
return ocsp_uri
def save_issuer_certificate(issuer_fn, cert_fn):
# save issuer certificate
chain = read_file(cert_fn).decode('utf-8')
m = re.match(
r'.*?-----END CERTIFICATE-----.*?(-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----)',
chain, re.DOTALL)
if not m:
die('--issuer option was not used, and failed to extract issuer certificate from the certificate')
write_file(issuer_fn, (m.group(1) + '\n').encode('utf-8'))
def send_and_receive_ocsp(respder_fn, cmd, cert_fn, issuer_fn, ocsp_uri,
ocsp_host, openssl_version):
# obtain response (without verification)
sys.stderr.write('sending OCSP request to {}\n'.format(ocsp_uri))
args = [
cmd, 'ocsp', '-issuer', issuer_fn, '-cert', cert_fn, '-url', ocsp_uri
]
if openssl_version.lower().startswith('openssl 1.'):
args.extend(['-header', 'Host', ocsp_host])
args.extend(['-noverify', '-respout', respder_fn])
resp = run_openssl(args, allow_tempfail=True)
return resp.decode('utf-8')
def verify_response(cmd, tempdir, issuer_fn, respder_fn):
# verify the response
sys.stderr.write('verifying the response signature\n')
verify_fn = os.path.join(tempdir, 'verify.out')
# try from exotic options
allextra = [
# for comodo
['-VAfile', issuer_fn],
# these options are only available in OpenSSL >= 1.0.2
['-partial_chain', '-trusted_first', '-CAfile', issuer_fn],
# for OpenSSL <= 1.0.1
['-CAfile', issuer_fn],
]
for extra in allextra:
with open(verify_fn, 'wb') as f:
args = [cmd, 'ocsp', '-respin', respder_fn]
args.extend(extra)
p = subprocess.Popen(args, stdout=f, stderr=f)
if p.wait() == 0:
sys.stderr.write('verify OK (used: {})\n'.format(extra))
return True
sys.stderr.write(read_file(verify_fn).decode('utf-8'))
return False
def fetch_ocsp_response(cmd, cert_fn, tempdir, issuer_fn=None):
openssl_version = detect_openssl_version(cmd)
sys.stderr.write(
'fetch-ocsp-response (using {})\n'.format(openssl_version))
ocsp_uri = extract_ocsp_uri(cmd, cert_fn)
ocsp_host = urlparse(ocsp_uri).hostname
if not issuer_fn:
issuer_fn = os.path.join(tempdir, 'issuer.crt')
save_issuer_certificate(issuer_fn, cert_fn)
respder_fn = os.path.join(tempdir, 'resp.der')
resp = send_and_receive_ocsp(
respder_fn, cmd, cert_fn, issuer_fn, ocsp_uri, ocsp_host,
openssl_version)
sys.stderr.write('{}\n'.format(resp))
if not verify_response(cmd, tempdir, issuer_fn, respder_fn):
tempfail('failed to verify the response')
# success
res = read_file(respder_fn)
stdout_bwrite(res)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description=
'''The command issues an OCSP request for given server certificate, verifies the response and prints the resulting DER.''',
epilog=
'''The command exits 0 if successful, or 75 (EX_TEMPFAIL) on temporary error. Other exit codes may be returned in case of hard errors.''')
parser.add_argument(
'--issuer',
metavar='FILE',
help=
'issuer certificate (if omitted, is extracted from the certificate chain)')
parser.add_argument('--openssl',
metavar='CMD',
help='openssl command to use (default: "openssl")',
default='openssl')
parser.add_argument('certificate',
help='path to certificate file to validate')
args = parser.parse_args()
tempdir = None
try:
# Python3.2 has tempfile.TemporaryDirectory, which has nice
# feature to delete its tree by cleanup() function. We have
# to support Python2.7, so we have to do this manually.
tempdir = tempfile.mkdtemp()
fetch_ocsp_response(args.openssl, args.certificate, tempdir,
args.issuer)
finally:
if tempdir:
shutil.rmtree(tempdir)

View File

@@ -25,13 +25,25 @@
#include "HttpServer.h"
#include <sys/stat.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif // HAVE_NETDB_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif // HAVE_UNISTD_H
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif // HAVE_FCNTL_H
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif // HAVE_NETINET_IN_H
#include <netinet/tcp.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif // HAVE_ARPA_INET_H
#include <cassert>
#include <set>
@@ -57,8 +69,9 @@
namespace nghttp2 {
namespace {
const std::string DEFAULT_HTML = "index.html";
const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION;
// TODO could be constexpr
constexpr char DEFAULT_HTML[] = "index.html";
constexpr char NGHTTPD_SERVER[] = "nghttpd nghttp2/" NGHTTP2_VERSION;
} // namespace
namespace {
@@ -87,16 +100,13 @@ template <typename Array> void append_nv(Stream *stream, const Array &nva) {
} // namespace
Config::Config()
: stream_read_timeout(60.), stream_write_timeout(60.),
session_option(nullptr), data_ptr(nullptr), padding(0), num_worker(1),
: stream_read_timeout(60.), stream_write_timeout(60.), 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) {
nghttp2_option_new(&session_option);
nghttp2_option_set_recv_client_preface(session_option, 1);
}
early_response(false), hexdump(false), echo_upload(false) {}
Config::~Config() { nghttp2_option_del(session_option); }
Config::~Config() {}
namespace {
void stream_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
@@ -282,7 +292,7 @@ private:
Stream::Stream(Http2Handler *handler, int32_t stream_id)
: handler(handler), file_ent(nullptr), body_length(0), body_offset(0),
stream_id(stream_id) {
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);
@@ -317,9 +327,13 @@ void on_session_closed(Http2Handler *hd, int64_t session_id) {
namespace {
void settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
int rv;
auto hd = static_cast<Http2Handler *>(w->data);
hd->terminate_session(NGHTTP2_SETTINGS_TIMEOUT);
hd->on_write();
rv = hd->on_write();
if (rv == -1) {
delete_handler(hd);
}
}
} // namespace
@@ -461,7 +475,7 @@ int Http2Handler::read_clear() {
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
if (rv < 0) {
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
std::cerr << "nghttp2_session_mem_recv() returned error: "
<< nghttp2_strerror(rv) << std::endl;
}
@@ -588,7 +602,7 @@ int Http2Handler::read_tls() {
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
if (rv < 0) {
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
std::cerr << "nghttp2_session_mem_recv() returned error: "
<< nghttp2_strerror(rv) << std::endl;
}
@@ -660,20 +674,22 @@ int Http2Handler::on_write() { return write_(*this); }
int Http2Handler::connection_made() {
int r;
r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
sessions_->get_config()->session_option);
r = nghttp2_session_server_new(&session_, sessions_->get_callbacks(), this);
if (r != 0) {
return r;
}
auto config = sessions_->get_config();
std::array<nghttp2_settings_entry, 4> entry;
size_t niv = 1;
entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
entry[0].value = 100;
entry[0].value = config->max_concurrent_streams;
if (sessions_->get_config()->header_table_size >= 0) {
if (config->header_table_size >= 0) {
entry[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
entry[niv].value = sessions_->get_config()->header_table_size;
entry[niv].value = config->header_table_size;
++niv;
}
r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(), niv);
@@ -724,7 +740,7 @@ int Http2Handler::submit_file_response(const std::string &status,
std::string content_length = util::utos(file_length);
std::string last_modified_str;
auto nva = make_array(http2::make_nv_ls(":status", status),
http2::make_nv_ls("server", NGHTTPD_SERVER),
http2::make_nv_ll("server", NGHTTPD_SERVER),
http2::make_nv_ls("content-length", content_length),
http2::make_nv_ll("cache-control", "max-age=3600"),
http2::make_nv_ls("date", sessions_->get_cached_date()),
@@ -754,7 +770,7 @@ int Http2Handler::submit_response(const std::string &status, int32_t stream_id,
auto nva = std::vector<nghttp2_nv>();
nva.reserve(3 + headers.size());
nva.push_back(http2::make_nv_ls(":status", status));
nva.push_back(http2::make_nv_ls("server", NGHTTPD_SERVER));
nva.push_back(http2::make_nv_ll("server", NGHTTPD_SERVER));
nva.push_back(http2::make_nv_ls("date", sessions_->get_cached_date()));
for (auto &nv : headers) {
nva.push_back(http2::make_nv(nv.name, nv.value, nv.no_index));
@@ -767,7 +783,7 @@ 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_ls("server", NGHTTPD_SERVER));
http2::make_nv_ll("server", NGHTTPD_SERVER));
return nghttp2_submit_response(session_, stream_id, nva.data(), nva.size(),
data_prd);
}
@@ -916,6 +932,49 @@ void prepare_status_response(Stream *stream, Http2Handler *hd, int status) {
}
} // namespace
namespace {
void prepare_echo_response(Stream *stream, Http2Handler *hd) {
auto length = lseek(stream->file_ent->fd, 0, SEEK_END);
if (length == -1) {
hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
return;
}
stream->body_length = length;
if (lseek(stream->file_ent->fd, 0, SEEK_SET) == -1) {
hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
return;
}
nghttp2_data_provider data_prd;
data_prd.source.fd = stream->file_ent->fd;
data_prd.read_callback = file_read_callback;
Headers headers;
headers.emplace_back("nghttpd-response", "echo");
headers.emplace_back("content-length", util::utos(length));
hd->submit_response("200", stream->stream_id, headers, &data_prd);
}
} // namespace
namespace {
bool prepare_upload_temp_store(Stream *stream, Http2Handler *hd) {
auto sessions = hd->get_sessions();
char tempfn[] = "/tmp/nghttpd.temp.XXXXXX";
auto fd = mkstemp(tempfn);
if (fd == -1) {
return false;
}
unlink(tempfn);
// Ordinary request never start with "echo:". The length is 0 for
// now. We will update it when we get whole request body.
stream->file_ent = sessions->cache_fd(std::string("echo:") + tempfn,
FileEntry(tempfn, 0, 0, fd));
stream->echo_upload = true;
return true;
}
} // namespace
namespace {
void prepare_redirect_response(Stream *stream, Http2Handler *hd,
const std::string &path, int status) {
@@ -970,8 +1029,14 @@ void prepare_response(Stream *stream, Http2Handler *hd,
url = reqpath;
}
url = util::percentDecode(url.begin(), url.end());
auto sessions = hd->get_sessions();
url = util::percentDecode(std::begin(url), std::end(url));
if (!util::check_path(url)) {
if (stream->file_ent) {
sessions->release_fd(stream->file_ent->path);
stream->file_ent = nullptr;
}
prepare_status_response(stream, hd, 404);
return;
}
@@ -985,12 +1050,18 @@ void prepare_response(Stream *stream, Http2Handler *hd,
}
}
}
std::string path = hd->get_config()->htdocs + url;
if (path[path.size() - 1] == '/') {
path += DEFAULT_HTML;
}
auto sessions = hd->get_sessions();
if (stream->echo_upload) {
assert(stream->file_ent);
prepare_echo_response(stream, hd);
return;
}
auto file_ent = sessions->get_cached_fd(path);
if (file_ent == nullptr) {
@@ -1024,7 +1095,7 @@ void prepare_response(Stream *stream, Http2Handler *hd,
return;
}
if (last_mod_found && buf.st_mtime <= last_mod) {
if (last_mod_found && static_cast<time_t>(buf.st_mtime) <= last_mod) {
close(file);
prepare_status_response(stream, hd, 304);
@@ -1120,7 +1191,7 @@ int hd_on_frame_recv_callback(nghttp2_session *session,
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
remove_stream_read_timeout(stream);
if (!hd->get_config()->early_response) {
if (stream->echo_upload || !hd->get_config()->early_response) {
prepare_response(stream, hd);
}
} else {
@@ -1144,14 +1215,22 @@ int hd_on_frame_recv_callback(nghttp2_session *session,
hd->submit_non_final_response("100", frame->hd.stream_id);
}
if (hd->get_config()->early_response) {
auto &method = http2::get_header(stream->hdidx, http2::HD__METHOD,
stream->headers)->value;
if (hd->get_config()->echo_upload &&
(method == "POST" || method == "PUT")) {
if (!prepare_upload_temp_store(stream, hd)) {
hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
return 0;
}
} else if (hd->get_config()->early_response) {
prepare_response(stream, hd);
}
}
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
remove_stream_read_timeout(stream);
if (!hd->get_config()->early_response) {
if (stream->echo_upload || !hd->get_config()->early_response) {
prepare_response(stream, hd);
}
} else {
@@ -1297,6 +1376,21 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
return 0;
}
if (stream->echo_upload) {
assert(stream->file_ent);
while (len) {
ssize_t n;
while ((n = write(stream->file_ent->fd, data, len)) == -1 &&
errno == EINTR)
;
if (n == -1) {
hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
return 0;
}
len -= n;
data += n;
}
}
// TODO Handle POST
add_stream_read_timeout(stream);

View File

@@ -27,9 +27,9 @@
#include "nghttp2_config.h"
#include <stdint.h>
#include <sys/types.h>
#include <cinttypes>
#include <cstdlib>
#include <string>
@@ -59,10 +59,10 @@ struct Config {
std::string address;
ev_tstamp stream_read_timeout;
ev_tstamp stream_write_timeout;
nghttp2_option *session_option;
void *data_ptr;
size_t padding;
size_t num_worker;
size_t max_concurrent_streams;
ssize_t header_table_size;
uint16_t port;
bool verbose;
@@ -72,6 +72,7 @@ struct Config {
bool error_gzip;
bool early_response;
bool hexdump;
bool echo_upload;
Config();
~Config();
};
@@ -100,6 +101,7 @@ struct Stream {
int64_t body_offset;
int32_t stream_id;
http2::HeaderIndex hdidx;
bool echo_upload;
Stream(Http2Handler *handler, int32_t stream_id);
~Stream();
};

View File

@@ -23,11 +23,21 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif // HAVE_NETDB_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif // HAVE_UNISTD_H
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif // HAVE_FCNTL_H
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif // HAVE_NETINET_IN_H
#include <netinet/tcp.h>
#include <poll.h>
@@ -130,8 +140,6 @@ const char *strframetype(uint8_t type) {
return "GOAWAY";
case NGHTTP2_WINDOW_UPDATE:
return "WINDOW_UPDATE";
case NGHTTP2_EXT_ALTSVC:
return "ALTSVC";
default:
return "UNKNOWN";
}
@@ -362,34 +370,6 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) {
fprintf(outfile, "(window_size_increment=%d)\n",
frame->window_update.window_size_increment);
break;
case NGHTTP2_EXT_ALTSVC: {
print_frame_attr_indent();
auto altsvc = static_cast<const nghttp2_ext_altsvc *>(frame->ext.payload);
fprintf(outfile, "(max-age=%u, port=%u, protocol_id=", altsvc->max_age,
altsvc->port);
if (altsvc->protocol_id_len) {
fwrite(altsvc->protocol_id, altsvc->protocol_id_len, 1, outfile);
}
fprintf(outfile, ", host=");
if (altsvc->host_len) {
fwrite(altsvc->host, altsvc->host_len, 1, outfile);
}
fprintf(outfile, ", origin=");
if (altsvc->origin_len) {
fwrite(altsvc->origin, altsvc->origin_len, 1, outfile);
}
fprintf(outfile, ")\n");
break;
}
default:
break;
}
@@ -429,10 +409,11 @@ int verbose_on_frame_recv_callback(nghttp2_session *session,
int verbose_on_invalid_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame,
uint32_t error_code,
int lib_error_code,
void *user_data) {
print_timer();
fprintf(outfile, " [INVALID; status=%s] recv ", strstatus(error_code));
fprintf(outfile, " [INVALID; error=%s] recv ",
nghttp2_strerror(lib_error_code));
print_frame(PRINT_RECV, frame);
fflush(outfile);
return 0;

View File

@@ -27,9 +27,11 @@
#include "nghttp2_config.h"
#include <stdint.h>
#include <cinttypes>
#include <cstdlib>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif // HAVE_SYS_TIME_H
#include <poll.h>
#include <map>
@@ -49,8 +51,7 @@ int verbose_on_frame_recv_callback(nghttp2_session *session,
int verbose_on_invalid_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame,
uint32_t error_code,
void *user_data);
int lib_error_code, void *user_data);
int verbose_on_frame_send_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data);

View File

@@ -75,10 +75,6 @@ void session_impl::connected(tcp::resolver::iterator endpoint_it) {
socket().set_option(boost::asio::ip::tcp::no_delay(true));
std::copy_n(NGHTTP2_CLIENT_CONNECTION_PREFACE,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN, std::begin(wb_));
wblen_ = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN;
do_write();
do_read();

View File

@@ -268,17 +268,7 @@ int http2_handler::start() {
nghttp2_session_callbacks_set_on_frame_not_send_callback(
callbacks, on_frame_not_send_callback);
nghttp2_option *option;
rv = nghttp2_option_new(&option);
if (rv != 0) {
return -1;
}
auto opt_del = defer(nghttp2_option_del, option);
nghttp2_option_set_recv_client_preface(option, 1);
rv = nghttp2_session_server_new2(&session_, callbacks, this, option);
rv = nghttp2_session_server_new(&session_, callbacks, this);
if (rv != 0) {
return -1;
}

View File

@@ -25,6 +25,10 @@
#ifndef BUFFER_TEST_H
#define BUFFER_TEST_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
namespace nghttp2 {
void test_buffer_write(void);

View File

@@ -26,7 +26,9 @@
#include <config.h>
#endif // HAVE_CONFIG_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif // HAVE_UNISTD_H
#include <getopt.h>
#include <cstdio>

View File

@@ -26,10 +26,14 @@
#include <getopt.h>
#include <signal.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif // HAVE_NETINET_IN_H
#include <netinet/tcp.h>
#include <sys/stat.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif // HAVE_FCNTL_H
#include <cstdio>
#include <cassert>
@@ -150,8 +154,8 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) {
Client::Client(Worker *worker, size_t req_todo)
: worker(worker), ssl(nullptr), next_addr(config.addrs), reqidx(0),
state(CLIENT_IDLE), req_todo(req_todo), req_started(0), req_done(0),
fd(-1) {
state(CLIENT_IDLE), first_byte_received(false), req_todo(req_todo),
req_started(0), req_done(0), fd(-1) {
ev_io_init(&wev, writecb, 0, EV_WRITE);
ev_io_init(&rev, readcb, 0, EV_READ);
@@ -165,6 +169,8 @@ int Client::do_read() { return readfn(*this); }
int Client::do_write() { return writefn(*this); }
int Client::connect() {
record_start_time(&worker->stats);
while (next_addr) {
auto addr = next_addr;
next_addr = next_addr->ai_next;
@@ -412,23 +418,21 @@ int Client::connection_made() {
if (next_proto) {
if (util::check_h2_is_selected(next_proto, next_proto_len)) {
session = make_unique<Http2Session>(this);
} else {
break;
}
#ifdef HAVE_SPDYLAY
else {
auto spdy_version =
spdylay_npn_get_version(next_proto, next_proto_len);
if (spdy_version) {
session = make_unique<SpdySession>(this, spdy_version);
} else {
debug_nextproto_error();
fail();
return -1;
break;
}
#else // !HAVE_SPDYLAY
debug_nextproto_error();
fail();
return -1;
#endif // !HAVE_SPDYLAY
}
#endif // HAVE_SPDYLAY
next_proto = nullptr;
break;
}
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
@@ -469,6 +473,8 @@ int Client::connection_made() {
session->on_connect();
record_connect_time(&worker->stats);
auto nreq =
std::min(req_todo - req_started, (size_t)config.max_concurrent_streams);
@@ -519,6 +525,11 @@ int Client::read_clear() {
if (on_read(buf, nread) != 0) {
return -1;
}
if (!first_byte_received) {
first_byte_received = true;
record_ttfb(&worker->stats);
}
}
return 0;
@@ -641,6 +652,11 @@ int Client::read_tls() {
if (on_read(buf, rv) != 0) {
return -1;
}
if (!first_byte_received) {
first_byte_received = true;
record_ttfb(&worker->stats);
}
}
}
@@ -691,6 +707,18 @@ void Client::record_request_time(RequestStat *req_stat) {
req_stat->request_time = std::chrono::steady_clock::now();
}
void Client::record_start_time(Stats *stat) {
stat->start_times.push_back(std::chrono::steady_clock::now());
}
void Client::record_connect_time(Stats *stat) {
stat->connect_times.push_back(std::chrono::steady_clock::now());
}
void Client::record_ttfb(Stats *stat) {
stat->ttfbs.push_back(std::chrono::steady_clock::now());
}
void Client::signal_write() { ev_io_start(worker->loop, &wev); }
Worker::Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t req_todo, size_t nclients,
@@ -731,70 +759,100 @@ void Worker::run() {
}
namespace {
double within_sd(const std::vector<std::unique_ptr<Worker>> &workers,
const std::chrono::microseconds &mean,
const std::chrono::microseconds &sd, size_t n) {
auto upper = mean.count() + sd.count();
auto lower = mean.count() - sd.count();
size_t m = 0;
for (const auto &w : workers) {
for (const auto &req_stat : w->stats.req_stats) {
if (!req_stat.completed) {
continue;
// Returns percentage of number of samples within mean +/- sd.
template <typename Duration>
double within_sd(const std::vector<Duration> &samples, const Duration &mean,
const Duration &sd) {
if (samples.size() == 0) {
return 0.0;
}
auto t = std::chrono::duration_cast<std::chrono::microseconds>(
req_stat.stream_close_time - req_stat.request_time);
if (lower <= t.count() && t.count() <= upper) {
++m;
auto lower = mean - sd;
auto upper = mean + sd;
auto m = std::count_if(
std::begin(samples), std::end(samples),
[&lower, &upper](const Duration &t) { return lower <= t && t <= upper; });
return (m / static_cast<double>(samples.size())) * 100;
}
} // namespace
namespace {
// Computes statistics using |samples|. The min, max, mean, sd, and
// percentage of number of samples within mean +/- sd are computed.
template <typename Duration>
TimeStat<Duration> compute_time_stat(const std::vector<Duration> &samples) {
if (samples.empty()) {
return {Duration::zero(), Duration::zero(), Duration::zero(),
Duration::zero(), 0.0};
}
// standard deviation calculated using Rapid calculation method:
// http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
double a = 0, q = 0;
size_t n = 0;
int64_t sum = 0;
auto res = TimeStat<Duration>{Duration::max(), Duration::min()};
for (const auto &t : samples) {
++n;
res.min = std::min(res.min, t);
res.max = std::max(res.max, t);
sum += t.count();
auto na = a + (t.count() - a) / n;
q += (t.count() - a) * (t.count() - na);
a = na;
}
}
return (m / static_cast<double>(n)) * 100;
assert(n > 0);
res.mean = Duration(sum / n);
res.sd = Duration(static_cast<typename Duration::rep>(sqrt(q / n)));
res.within_sd = within_sd(samples, res.mean, res.sd);
return res;
}
} // namespace
namespace {
TimeStats
process_time_stats(const std::vector<std::unique_ptr<Worker>> &workers) {
auto ts = TimeStats();
int64_t sum = 0;
size_t n = 0;
size_t nrequest_times = 0, nttfb_times = 0;
for (const auto &w : workers) {
nrequest_times += w->stats.req_stats.size();
nttfb_times += w->stats.ttfbs.size();
}
ts.time_min = std::chrono::microseconds::max();
ts.time_max = std::chrono::microseconds::min();
ts.within_sd = 0.;
std::vector<std::chrono::microseconds> request_times;
request_times.reserve(nrequest_times);
std::vector<std::chrono::microseconds> connect_times, ttfb_times;
connect_times.reserve(nttfb_times);
ttfb_times.reserve(nttfb_times);
// standard deviation calculated using Rapid calculation method:
// http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
double a = 0, q = 0;
for (const auto &w : workers) {
for (const auto &req_stat : w->stats.req_stats) {
if (!req_stat.completed) {
continue;
}
++n;
auto t = std::chrono::duration_cast<std::chrono::microseconds>(
req_stat.stream_close_time - req_stat.request_time);
ts.time_min = std::min(ts.time_min, t);
ts.time_max = std::max(ts.time_max, t);
sum += t.count();
auto na = a + (t.count() - a) / n;
q = q + (t.count() - a) * (t.count() - na);
a = na;
}
}
if (n == 0) {
ts.time_max = ts.time_min = std::chrono::microseconds::zero();
return ts;
request_times.push_back(
std::chrono::duration_cast<std::chrono::microseconds>(
req_stat.stream_close_time - req_stat.request_time));
}
ts.time_mean = std::chrono::microseconds(sum / n);
ts.time_sd = std::chrono::microseconds(
static_cast<std::chrono::microseconds::rep>(sqrt(q / n)));
const auto &stat = w->stats;
// rule out cases where we started but didn't connect or get the
// first byte (errors). We will get connect event before FFTB.
assert(stat.start_times.size() >= stat.ttfbs.size());
assert(stat.connect_times.size() >= stat.ttfbs.size());
for (size_t i = 0; i < stat.ttfbs.size(); ++i) {
connect_times.push_back(
std::chrono::duration_cast<std::chrono::microseconds>(
stat.connect_times[i] - stat.start_times[i]));
ts.within_sd = within_sd(workers, ts.time_mean, ts.time_sd, n);
return ts;
ttfb_times.push_back(
std::chrono::duration_cast<std::chrono::microseconds>(
stat.ttfbs[i] - stat.start_times[i]));
}
}
return {compute_time_stat(request_times), compute_time_stat(connect_times),
compute_time_stat(ttfb_times)};
}
} // namespace
@@ -959,7 +1017,7 @@ Options:
Number of native threads.
Default: )" << config.nthreads << R"(
-i, --input-file=<FILE>
Path of a file with multiple URIs are seperated by EOLs.
Path of a file with multiple URIs are separated by EOLs.
This option will disable URIs getting from command-line.
If '-' is given as <FILE>, URIs will be read from stdin.
URIs are used in this order for each client. All URIs
@@ -1006,6 +1064,14 @@ Options:
} // namespace
int main(int argc, char **argv) {
#ifndef NOTHREADS
ssl::LibsslGlobalLock lock;
#endif // NOTHREADS
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
OPENSSL_config(nullptr);
std::string datafile;
while (1) {
static int flag = 0;
@@ -1202,14 +1268,6 @@ int main(int argc, char **argv) {
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, nullptr);
OPENSSL_config(nullptr);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
#ifndef NOTHREADS
ssl::LibsslGlobalLock lock;
#endif // NOTHREADS
auto ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (!ssl_ctx) {
@@ -1408,7 +1466,7 @@ int main(int argc, char **argv) {
}
}
auto time_stats = process_time_stats(workers);
auto ts = process_time_stats(workers);
// Requests which have not been issued due to connection errors, are
// counted towards req_failed and req_error.
@@ -1441,14 +1499,23 @@ status codes: )" << stats.status[2] << " 2xx, " << stats.status[3] << " 3xx, "
traffic: )" << stats.bytes_total << " bytes total, " << stats.bytes_head
<< " bytes headers, " << stats.bytes_body << R"( bytes data
min max mean sd +/- sd
time for request: )" << std::setw(10)
<< util::format_duration(time_stats.time_min) << " "
<< std::setw(10) << util::format_duration(time_stats.time_max)
<< " " << std::setw(10)
<< util::format_duration(time_stats.time_mean) << " "
<< std::setw(10) << util::format_duration(time_stats.time_sd)
<< std::setw(9) << util::dtos(time_stats.within_sd) << "%"
<< std::endl;
time for request: )" << std::setw(10) << util::format_duration(ts.request.min)
<< " " << std::setw(10) << util::format_duration(ts.request.max)
<< " " << std::setw(10) << util::format_duration(ts.request.mean)
<< " " << std::setw(10) << util::format_duration(ts.request.sd)
<< std::setw(9) << util::dtos(ts.request.within_sd) << "%"
<< "\ntime for connect: " << std::setw(10)
<< util::format_duration(ts.connect.min) << " " << std::setw(10)
<< util::format_duration(ts.connect.max) << " " << std::setw(10)
<< util::format_duration(ts.connect.mean) << " " << std::setw(10)
<< util::format_duration(ts.connect.sd) << std::setw(9)
<< util::dtos(ts.connect.within_sd) << "%"
<< "\ntime to 1st byte: " << std::setw(10)
<< util::format_duration(ts.ttfb.min) << " " << std::setw(10)
<< util::format_duration(ts.ttfb.max) << " " << std::setw(10)
<< util::format_duration(ts.ttfb.mean) << " " << std::setw(10)
<< util::format_duration(ts.ttfb.sd) << std::setw(9)
<< util::dtos(ts.ttfb.within_sd) << "%" << std::endl;
SSL_CTX_free(ssl_ctx);

View File

@@ -28,8 +28,12 @@
#include "nghttp2_config.h"
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif // HAVE_NETDB_H
#include <vector>
#include <string>
@@ -94,13 +98,24 @@ struct RequestStat {
bool completed;
};
struct TimeStats {
// time for request: max, min, mean and sd (standard deviation)
std::chrono::microseconds time_max, time_min, time_mean, time_sd;
// percentage of number of requests inside mean -/+ sd
template <typename Duration> struct TimeStat {
// min, max, mean and sd (standard deviation)
Duration min, max, mean, sd;
// percentage of samples inside mean -/+ sd
double within_sd;
};
struct TimeStats {
// time for request
TimeStat<std::chrono::microseconds> request;
// time for connect
TimeStat<std::chrono::microseconds> connect;
// time to first byte (TTFB)
TimeStat<std::chrono::microseconds> ttfb;
};
enum TimeStatType { STAT_REQUEST, STAT_CONNECT, STAT_FIRST_BYTE };
struct Stats {
Stats(size_t req_todo);
// The total number of requests
@@ -132,6 +147,12 @@ struct Stats {
std::array<size_t, 6> status;
// The statistics per request
std::vector<RequestStat> req_stats;
// time connect starts
std::vector<std::chrono::steady_clock::time_point> start_times;
// time to connect
std::vector<std::chrono::steady_clock::time_point> connect_times;
// time to first byte (TTFB)
std::vector<std::chrono::steady_clock::time_point> ttfbs;
};
enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
@@ -171,6 +192,7 @@ struct Client {
addrinfo *next_addr;
size_t reqidx;
ClientState state;
bool first_byte_received;
// The number of requests this client has to issue.
size_t req_todo;
// The number of requests this client has issued so far.
@@ -215,6 +237,9 @@ struct Client {
void on_stream_close(int32_t stream_id, bool success, RequestStat *req_stat);
void record_request_time(RequestStat *req_stat);
void record_start_time(Stats *stat);
void record_connect_time(Stats *stat);
void record_ttfb(Stats *stat);
void signal_write();
};

View File

@@ -202,12 +202,6 @@ void Http2Session::on_connect() {
extra_connection_window);
}
auto &wb = client_->wb;
assert(wb.wleft() >= NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
wb.write(NGHTTP2_CLIENT_CONNECTION_PREFACE,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
client_->signal_write();
}

View File

@@ -28,7 +28,8 @@
#include "nghttp2_config.h"
#include <sys/types.h>
#include <stdint.h>
#include <cinttypes>
#include "h2load.h"

View File

@@ -25,6 +25,7 @@
#include "h2load_spdy_session.h"
#include <cassert>
#include <cerrno>
#include "h2load.h"
#include "util.h"

View File

@@ -832,7 +832,7 @@ parse_next_link_header_once(const char *first, const char *last) {
static constexpr size_t PLLEN = sizeof(PL) - 1;
if (first + PLLEN == last) {
if (std::equal(PL, PL + PLLEN, first, util::CaseCmp())) {
ok = true;
// ok = true;
// this is the end of sequence
return {{{url_first, url_last}}, last};
}
@@ -842,7 +842,7 @@ parse_next_link_header_once(const char *first, const char *last) {
if (!std::equal(PL, PL + PLLEN, first, util::CaseCmp())) {
break;
}
ok = true;
// ok = true;
// skip including ','
first += PLLEN + 1;
return {{{url_first, url_last}}, first};
@@ -1113,6 +1113,192 @@ bool expect_response_body(const std::string &method, int status_code) {
return method != "HEAD" && expect_response_body(status_code);
}
bool expect_response_body(int method_token, int status_code) {
return method_token != HTTP_HEAD && expect_response_body(status_code);
}
int lookup_method_token(const std::string &name) {
return lookup_method_token(reinterpret_cast<const uint8_t *>(name.c_str()),
name.size());
}
// This function was generated by genmethodfunc.py.
int lookup_method_token(const uint8_t *name, size_t namelen) {
switch (namelen) {
case 3:
switch (name[2]) {
case 'T':
if (util::streq_l("GE", name, 2)) {
return HTTP_GET;
}
if (util::streq_l("PU", name, 2)) {
return HTTP_PUT;
}
break;
}
break;
case 4:
switch (name[3]) {
case 'D':
if (util::streq_l("HEA", name, 3)) {
return HTTP_HEAD;
}
break;
case 'E':
if (util::streq_l("MOV", name, 3)) {
return HTTP_MOVE;
}
break;
case 'K':
if (util::streq_l("LOC", name, 3)) {
return HTTP_LOCK;
}
break;
case 'T':
if (util::streq_l("POS", name, 3)) {
return HTTP_POST;
}
break;
case 'Y':
if (util::streq_l("COP", name, 3)) {
return HTTP_COPY;
}
break;
}
break;
case 5:
switch (name[4]) {
case 'E':
if (util::streq_l("MERG", name, 4)) {
return HTTP_MERGE;
}
if (util::streq_l("PURG", name, 4)) {
return HTTP_PURGE;
}
if (util::streq_l("TRAC", name, 4)) {
return HTTP_TRACE;
}
break;
case 'H':
if (util::streq_l("PATC", name, 4)) {
return HTTP_PATCH;
}
break;
case 'L':
if (util::streq_l("MKCO", name, 4)) {
return HTTP_MKCOL;
}
break;
}
break;
case 6:
switch (name[5]) {
case 'E':
if (util::streq_l("DELET", name, 5)) {
return HTTP_DELETE;
}
break;
case 'H':
if (util::streq_l("SEARC", name, 5)) {
return HTTP_SEARCH;
}
break;
case 'K':
if (util::streq_l("UNLOC", name, 5)) {
return HTTP_UNLOCK;
}
break;
case 'T':
if (util::streq_l("REPOR", name, 5)) {
return HTTP_REPORT;
}
break;
case 'Y':
if (util::streq_l("NOTIF", name, 5)) {
return HTTP_NOTIFY;
}
break;
}
break;
case 7:
switch (name[6]) {
case 'H':
if (util::streq_l("MSEARC", name, 6)) {
return HTTP_MSEARCH;
}
break;
case 'S':
if (util::streq_l("OPTION", name, 6)) {
return HTTP_OPTIONS;
}
break;
case 'T':
if (util::streq_l("CONNEC", name, 6)) {
return HTTP_CONNECT;
}
break;
}
break;
case 8:
switch (name[7]) {
case 'D':
if (util::streq_l("PROPFIN", name, 7)) {
return HTTP_PROPFIND;
}
break;
case 'T':
if (util::streq_l("CHECKOU", name, 7)) {
return HTTP_CHECKOUT;
}
break;
}
break;
case 9:
switch (name[8]) {
case 'E':
if (util::streq_l("SUBSCRIB", name, 8)) {
return HTTP_SUBSCRIBE;
}
break;
case 'H':
if (util::streq_l("PROPPATC", name, 8)) {
return HTTP_PROPPATCH;
}
break;
}
break;
case 10:
switch (name[9]) {
case 'R':
if (util::streq_l("MKCALENDA", name, 9)) {
return HTTP_MKCALENDAR;
}
break;
case 'Y':
if (util::streq_l("MKACTIVIT", name, 9)) {
return HTTP_MKACTIVITY;
}
break;
}
break;
case 11:
switch (name[10]) {
case 'E':
if (util::streq_l("UNSUBSCRIB", name, 10)) {
return HTTP_UNSUBSCRIBE;
}
break;
}
break;
}
return -1;
}
const char *to_method_string(int method_token) {
// we happened to use same value for method with http-parser.
return http_method_str(static_cast<http_method>(method_token));
}
} // namespace http2
} // namespace nghttp2

View File

@@ -109,7 +109,7 @@ nghttp2_nv make_nv(const std::string &name, const std::string &value,
// Create nghttp2_nv from string literal |name| and |value|.
template <size_t N, size_t M>
nghttp2_nv make_nv_ll(const char (&name)[N], const char (&value)[M]) {
constexpr nghttp2_nv make_nv_ll(const char (&name)[N], const char (&value)[M]) {
return {(uint8_t *)name, (uint8_t *)value, N - 1, M - 1,
NGHTTP2_NV_FLAG_NONE};
}
@@ -285,10 +285,19 @@ std::string path_join(const char *base_path, size_t base_pathlen,
// true if response has body, taking into account the request method
// and status code.
bool expect_response_body(const std::string &method, int status_code);
bool expect_response_body(int method_token, int status_code);
// true if response has body, taking into account status code only.
bool expect_response_body(int status_code);
// Looks up method token for method name |name| of length |namelen|.
// Only methods defined in http-parser/http-parser.h (http_method) are
// tokenized. If method name cannot be tokenized, returns -1.
int lookup_method_token(const uint8_t *name, size_t namelen);
int lookup_method_token(const std::string &name);
const char *to_method_string(int method_token);
} // namespace http2
} // namespace nghttp2

View File

@@ -380,6 +380,12 @@ void test_http2_parse_link_header(void) {
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
{
// Error if link header ends with ';'
const char s[] = "<url>;rel=preload;, <url>";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
{
// OK if input ends with ','
const char s[] = "<url>;rel=preload,";
@@ -396,13 +402,13 @@ void test_http2_parse_link_header(void) {
}
{
// Error if url is not enclosed by <>
const char s[] = "url>;rel=preload;";
const char s[] = "url>;rel=preload";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
{
// Error if url is not enclosed by <>
const char s[] = "<url;rel=preload;";
const char s[] = "<url;rel=preload";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}

View File

@@ -25,6 +25,10 @@
#ifndef SHRPX_HTTP2_TEST_H
#define SHRPX_HTTP2_TEST_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
namespace shrpx {
void test_http2_add_header(void);

View File

@@ -26,7 +26,9 @@
#include <config.h>
#endif // HAVE_CONFIG_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif // HAVE_UNISTD_H
#include <getopt.h>
#include <cstdio>
@@ -99,6 +101,11 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) {
return -1;
}
if (!json_is_string(wire)) {
fprintf(stderr, "'wire' value is not string at %d\n", seq);
return -1;
}
auto table_size = json_object_get(obj, "header_table_size");
if (table_size) {

View File

@@ -25,6 +25,10 @@
#ifndef MEMCHUNK_TEST_H
#define MEMCHUNK_TEST_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
namespace nghttp2 {
void test_pool_recycle(void);

View File

@@ -25,9 +25,15 @@
#include "nghttp.h"
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif // HAVE_UNISTD_H
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif // HAVE_FCNTL_H
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif // HAVE_NETINET_IN_H
#include <netinet/tcp.h>
#include <getopt.h>
@@ -83,7 +89,7 @@ enum {
};
namespace {
auto anchors = std::array<Anchor, 5>{{
constexpr auto anchors = std::array<Anchor, 5>{{
{3, 0, 201}, {5, 0, 101}, {7, 0, 1}, {9, 7, 1}, {11, 3, 1},
}};
} // namespace
@@ -948,9 +954,6 @@ int HttpClient::connection_made() {
request_done(stream_user_data);
}
}
// Send connection header here
wb.write(NGHTTP2_CLIENT_CONNECTION_PREFACE,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
// If upgrade succeeds, the SETTINGS value sent with
// HTTP2-Settings header field has already been submitted to
// session object.
@@ -2315,8 +2318,9 @@ Options:
filename is dereived from URI. If URI ends with '/',
'index.html' is used as a filename. Not implemented
yet.
-t, --timeout=<SEC>
Timeout each request after <SEC> seconds.
-t, --timeout=<DURATION>
Timeout each request after <DURATION>. Set 0 to disable
timeout.
-w, --window-bits=<N>
Sets the stream level initial window size to 2**<N>-1.
-W, --connection-window-bits=<N>
@@ -2386,11 +2390,21 @@ Options:
--
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).)" << std::endl;
10 * 1024). Units are K, M and G (powers of 1024).
The <DURATION> argument is an integer and an optional unit (e.g., 1s
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit.)" << std::endl;
}
} // namespace
int main(int argc, char **argv) {
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
OPENSSL_config(nullptr);
bool color = false;
while (1) {
static int flag = 0;
@@ -2472,7 +2486,11 @@ int main(int argc, char **argv) {
++config.verbose;
break;
case 't':
config.timeout = atoi(optarg);
config.timeout = util::parse_duration_with_unit(optarg);
if (config.timeout == std::numeric_limits<double>::infinity()) {
std::cerr << "-t: bad timeout value: " << optarg << std::endl;
exit(EXIT_FAILURE);
}
break;
case 'u':
config.upgrade = true;
@@ -2626,10 +2644,6 @@ int main(int argc, char **argv) {
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, nullptr);
OPENSSL_config(nullptr);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
reset_timer();
return run(argv + optind, argc - optind);
}

View File

@@ -28,8 +28,12 @@
#include "nghttp2_config.h"
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif // HAVE_NETDB_H
#include <string>
#include <vector>

View File

@@ -25,6 +25,10 @@
#ifndef NGHTTP2_GZIP_TEST_H
#define NGHTTP2_GZIP_TEST_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -24,7 +24,9 @@
*/
#include "nghttp2_config.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif // HAVE_UNISTD_H
#include <signal.h>
#include <getopt.h>
@@ -88,6 +90,7 @@ void print_usage(std::ostream &out) {
namespace {
void print_help(std::ostream &out) {
Config config;
print_usage(out);
out << R"(
<PORT> Specify listening port number.
@@ -128,6 +131,10 @@ Options:
-b, --padding=<N>
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
-m, --max-concurrent-streams=<N>
Set the maximum number of the concurrent streams in one
HTTP/2 session.
Default: )" << config.max_concurrent_streams << R"(
-n, --workers=<N>
Set the number of worker threads.
Default: 1
@@ -148,6 +155,8 @@ Options:
--hexdump Display the incoming traffic in hexadecimal (Canonical
hex+ASCII display). If SSL/TLS is used, decrypted data
are used.
--echo-upload
Send back uploaded content if method is POST or PUT.
--version Display version information and exit.
-h, --help Display this help and exit.
@@ -159,6 +168,14 @@ Options:
} // namespace
int main(int argc, char **argv) {
#ifndef NOTHREADS
ssl::LibsslGlobalLock lock;
#endif // NOTHREADS
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
OPENSSL_config(nullptr);
Config config;
bool color = false;
while (1) {
@@ -173,6 +190,7 @@ int main(int argc, char **argv) {
{"header-table-size", required_argument, nullptr, 'c'},
{"push", required_argument, nullptr, 'p'},
{"padding", required_argument, nullptr, 'b'},
{"max-concurrent-streams", required_argument, nullptr, 'm'},
{"workers", required_argument, nullptr, 'n'},
{"error-gzip", no_argument, nullptr, 'e'},
{"no-tls", no_argument, &flag, 1},
@@ -182,9 +200,10 @@ int main(int argc, char **argv) {
{"early-response", no_argument, &flag, 5},
{"trailer", required_argument, &flag, 6},
{"hexdump", no_argument, &flag, 7},
{"echo-upload", no_argument, &flag, 8},
{nullptr, 0, nullptr, 0}};
int option_index = 0;
int c = getopt_long(argc, argv, "DVb:c:d:ehn:p:va:", long_options,
int c = getopt_long(argc, argv, "DVb:c:d:ehm:n:p:va:", long_options,
&option_index);
char *end;
if (c == -1) {
@@ -209,6 +228,16 @@ int main(int argc, char **argv) {
case 'e':
config.error_gzip = true;
break;
case 'm': {
// max-concurrent-streams option
auto n = util::parse_uint(optarg);
if (n == -1) {
std::cerr << "-m: invalid argument: " << optarg << std::endl;
exit(EXIT_FAILURE);
}
config.max_concurrent_streams = n;
break;
}
case 'n':
#ifdef NOTHREADS
std::cerr << "-n: WARNING: Threading disabled at build time, "
@@ -294,6 +323,10 @@ int main(int argc, char **argv) {
// hexdump option
config.hexdump = true;
break;
case 8:
// echo-upload option
config.echo_upload = true;
break;
}
break;
default:
@@ -334,13 +367,6 @@ int main(int argc, char **argv) {
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, nullptr);
OPENSSL_config(nullptr);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
#ifndef NOTHREADS
ssl::LibsslGlobalLock lock;
#endif // NOTHREADS
reset_timer();

View File

@@ -24,7 +24,7 @@
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#endif // HAVE_CONFIG_H
#include <stdio.h>
#include <string.h>

View File

@@ -24,25 +24,41 @@
*/
#include "shrpx.h"
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H
#include <sys/un.h>
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif // HAVE_NETDB_H
#include <signal.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif // HAVE_NETINET_IN_H
#include <netinet/tcp.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif // HAVE_ARPA_INET_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif // HAVE_UNISTD_H
#include <getopt.h>
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif // HAVE_SYSLOG_H
#include <signal.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif // HAVE_LIMITS_H
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif // HAVE_SYS_TIME_H
#include <sys/resource.h>
#include <grp.h>
#include <cinttypes>
#include <limits>
#include <cstdlib>
#include <iostream>
@@ -295,11 +311,15 @@ std::unique_ptr<AcceptHandler> create_acceptor(ConnectionHandler *handler,
fd =
socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
if (fd == -1) {
auto error = errno;
LOG(WARN) << "socket() syscall failed, error=" << error;
continue;
}
#else // !SOCK_NONBLOCK
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (fd == -1) {
auto error = errno;
LOG(WARN) << "socket() syscall failed, error=" << error;
continue;
}
util::make_socket_nonblocking(fd);
@@ -307,6 +327,10 @@ std::unique_ptr<AcceptHandler> create_acceptor(ConnectionHandler *handler,
int val = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
static_cast<socklen_t>(sizeof(val))) == -1) {
auto error = errno;
LOG(WARN)
<< "Failed to set SO_REUSEADDR option to listener socket, error="
<< error;
close(fd);
continue;
}
@@ -315,6 +339,10 @@ std::unique_ptr<AcceptHandler> create_acceptor(ConnectionHandler *handler,
if (family == AF_INET6) {
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
static_cast<socklen_t>(sizeof(val))) == -1) {
auto error = errno;
LOG(WARN)
<< "Failed to set IPV6_V6ONLY option to listener socket, error="
<< error;
close(fd);
continue;
}
@@ -329,11 +357,24 @@ std::unique_ptr<AcceptHandler> create_acceptor(ConnectionHandler *handler,
}
#endif // TCP_DEFER_ACCEPT
if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0 &&
listen(fd, get_config()->backlog) == 0) {
break;
}
// When we are executing new binary, and the old binary did not
// bind privileged port (< 1024) for some reason, binding to those
// ports will fail with permission denied error.
if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
auto error = errno;
LOG(WARN) << "bind() syscall failed, error=" << error;
close(fd);
continue;
}
if (listen(fd, get_config()->backlog) == -1) {
auto error = errno;
LOG(WARN) << "listen() syscall failed, error=" << error;
close(fd);
continue;
}
break;
}
if (!rp) {
@@ -752,7 +793,7 @@ bool conf_exists(const char *path) {
} // namespace
namespace {
const char *DEFAULT_NPN_LIST = "h2,h2-16," NGHTTP2_PROTO_VERSION_ID ","
constexpr char DEFAULT_NPN_LIST[] = "h2,h2-16,h2-14,"
#ifdef HAVE_SPDYLAY
"spdy/3.1,"
#endif // HAVE_SPDYLAY
@@ -760,17 +801,18 @@ const char *DEFAULT_NPN_LIST = "h2,h2-16," NGHTTP2_PROTO_VERSION_ID ","
} // namespace
namespace {
const char *DEFAULT_TLS_PROTO_LIST = "TLSv1.2,TLSv1.1";
constexpr char DEFAULT_TLS_PROTO_LIST[] = "TLSv1.2,TLSv1.1";
} // namespace
namespace {
const char *DEFAULT_ACCESSLOG_FORMAT = "$remote_addr - - [$time_local] "
"\"$request\" $status $body_bytes_sent "
"\"$http_referer\" \"$http_user_agent\"";
constexpr char DEFAULT_ACCESSLOG_FORMAT[] =
R"($remote_addr - - [$time_local] )"
R"("$request" $status $body_bytes_sent )"
R"("$http_referer" "$http_user_agent")";
} // namespace
namespace {
auto DEFAULT_DOWNSTREAM_HOST = "127.0.0.1";
constexpr char DEFAULT_DOWNSTREAM_HOST[] = "127.0.0.1";
int16_t DEFAULT_DOWNSTREAM_PORT = 80;
} // namespace;
@@ -887,6 +929,7 @@ void fill_default_config() {
nghttp2_option_new(&mod_config()->http2_option);
nghttp2_option_set_no_auto_window_update(get_config()->http2_option, 1);
nghttp2_option_set_no_recv_client_magic(get_config()->http2_option, 1);
nghttp2_option_new(&mod_config()->http2_client_option);
nghttp2_option_set_no_auto_window_update(get_config()->http2_client_option,
@@ -912,6 +955,8 @@ void fill_default_config() {
mod_config()->fetch_ocsp_response_file =
strcopy(PKGDATADIR "/fetch-ocsp-response");
mod_config()->no_ocsp = false;
mod_config()->header_field_buffer = 64 * 1024;
mod_config()->max_header_fields = 100;
}
} // namespace
@@ -1326,16 +1371,32 @@ HTTP:
--altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
Specify protocol ID, port, host and origin of
alternative service. <HOST> and <ORIGIN> are optional.
They are advertised in alt-svc header field or HTTP/2
ALTSVC frame. This option can be used multiple times to
specify multiple alternative services. Example:
--altsvc=h2,443
They are advertised in alt-svc header field only in
HTTP/1.1 frontend. This option can be used multiple
times to specify multiple alternative services.
Example: --altsvc=h2,443
--add-request-header=<HEADER>
Specify additional header field to add to request header
set. This option just appends header field and won't
replace anything already set. This option can be used
several times to specify multiple header fields.
Example: --add-request-header="foo: bar"
--add-response-header=<HEADER>
Specify additional header field to add to response
header set. This option just appends header field and
won't replace anything already set. This option can be
used several times to specify multiple header fields.
Example: --add-response-header="foo: bar"
--header-field-buffer=<SIZE>
Set maximum buffer size for incoming HTTP header field
list. This is the sum of header name and value in
bytes.
Default: )"
<< util::utos_with_unit(get_config()->header_field_buffer) << R"(
--max-header-fields=<N>
Set maximum number of incoming HTTP header fields, which
appear in one request or response header field list.
Default: )" << get_config()->max_header_fields << R"(
Debug:
--frontend-http2-dump-request-header=<PATH>
@@ -1386,6 +1447,16 @@ Misc:
} // namespace
int main(int argc, char **argv) {
#ifndef NOTHREADS
nghttp2::ssl::LibsslGlobalLock lock;
#endif // NOTHREADS
// Initialize OpenSSL before parsing options because we create
// SSL_CTX there.
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
OPENSSL_config(nullptr);
Log::set_severity_level(NOTICE);
create_config();
fill_default_config();
@@ -1409,93 +1480,102 @@ int main(int argc, char **argv) {
while (1) {
static int flag = 0;
static option long_options[] = {
{"daemon", no_argument, nullptr, 'D'},
{"log-level", required_argument, nullptr, 'L'},
{"backend", required_argument, nullptr, 'b'},
{"http2-max-concurrent-streams", required_argument, nullptr, 'c'},
{"frontend", required_argument, nullptr, 'f'},
{SHRPX_OPT_DAEMON, no_argument, nullptr, 'D'},
{SHRPX_OPT_LOG_LEVEL, required_argument, nullptr, 'L'},
{SHRPX_OPT_BACKEND, required_argument, nullptr, 'b'},
{SHRPX_OPT_HTTP2_MAX_CONCURRENT_STREAMS, required_argument, nullptr,
'c'},
{SHRPX_OPT_FRONTEND, required_argument, nullptr, 'f'},
{"help", no_argument, nullptr, 'h'},
{"insecure", no_argument, nullptr, 'k'},
{"workers", required_argument, nullptr, 'n'},
{"client-proxy", no_argument, nullptr, 'p'},
{"http2-proxy", no_argument, nullptr, 's'},
{SHRPX_OPT_INSECURE, no_argument, nullptr, 'k'},
{SHRPX_OPT_WORKERS, required_argument, nullptr, 'n'},
{SHRPX_OPT_CLIENT_PROXY, no_argument, nullptr, 'p'},
{SHRPX_OPT_HTTP2_PROXY, no_argument, nullptr, 's'},
{"version", no_argument, nullptr, 'v'},
{"frontend-frame-debug", no_argument, nullptr, 'o'},
{"add-x-forwarded-for", no_argument, &flag, 1},
{"frontend-http2-read-timeout", required_argument, &flag, 2},
{"frontend-read-timeout", required_argument, &flag, 3},
{"frontend-write-timeout", required_argument, &flag, 4},
{"backend-read-timeout", required_argument, &flag, 5},
{"backend-write-timeout", required_argument, &flag, 6},
{"accesslog-file", required_argument, &flag, 7},
{"backend-keep-alive-timeout", required_argument, &flag, 8},
{"frontend-http2-window-bits", required_argument, &flag, 9},
{"pid-file", required_argument, &flag, 10},
{"user", required_argument, &flag, 11},
{SHRPX_OPT_FRONTEND_FRAME_DEBUG, no_argument, nullptr, 'o'},
{SHRPX_OPT_ADD_X_FORWARDED_FOR, no_argument, &flag, 1},
{SHRPX_OPT_FRONTEND_HTTP2_READ_TIMEOUT, required_argument, &flag, 2},
{SHRPX_OPT_FRONTEND_READ_TIMEOUT, required_argument, &flag, 3},
{SHRPX_OPT_FRONTEND_WRITE_TIMEOUT, required_argument, &flag, 4},
{SHRPX_OPT_BACKEND_READ_TIMEOUT, required_argument, &flag, 5},
{SHRPX_OPT_BACKEND_WRITE_TIMEOUT, required_argument, &flag, 6},
{SHRPX_OPT_ACCESSLOG_FILE, required_argument, &flag, 7},
{SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT, required_argument, &flag, 8},
{SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS, required_argument, &flag, 9},
{SHRPX_OPT_PID_FILE, required_argument, &flag, 10},
{SHRPX_OPT_USER, required_argument, &flag, 11},
{"conf", required_argument, &flag, 12},
{"syslog-facility", required_argument, &flag, 14},
{"backlog", required_argument, &flag, 15},
{"ciphers", required_argument, &flag, 16},
{"client", no_argument, &flag, 17},
{"backend-http2-window-bits", required_argument, &flag, 18},
{"cacert", required_argument, &flag, 19},
{"backend-ipv4", no_argument, &flag, 20},
{"backend-ipv6", no_argument, &flag, 21},
{"private-key-passwd-file", required_argument, &flag, 22},
{"no-via", no_argument, &flag, 23},
{"subcert", required_argument, &flag, 24},
{"http2-bridge", no_argument, &flag, 25},
{"backend-http-proxy-uri", required_argument, &flag, 26},
{"backend-no-tls", no_argument, &flag, 27},
{"frontend-no-tls", no_argument, &flag, 29},
{"backend-tls-sni-field", required_argument, &flag, 31},
{"dh-param-file", required_argument, &flag, 33},
{"read-rate", required_argument, &flag, 34},
{"read-burst", required_argument, &flag, 35},
{"write-rate", required_argument, &flag, 36},
{"write-burst", required_argument, &flag, 37},
{"npn-list", required_argument, &flag, 38},
{"verify-client", no_argument, &flag, 39},
{"verify-client-cacert", required_argument, &flag, 40},
{"client-private-key-file", required_argument, &flag, 41},
{"client-cert-file", required_argument, &flag, 42},
{"frontend-http2-dump-request-header", required_argument, &flag, 43},
{"frontend-http2-dump-response-header", required_argument, &flag, 44},
{"http2-no-cookie-crumbling", no_argument, &flag, 45},
{"frontend-http2-connection-window-bits", required_argument, &flag, 46},
{"backend-http2-connection-window-bits", required_argument, &flag, 47},
{"tls-proto-list", required_argument, &flag, 48},
{"padding", required_argument, &flag, 49},
{"worker-read-rate", required_argument, &flag, 50},
{"worker-read-burst", required_argument, &flag, 51},
{"worker-write-rate", required_argument, &flag, 52},
{"worker-write-burst", required_argument, &flag, 53},
{"altsvc", required_argument, &flag, 54},
{"add-response-header", required_argument, &flag, 55},
{"worker-frontend-connections", required_argument, &flag, 56},
{"accesslog-syslog", no_argument, &flag, 57},
{"errorlog-file", required_argument, &flag, 58},
{"errorlog-syslog", no_argument, &flag, 59},
{"stream-read-timeout", required_argument, &flag, 60},
{"stream-write-timeout", required_argument, &flag, 61},
{"no-location-rewrite", no_argument, &flag, 62},
{"backend-http1-connections-per-host", required_argument, &flag, 63},
{"listener-disable-timeout", required_argument, &flag, 64},
{"strip-incoming-x-forwarded-for", no_argument, &flag, 65},
{"accesslog-format", required_argument, &flag, 66},
{"backend-http1-connections-per-frontend", required_argument, &flag,
67},
{"tls-ticket-key-file", required_argument, &flag, 68},
{"rlimit-nofile", required_argument, &flag, 69},
{"tls-ctx-per-worker", no_argument, &flag, 70},
{"backend-response-buffer", required_argument, &flag, 71},
{"backend-request-buffer", required_argument, &flag, 72},
{"no-host-rewrite", no_argument, &flag, 73},
{"no-server-push", no_argument, &flag, 74},
{"backend-http2-connections-per-worker", required_argument, &flag, 76},
{"fetch-ocsp-response-file", required_argument, &flag, 77},
{"ocsp-update-interval", required_argument, &flag, 78},
{"no-ocsp", no_argument, &flag, 79},
{SHRPX_OPT_SYSLOG_FACILITY, required_argument, &flag, 14},
{SHRPX_OPT_BACKLOG, required_argument, &flag, 15},
{SHRPX_OPT_CIPHERS, required_argument, &flag, 16},
{SHRPX_OPT_CLIENT, no_argument, &flag, 17},
{SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS, required_argument, &flag, 18},
{SHRPX_OPT_CACERT, required_argument, &flag, 19},
{SHRPX_OPT_BACKEND_IPV4, no_argument, &flag, 20},
{SHRPX_OPT_BACKEND_IPV6, no_argument, &flag, 21},
{SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE, required_argument, &flag, 22},
{SHRPX_OPT_NO_VIA, no_argument, &flag, 23},
{SHRPX_OPT_SUBCERT, required_argument, &flag, 24},
{SHRPX_OPT_HTTP2_BRIDGE, no_argument, &flag, 25},
{SHRPX_OPT_BACKEND_HTTP_PROXY_URI, required_argument, &flag, 26},
{SHRPX_OPT_BACKEND_NO_TLS, no_argument, &flag, 27},
{SHRPX_OPT_FRONTEND_NO_TLS, no_argument, &flag, 29},
{SHRPX_OPT_BACKEND_TLS_SNI_FIELD, required_argument, &flag, 31},
{SHRPX_OPT_DH_PARAM_FILE, required_argument, &flag, 33},
{SHRPX_OPT_READ_RATE, required_argument, &flag, 34},
{SHRPX_OPT_READ_BURST, required_argument, &flag, 35},
{SHRPX_OPT_WRITE_RATE, required_argument, &flag, 36},
{SHRPX_OPT_WRITE_BURST, required_argument, &flag, 37},
{SHRPX_OPT_NPN_LIST, required_argument, &flag, 38},
{SHRPX_OPT_VERIFY_CLIENT, no_argument, &flag, 39},
{SHRPX_OPT_VERIFY_CLIENT_CACERT, required_argument, &flag, 40},
{SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE, required_argument, &flag, 41},
{SHRPX_OPT_CLIENT_CERT_FILE, required_argument, &flag, 42},
{SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER, required_argument, &flag,
43},
{SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER, required_argument,
&flag, 44},
{SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING, no_argument, &flag, 45},
{SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS, required_argument,
&flag, 46},
{SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS, required_argument,
&flag, 47},
{SHRPX_OPT_TLS_PROTO_LIST, required_argument, &flag, 48},
{SHRPX_OPT_PADDING, required_argument, &flag, 49},
{SHRPX_OPT_WORKER_READ_RATE, required_argument, &flag, 50},
{SHRPX_OPT_WORKER_READ_BURST, required_argument, &flag, 51},
{SHRPX_OPT_WORKER_WRITE_RATE, required_argument, &flag, 52},
{SHRPX_OPT_WORKER_WRITE_BURST, required_argument, &flag, 53},
{SHRPX_OPT_ALTSVC, required_argument, &flag, 54},
{SHRPX_OPT_ADD_RESPONSE_HEADER, required_argument, &flag, 55},
{SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS, required_argument, &flag, 56},
{SHRPX_OPT_ACCESSLOG_SYSLOG, no_argument, &flag, 57},
{SHRPX_OPT_ERRORLOG_FILE, required_argument, &flag, 58},
{SHRPX_OPT_ERRORLOG_SYSLOG, no_argument, &flag, 59},
{SHRPX_OPT_STREAM_READ_TIMEOUT, required_argument, &flag, 60},
{SHRPX_OPT_STREAM_WRITE_TIMEOUT, required_argument, &flag, 61},
{SHRPX_OPT_NO_LOCATION_REWRITE, no_argument, &flag, 62},
{SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST, required_argument, &flag,
63},
{SHRPX_OPT_LISTENER_DISABLE_TIMEOUT, required_argument, &flag, 64},
{SHRPX_OPT_STRIP_INCOMING_X_FORWARDED_FOR, no_argument, &flag, 65},
{SHRPX_OPT_ACCESSLOG_FORMAT, required_argument, &flag, 66},
{SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND, required_argument,
&flag, 67},
{SHRPX_OPT_TLS_TICKET_KEY_FILE, required_argument, &flag, 68},
{SHRPX_OPT_RLIMIT_NOFILE, required_argument, &flag, 69},
{SHRPX_OPT_BACKEND_RESPONSE_BUFFER, required_argument, &flag, 71},
{SHRPX_OPT_BACKEND_REQUEST_BUFFER, required_argument, &flag, 72},
{SHRPX_OPT_NO_HOST_REWRITE, no_argument, &flag, 73},
{SHRPX_OPT_NO_SERVER_PUSH, no_argument, &flag, 74},
{SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER, required_argument,
&flag, 76},
{SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE, required_argument, &flag, 77},
{SHRPX_OPT_OCSP_UPDATE_INTERVAL, required_argument, &flag, 78},
{SHRPX_OPT_NO_OCSP, no_argument, &flag, 79},
{SHRPX_OPT_HEADER_FIELD_BUFFER, required_argument, &flag, 80},
{SHRPX_OPT_MAX_HEADER_FIELDS, required_argument, &flag, 81},
{SHRPX_OPT_ADD_REQUEST_HEADER, required_argument, &flag, 82},
{nullptr, 0, nullptr, 0}};
int option_index = 0;
@@ -1846,6 +1926,18 @@ int main(int argc, char **argv) {
// --no-ocsp
cmdcfgs.emplace_back(SHRPX_OPT_NO_OCSP, "yes");
break;
case 80:
// --header-field-buffer
cmdcfgs.emplace_back(SHRPX_OPT_HEADER_FIELD_BUFFER, optarg);
break;
case 81:
// --max-header-fields
cmdcfgs.emplace_back(SHRPX_OPT_MAX_HEADER_FIELDS, optarg);
break;
case 82:
// --add-request-header
cmdcfgs.emplace_back(SHRPX_OPT_ADD_REQUEST_HEADER, optarg);
break;
default:
break;
}
@@ -1855,13 +1947,6 @@ int main(int argc, char **argv) {
}
}
// Initialize OpenSSL before parsing options because we create
// SSL_CTX there.
OPENSSL_config(nullptr);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
if (conf_exists(get_config()->conf_path.get())) {
if (load_config(get_config()->conf_path.get()) == -1) {
LOG(FATAL) << "Failed to load configuration from "
@@ -1886,10 +1971,6 @@ int main(int argc, char **argv) {
}
}
#ifndef NOTHREADS
auto lock = make_unique<nghttp2::ssl::LibsslGlobalLock>();
#endif // NOTHREADS
if (get_config()->accesslog_syslog || get_config()->errorlog_syslog) {
openlog("nghttpx", LOG_NDELAY | LOG_NOWAIT | LOG_PID,
get_config()->syslog_facility);

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