Compare commits

..

1125 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
5a8d5e5dd9 Update man pages 2015-06-23 23:22:35 +09:00
Tatsuhiro Tsujikawa
9bcb0ffdef Bump up version number to 1.0.4, LT revision to 14:4:0 2015-06-23 23:20:13 +09:00
Tatsuhiro Tsujikawa
1945d0f02a Fix assertion failure in nghttp2_stream.c
This is regression introduced in
46b70c1db8.
2015-06-23 23:04:53 +09:00
Tatsuhiro Tsujikawa
4870edb33d Bump up version number to 1.0.4-DEV 2015-06-23 01:02:48 +09:00
Tatsuhiro Tsujikawa
3abb162969 Update man pages 2015-06-23 00:54:09 +09:00
Tatsuhiro Tsujikawa
4242478f39 Update nghttpx man page template 2015-06-23 00:53:51 +09:00
Tatsuhiro Tsujikawa
4fa2ffe292 Dump up version number to 1.0.3, LT revision to 14:3:0 2015-06-23 00:48:23 +09:00
Tatsuhiro Tsujikawa
301df2a856 src: Disable SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 2015-06-22 23:26:45 +09:00
Tatsuhiro Tsujikawa
f3b7f4140b nghttpx: Clarify origin host for --backend-http1-connection-per-host 2015-06-22 21:09:39 +09:00
Tatsuhiro Tsujikawa
878b873c69 src: Use using instead of typedef 2015-06-21 19:37:50 +09:00
Tatsuhiro Tsujikawa
2ca8cf36b7 util: Use constexpr for ALPN id 2015-06-21 19:34:43 +09:00
Tatsuhiro Tsujikawa
2224b98c9c Remove duplicated dependency validation in nghttp2_session_reprioritize_stream 2015-06-21 16:31:30 +09:00
Tatsuhiro Tsujikawa
a7031da364 Fix bug that idle self-depending PRIORITY is not handled gracefully
Previously, we did not handle PRIORITY frame which depends on itself
and for idle stream.  As a result, nghttp2_session_mem_recv (or
nghttp2_session_recv) returne NGHTTP2_ERR_NOMEM.  The error code was
still misleading.  It was not out of memory, and we failed to insert
hash map because of duplicated key, which was treated as out of
memory.  This commit fixes this issue, by explicitly checking
dependency for incoming PRIORITY for all cases.
2015-06-21 16:02:32 +09:00
Tatsuhiro Tsujikawa
cebfdacc5a src: Use user-defined literals for time (hours and minutes) 2015-06-21 14:51:32 +09:00
Tatsuhiro Tsujikawa
39f89f4a60 src: Use user-defined literals for k, m, and g. 2015-06-21 14:32:47 +09:00
Tatsuhiro Tsujikawa
46b70c1db8 Optimize dependency based priority code to Firefox style tree
While this commit optimizes dependency routine to Firefox style tree,
the other use cases (e.g., linear chain) are also improved
dramatically as well.
2015-06-20 22:11:24 +09:00
Tatsuhiro Tsujikawa
5537503172 Merge branch 'jfcalcerrada-patch-1' 2015-06-20 19:42:09 +09:00
José F. Calcerrada
81cc550eb9 Update README.rst
Typo
2015-06-20 11:02:33 +01:00
Tatsuhiro Tsujikawa
0a6de0d378 nghttp: Perform special handling of IPv6 literal with zone ID as per RFC 6874
This commit adds special handling of IPv6 literal with zone ID as per
RFC 6874.  Still IPv6 link local address does not work, since URI
parser from http-parser does not allow this syntax.
2015-06-18 20:00:02 +09:00
Tatsuhiro Tsujikawa
25d1de0278 nghttp: Print error if all connect() syscall faild 2015-06-18 18:03:25 +09:00
Tatsuhiro Tsujikawa
39eb8b8a6b nghttp: Print error when parsing URI failed 2015-06-18 18:00:24 +09:00
Tatsuhiro Tsujikawa
c050fca177 Merge branch 'vapier-master' 2015-06-18 17:55:50 +09:00
Mike Frysinger
19309823aa enable third-party for asio_lib too
Since this library uses the third-party subdir, make sure we auto-enable
it when that lib is turned on.
2015-06-17 13:29:37 -04:00
Tatsuhiro Tsujikawa
90bcdb0dda Merge branch 'libressl' 2015-06-17 18:27:54 +09:00
Tatsuhiro Tsujikawa
17ec30e45c Mention LibreSSL in README.rst 2015-06-17 18:27:27 +09:00
Tatsuhiro Tsujikawa
07f763be49 fetch-ocsp-response: Support LibreSSL, and include port in ocsp_host 2015-06-17 18:24:57 +09:00
Tatsuhiro Tsujikawa
69119f47c4 src: Support compile with LibreSSL 2015-06-17 18:24:51 +09:00
Tatsuhiro Tsujikawa
b0b792e735 integration: Add tests for x-forwarded-proto header field 2015-06-16 21:31:47 +09:00
Tatsuhiro Tsujikawa
8aab74ad36 nghttpx: Refactor a bit 2015-06-16 21:31:33 +09:00
Tatsuhiro Tsujikawa
f418d1239f nghttpx: Fix bug that XFP header always http on HTTP/2 backend
This commit fixes the bug that x-forwarded-proto header field sent on
HTTP/2 backend always "http", regardless of frontend scheme.
2015-06-16 21:29:47 +09:00
Tatsuhiro Tsujikawa
5b51320dc5 nghttpx: Validate :path on SPDY frontend
Unless method is CONNECT, we require that :path starts with "/",
except for OPTIONS method, which can take "*" as :path (server-wide
OPTIONS request).
2015-06-16 00:09:22 +09:00
Tatsuhiro Tsujikawa
d2e81da9e2 Bump up version number to 1.0.3-DEV 2015-06-12 22:58:14 +09:00
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
63630690a8 Fix make -j3 distcheck error 2015-04-27 23:52:36 +09:00
Tatsuhiro Tsujikawa
dbc613e0d0 Update man pages 2015-04-27 23:09:00 +09:00
Tatsuhiro Tsujikawa
ee354ee6c8 Bump up version number to 0.7.13, LT revision to 13:2:8 2015-04-27 23:06:14 +09:00
Tatsuhiro Tsujikawa
df707df21b Update man pages 2015-04-27 22:36:34 +09:00
Tatsuhiro Tsujikawa
2436acbd23 Update doc about h2load flow control 2015-04-27 22:36:03 +09:00
Tatsuhiro Tsujikawa
b41835f19b h2load: Effectively disable flow control by setting large window size
Previously h2load used default flow control window as described in
HTTP/2 and SPDY specification.  The window size is 64KiB, which is a
bit small, and cannot utilize full server performance when response
size is not too small.  Basically, we do this kind of benchmarking
test to measure server's throughput, and optimal performance.  Smaller
window certainly degrades performance even in local testing because
server is so fast that it has to wait for WINDOW_UPDATE from h2load.
To make default behaviour suitable for peak performance test, we
decided to disable flow control in h2load by setting large enough
window size.

Most users used h2load without -w or -W options, so they were
implicitly throttled by flow control and the result was affected by
that negatively.  Now flow control is disabled by default, the result
may improve depending on the implementations.
2015-04-27 21:23:01 +09:00
Tatsuhiro Tsujikawa
42b2430fe1 Remove unnecessary assignment to item->cycle 2015-04-26 22:32:54 +09:00
Tatsuhiro Tsujikawa
c8f67788e0 Remove unused local variable 2015-04-26 19:47:14 +09:00
Tatsuhiro Tsujikawa
bbdff112a3 Make huffman decoding slightly faster using evil looking macro 2015-04-26 19:39:33 +09:00
Tatsuhiro Tsujikawa
02468b1ca1 Allocate field name and value in the same buffer if indname to dynamic table 2015-04-26 18:43:24 +09:00
Tatsuhiro Tsujikawa
c41f413978 Fix compile error with --enable-werror 2015-04-25 02:23:01 +09:00
Tatsuhiro Tsujikawa
e38dd37667 Update doc 2015-04-25 01:00:02 +09:00
Tatsuhiro Tsujikawa
f2cf2b625c Replace priority queue with linear queue where possible
After reviewing codebase, only queue for DATA frames requires
priorities.  Other frames can be replaced multiple linear queues.
Replacing priority queue with linear queue allows us to simplify
codebase a bit; for example, now nghttp2_session.next_seq is gone.
2015-04-25 00:56:46 +09:00
Tatsuhiro Tsujikawa
eb05777d88 clang-format 2015-04-24 00:17:13 +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
6b0b8ea7d5 Update doc 2015-04-24 00:05:10 +09:00
Tatsuhiro Tsujikawa
c925c32233 Fix bug that promised stream is not reset on temporal failure from on_header_callback 2015-04-23 23:57:39 +09:00
Tatsuhiro Tsujikawa
514558afc0 Allow NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE from nghttp2_on_begin_headers_callback
Since application most likely allocates the stream object in
nghttp2_on_begin_headers_callback, it is desirable to handle its
failure as stream error.  But previously it only signals success or
fatal error.  Submitting RST_STREAM does not prevent
nghttp2_on_header_callback from being invoked.  This commit improves
this situation by allowing NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE from
nghttp2_on_begin_headers_callback.  If that value is returned, library
submits RST_STREAM with error code INTERNAL_ERROR, and
nghttp2_on_header_callback and nghttp2_on_frame_recv_callback for that
frame are not invoked.  Note that for PUSH_PROMISE frame, the stream
to be reset is promised stream.
2015-04-23 23:43:30 +09:00
Tatsuhiro Tsujikawa
b9f602b9a2 Update doc 2015-04-23 21:14:09 +09:00
Tatsuhiro Tsujikawa
1a99bcc860 Merge branch 'travis-container' 2015-04-23 00:00:06 +09:00
Tatsuhiro Tsujikawa
6b8aa36c98 travis: Use gcc-4.9 instead of gcc-4.8 2015-04-22 23:59:23 +09:00
Tatsuhiro Tsujikawa
86ddda5c0e tiny-nghttpd: Fix compile error with travis gcc-4.8 2015-04-22 23:59:23 +09:00
Tatsuhiro Tsujikawa
58b7f4a096 Fix inline error with travis gcc-4.8 2015-04-22 23:59:23 +09:00
Tatsuhiro Tsujikawa
4069aab4f7 travis: Attempt to enable gcc 2015-04-22 23:59:23 +09:00
Tatsuhiro Tsujikawa
5595ba643e travis: Use container-based infrastructure 2015-04-22 23:59:23 +09:00
Tatsuhiro Tsujikawa
77c556901c nghttpx: Increase maximum header field set size 2015-04-22 22:27:48 +09:00
Tatsuhiro Tsujikawa
4928959213 asio: Document asynchronous parameter for listen_and_serve 2015-04-22 22:25:16 +09:00
Tatsuhiro Tsujikawa
a200bb1084 Merge branch 'sunxiaoguang-asio_graceful_shutdown' 2015-04-22 21:43:52 +09:00
Xiaoguang Sun
92a1ca5917 Graceful shutdown and joinable server 2015-04-22 17:51:28 +08:00
Tatsuhiro Tsujikawa
97648d257f mkhufftbl.py: Refactor 2015-04-21 23:48:45 +09:00
Tatsuhiro Tsujikawa
5937b4b6f7 Merge branch 'master' into v1.0.0 2015-04-19 23:13:38 +09:00
Tatsuhiro Tsujikawa
787d40129b Bump up version number to 0.7.13-DEV 2015-04-19 18:32:58 +09:00
Tatsuhiro Tsujikawa
91ad7e150e Never indexing still can use header field name in dynamic table 2015-04-19 18:21:26 +09:00
Tatsuhiro Tsujikawa
28bde2cef0 Update bash_completion 2015-04-19 18:11:11 +09:00
Tatsuhiro Tsujikawa
a9b54a1bfa Update man pages 2015-04-19 18:10:54 +09:00
Tatsuhiro Tsujikawa
80f0e99f00 Bump up version number to 0.7.12, LT revision to 13:1:8 2015-04-19 18:07:57 +09:00
Tatsuhiro Tsujikawa
102ea7c0bb nghttpd: Cache fd
Implement fd caching for static files.  The response body for such as
404 was dynamically generated previously, but now it is written in
temporally file and its fd is cached.  Currently, cache is reference
counted and expired when count becomes 0.  This makes caching is not
effective other than "busy" period, but we don't need this feature if
we are not busy.
2015-04-19 17:38:06 +09:00
Tatsuhiro Tsujikawa
85671a69bf Update doc 2015-04-18 16:49:34 +09:00
Tatsuhiro Tsujikawa
a3fa257473 Fix compile error with Android NDK r10d + --enable-werror 2015-04-17 23:46:19 +09:00
Tatsuhiro Tsujikawa
c4e994c97d nghttp: Add --no-push option to disable server push 2015-04-17 23:35:16 +09:00
Tatsuhiro Tsujikawa
0b41e20d54 nghttp: Show stream ID in statistics output 2015-04-17 23:35:16 +09:00
Tatsuhiro Tsujikawa
cfabce6e70 Update man pages 2015-04-17 23:14:23 +09:00
Tatsuhiro Tsujikawa
b948c5457d Specify program directive 2015-04-17 23:13:42 +09:00
Tatsuhiro Tsujikawa
3bdf78e8af Document nghttp's dependency based priority 2015-04-17 23:06:07 +09:00
Tatsuhiro Tsujikawa
436595df98 nghttp: Remove --dep-idle option
In this commit, we made --dep-idle behaviour by default.  This is
because the previous default behaviour is not reflect current usage of
dependency priority and never will be because of fragility of tree due
to stream closure.
2015-04-17 22:24:06 +09:00
Tatsuhiro Tsujikawa
d3561a63b1 nghttp: Depend on "leader" anchor if js is linked inside head element 2015-04-17 21:25:31 +09:00
Tatsuhiro Tsujikawa
1a12a9b397 Penalize cycle according to effective weight 2015-04-17 21:17:22 +09:00
Tatsuhiro Tsujikawa
57644e0256 Effectively revert 03c4092862
This is not mandated by spec.  Also it may work badly with Firefox
style dependency tree usage.
2015-04-17 21:04:17 +09:00
Tatsuhiro Tsujikawa
7323d4c639 Fix bug that nghttp2_session_set_next_stream_id accepts invalid stream_id 2015-04-17 00:12:47 +09:00
Tatsuhiro Tsujikawa
e23225689f nghttp: Use same priority anchor nodes as Firefox does 2015-04-16 23:56:37 +09:00
Tatsuhiro Tsujikawa
e6ad2eb14f We can assert this 2015-04-16 22:58:25 +09:00
Tatsuhiro Tsujikawa
d4a22edeb3 Don't do fancy stuff yet 2015-04-16 22:58:25 +09:00
Tatsuhiro Tsujikawa
8f4e2d941f Revert accidental change in nghttp.cc 2015-04-16 22:58:25 +09:00
Tatsuhiro Tsujikawa
1a8da6caec Update doc 2015-04-16 21:40:39 +09:00
Tatsuhiro Tsujikawa
dc335b9025 Improve weight handling a bit 2015-04-16 21:38:13 +09:00
Tatsuhiro Tsujikawa
93afbc7d2f Rewrite static header table handling
We rewrite static header table handling in nghttp2_hd.c.  We expand
nghttp2_token to include all static header table entries, and fully
use them in header compression and decompression.  The lookup function
is now located in nghttp2_hd.c.  We add new nghttp2_hd_inflate_hd2()
function to export token value for header name, then we pass it to
nghttp2_http_on_header function, so that we don't have to look up
token there.  We carefully set enum value of token to static table
index, so looking up static table is now O(1), assuming we have token.
2015-04-15 23:58:56 +09:00
Tatsuhiro Tsujikawa
82e2c5bd22 Never index authorization and small cookie header field
nghttp2 library now use Literal Header Field never Indexed for
"authorization" header field and small "cookie" header field,
regardless of nghttp2_nv.flags.
2015-04-15 23:58:56 +09:00
Tatsuhiro Tsujikawa
53bcafb39f Merge branch 'cubicdaiya-alloc-error-handling' 2015-04-15 22:45:10 +09:00
Tatsuhiko Kubo
59f8397659 Use nullptr instead of NULL in C++. 2015-04-15 21:18:39 +09:00
Tatsuhiko Kubo
061732adf0 improved malloc error handlings. 2015-04-15 09:20:45 +09:00
Tatsuhiro Tsujikawa
5c2ca28706 asio: client: Call error_cb on error occurred in do_read and do_write
Fixes GH-207
2015-04-13 21:33:43 +09:00
Tatsuhiro Tsujikawa
a8ea86cfe5 src: constexpr 2015-04-12 17:51:23 +09:00
Tatsuhiro Tsujikawa
7451a73def nghttpx: Don't push resource if link header has non empty loadpolicy 2015-04-12 17:42:25 +09:00
Tatsuhiro Tsujikawa
889e705f35 nghttpx: Add logging for somewhat important events (logs, tickets, and ocsp) 2015-04-11 00:08:28 +09:00
Tatsuhiro Tsujikawa
14d4979c54 Don't install libnghttp2_asio headers if they are disabled 2015-04-10 23:11:40 +09:00
Tatsuhiro Tsujikawa
095bc178f3 nghttpx: Robust HTTP/1 backend CL and TE handling
We should ignore Content-Length and Transfer-Encoding for upgraded
response, and reset content-length if this is a non-final response.
2015-04-10 22:30:20 +09:00
Tatsuhiro Tsujikawa
308738025c nghttpx: Don't set response content-length if HTTP/2 response upgraded 2015-04-10 22:24:17 +09:00
Tatsuhiro Tsujikawa
97366bf55c nghttpx: Set content-length after complete request/response headers 2015-04-10 22:10:51 +09:00
Tatsuhiro Tsujikawa
87cadca3d8 integration: Add HTTP Upgrade test 2015-04-10 21:28:12 +09:00
Tatsuhiro Tsujikawa
9803f92e9c nghttpx: Set Downstream to stream user data on HTTP Upgrade to h2 2015-04-10 02:40:09 +09:00
Tatsuhiro Tsujikawa
cbfa021095 Bump up version number to 0.7.12-DEV 2015-04-10 00:38:17 +09:00
Tatsuhiro Tsujikawa
03746884a4 Update man pages 2015-04-10 00:35:00 +09:00
Tatsuhiro Tsujikawa
6ed710adbd Bump up version number to 0.7.11 2015-04-10 00:31:46 +09:00
Tatsuhiro Tsujikawa
44b4cda200 src: Check return value from nghttp2_session_get_stream_user_data 2015-04-10 00:21:31 +09:00
Tatsuhiro Tsujikawa
69a4f3bf42 nghttp: Consider :authority custom header field for SNI 2015-04-10 00:15:01 +09:00
Tatsuhiro Tsujikawa
5334cb5acc Enable PIE in Dockerfile.android too 2015-04-09 23:34:42 +09:00
Tatsuhiro Tsujikawa
6ca24264e4 Enable PIE for Android build 2015-04-09 23:30:12 +09:00
Tatsuhiro Tsujikawa
37a631278f Merge branch 'alagoutte-misc' 2015-04-09 23:27:15 +09:00
Alexis La Goutte
5c42687759 fix comma at end of enumerator list [-Wpedantic] 2015-04-09 15:44:36 +02:00
Tatsuhiro Tsujikawa
b636e9744f Merge branch 'nghttpx-rewrite-ocsp' 2015-04-09 01:06:13 +09:00
Tatsuhiro Tsujikawa
b873930802 nghttpx: Now ocsp works without threads 2015-04-09 01:03:28 +09:00
Tatsuhiro Tsujikawa
bc53c81616 nghttpx: Replace posix_spawn functions with fork + dup2 + execve
Although posx_spawn is very convenient and useful, we have platform
which don't have these functions (e.g., Android NDK r10d).
2015-04-09 01:03:28 +09:00
Tatsuhiro Tsujikawa
09c485e712 nghttpx: Eliminate 1 second refresh timer 2015-04-09 01:03:28 +09:00
Tatsuhiro Tsujikawa
d247470da2 nghttpx: Rewrite ocsp without thread
Since libev handles SIGCHLD, using waitpid in separate thread to wait
for the completion of fetch-ocsp-response script process is undefined.
This commit rewrite ocsp handling code so that it utilizes libev
ev_child watcher and perform ocsp update without thread.
2015-04-09 01:03:28 +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
4aca2f0b59 Bump up version number to 0.7.11-DEV 2015-04-08 18:07:38 +09:00
Tatsuhiro Tsujikawa
9d711f65f7 Fix make distcheck 2015-04-08 17:55:23 +09:00
Tatsuhiro Tsujikawa
0eab08a7cf Update bash_completion files 2015-04-08 17:38:55 +09:00
Tatsuhiro Tsujikawa
b9c4757d21 Update man pages 2015-04-08 17:36:12 +09:00
Tatsuhiro Tsujikawa
1fcd881395 nghttpx: Document that stderr is redirected to error log file 2015-04-08 17:33:18 +09:00
Tatsuhiro Tsujikawa
cd0564ddfa Bump up version number to 0.7.10, LT revision to 13:0:8 2015-04-08 17:21:40 +09:00
Tatsuhiro Tsujikawa
dd435b51ab nghttpx: Redirect stderr to errorlog file 2015-04-08 16:59:58 +09:00
Tatsuhiro Tsujikawa
ff60cc6b71 integration: Don't send Link header field for resource under /css/ 2015-04-08 16:09:02 +09:00
Tatsuhiro Tsujikawa
80743ddc7b nghttpx: Set promised Downstream as nghttp2 stream user data 2015-04-08 16:07:53 +09:00
Tatsuhiro Tsujikawa
36a8f24559 nghttpx: Finish incomplete incoming request with END_STREAM flag
Previously we send RST_STREAM when we send DATA with END_STREAM flag
set.  With this commit, we also do this when we send HEADERS with
END_STREAM flag set.
2015-04-08 16:07:13 +09:00
Tatsuhiro Tsujikawa
b25e19e876 nghttpx: HTTP backend: Check parser error first so that we can get error msg 2015-04-08 14:39:27 +09:00
Tatsuhiro Tsujikawa
e9660c3558 nghttpx: Fix heap-use-after-free
The bug was introduced by 8c3b379b66.
2015-04-08 13:43:57 +09:00
Tatsuhiro Tsujikawa
8c3b379b66 Pool Memchunk per worker 2015-04-08 00:10:48 +09:00
Tatsuhiro Tsujikawa
b2bb6f1db1 Fix android NDK build error 2015-04-07 21:25:05 +09:00
Tatsuhiro Tsujikawa
59e3783f3f Update manual entry 2015-04-07 00:19:57 +09:00
Tatsuhiro Tsujikawa
d56ecd7414 Add nghttp2_session_consume_{connection,stream} to consume bytes independently
The existing nghttp2_session_consume() affects both connection and
stream level flow control windows.  The new functions only affects
either connection or stream.  There is some interesting use cases.
For example, we may want to pause a stream by not sending
WINDOW_UPDATE, meanwhile we want to continue to process other streams.
In this case, we use nghttp2_session_consume_connection() to tell
library that only connection level window is recovered.  The relevant
discussion: https://code.google.com/p/chromium/issues/detail?id=473259
2015-04-07 00:14:18 +09:00
Tatsuhiro Tsujikawa
ef4e39be55 Update doc 2015-04-06 23:57:48 +09:00
Tatsuhiro Tsujikawa
d42f31ca78 nghttpx: Fix bug that data buffered in SSL object are not read
This is same issue described in https://github.com/h2o/h2o/issues/268.
That is if SSL object has decrypted data buffered inside it, and
application does not read it for some reason (e.g., rate limit), we
have to check the existence of data using SSL_pending.  This is
because buffered data inside SSL is not notified by io watcher.  It is
obvious, but we totally missed it.

nghttpx code normally reads everything until SSL_read returns error
(want-read).  But if rate limit is involved, we stop reading early.
Also in HTTP/1 code, while processing one request, we just read until
buffer is filled up.  In these cases, we may suffer from this problem.

This commit fixes this problem, by performing SSL_pending() and if it
has buffered data and read io watcher is enabled, we feed event using
ev_feed_event().
2015-04-06 22:31:36 +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
Tatsuhiro Tsujikawa
7522d50d1a nghttpd, tiny-nghttpd: No need to check existence of stream
The stream existence is guaranteed by library as of
cc03a12b75.
2015-04-05 23:13:29 +09:00
Tatsuhiro Tsujikawa
cc03a12b75 Don't call nghttp2_send_data_callback if stream has already closed
This is more inline with other callback function invocations where if
stream was closed, they are not invoked.
2015-04-05 12:40:21 +09:00
Tatsuhiro Tsujikawa
9eff511c5e Add nghttp2_send_data_callback to send DATA payload without copying
To avoid buffer copy in nghttp2_data_source_read_callback, this commit
introduces NGHTTP2_DATA_FLAG_NO_COPY and nghttp2_send_data_callback.
By using NGHTTP2_DATA_FLAG_NO_COPY in
nghttp2_data_source_read_callback, application can avoid to copy
application data to given buffer.  Instead, application has to
implement nghttp2_send_data_callback to send complete DATA frame by
itself.  We see noticeable performance increase in nghttpd and
tiny-nghttpd using this new feature.  On the other hand, nghttpx does
not show such difference, probably because buffer copy is not
bottleneck.  Using nghttp2_send_data_callback adds complexity, so it
is recommended to measure the performance to see whether this extra
complexity worth it.
2015-04-04 21:23:50 +09:00
Tatsuhiro Tsujikawa
a96ac6f0a0 Merge branch 'remoe-patch-2' 2015-04-04 01:05:02 +09:00
Tatsuhiro Tsujikawa
213a63d97d Merge branch 'patch-2' of https://github.com/remoe/nghttp2 into remoe-patch-2 2015-04-04 01:04:28 +09:00
Tatsuhiro Tsujikawa
8d4548b9c1 Merge branch 'remoe-patch-1' 2015-04-04 01:03:33 +09:00
Tatsuhiro Tsujikawa
44f2e6ae1d Merge branch 'patch-1' of https://github.com/remoe/nghttp2 into remoe-patch-1 2015-04-04 01:02:52 +09:00
Tatsuhiro Tsujikawa
0cd7d268f3 python: Update url 2015-04-03 21:10:11 +09:00
Remo E
f3a9041851 MSVC: remove of winsock dependency 2015-04-03 12:00:06 +02:00
Remo E
776a8c64f6 "static inline" fix for build with VS2013
"static inline" doesn't build on VS2013:

https://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
2015-04-03 11:55:57 +02:00
Tatsuhiro Tsujikawa
524a1f9498 Update sphinx_rtd_theme 2015-04-01 23:11:07 +09:00
Tatsuhiro Tsujikawa
28cfae162a Update doc 2015-04-01 23:10:01 +09:00
Tatsuhiro Tsujikawa
b0123448a4 python: Add async body generation support 2015-04-01 22:54:31 +09:00
Tatsuhiro Tsujikawa
2d15dca096 Merge branch 'alagoutte-scan-build' 2015-04-01 22:53:56 +09:00
Alexis La Goutte
5f05135d1b Fix some "Value stored to 'stream' is never read" found by Clang Analyzer 2015-04-01 13:03:22 +02:00
Alexis La Goutte
3b6b4ff066 Fix Value stored to 'rv' is never read found by Clang Analyzer 2015-04-01 13:03:22 +02:00
Tatsuhiro Tsujikawa
0c8ec7bfa6 Make sure that nghttp2 license is MIT license 2015-04-01 19:41:32 +09:00
Tatsuhiro Tsujikawa
2c05b8d6f0 Update doc 2015-04-01 01:26:21 +09:00
Tatsuhiro Tsujikawa
45c4187d8f doc: Update .gitignore 2015-04-01 01:19:08 +09:00
Tatsuhiro Tsujikawa
87029e05af doc: Split API reference into smaller fine grained files
Previously API reference is gigantic one rst file and it is a bit hard
to use, especially when browsing similar functions.  This commit
splits API reference into smaller fine grained files.  The macros,
enums, types are now in its own file.  Each API function has its own
file now.  API reference doc is now index to above documentation
files.  The apiref-header.rst is renamed as programmers-guide.rst and
becomes standalone document.
2015-04-01 01:13:10 +09:00
Tatsuhiro Tsujikawa
363914c3f7 Mention OCSP stapling in doc 2015-03-31 23:31:24 +09:00
Tatsuhiro Tsujikawa
1316065c14 python: Fix pseudo-header field ordering bug 2015-03-31 21:53:13 +09:00
Tatsuhiro Tsujikawa
2b6a181bef Dockerfile.android: Update openssl to 1.0.2a 2015-03-31 21:36:53 +09:00
Tatsuhiro Tsujikawa
bf68df9ef4 Merge branch 'wzyboy-patch-dockerfile' 2015-03-31 21:35:32 +09:00
Tatsuhiro Tsujikawa
e7f6089b0e Merge branch 'patch-dockerfile' of https://github.com/wzyboy/nghttp2 into wzyboy-patch-dockerfile 2015-03-31 21:35:10 +09:00
Tatsuhiro Tsujikawa
a1500b0ee3 rst document specific corrections 2015-03-31 21:32:25 +09:00
Tatsuhiro Tsujikawa
14001052f8 Merge branch 'fangdingjun-master' 2015-03-31 21:27:18 +09:00
Tatsuhiro Tsujikawa
95ab54c79d Merge branch 'master' of https://github.com/fangdingjun/nghttp2 into fangdingjun-master 2015-03-31 21:26:46 +09:00
Zhuoyun Wei
5e84f767f0 Improve Dockerfile
- Tell Vim this is a Dockerfile to enable syntax highlight;
- Explicity use Ubuntu "Trusty";
- Remove downloaded file to save space;
- Chain up some RUN commands to generate fewer layers.
2015-03-31 14:21:56 +08:00
Dingjun
c47855085b Update README.rst
fix the typo and add the missing command in sample command
2015-03-31 10:02:22 +08:00
Tatsuhiro Tsujikawa
1442b1bd0a nghttpx: Remove --tls-ctx-per-worker option
--tls-ctx-per-worker option does not work well of OCSP stapling.  Also
it makes session ID useless.
2015-03-31 00:42:21 +09:00
Tatsuhiro Tsujikawa
763293a050 Update man pages 2015-03-31 00:23:12 +09:00
Tatsuhiro Tsujikawa
cc94632b29 src: Use separator "--" to mark start of the footer without ambiguity 2015-03-31 00:21:52 +09:00
Tatsuhiro Tsujikawa
5df770b9c1 h2load: Fix compile error with Android NDK 2015-03-30 23:59:03 +09:00
Tatsuhiro Tsujikawa
4bc9afe20a nghttpx: Add OCSP stapling feature 2015-03-30 23:58:28 +09:00
Dingjun
522faeb24f Update README.rst 2015-03-30 18:39:07 +08:00
fangdingjun
362ff09183 add build notes for windows user under Mingw and Cygwin 2015-03-30 18:29:10 +08:00
Tatsuhiro Tsujikawa
ccea4d42b5 Refactor .gitignore files 2015-03-29 18:40:37 +09:00
Tatsuhiro Tsujikawa
ebbe065716 Update .gitignore 2015-03-29 18:23:55 +09:00
Tatsuhiro Tsujikawa
3a97f21383 Reorder fields 2015-03-29 18:10:38 +09:00
Tatsuhiro Tsujikawa
12ced1cddc nghttpx: Add flag to track connection state in HTTP/1 backend 2015-03-29 01:47:22 +09:00
Tatsuhiro Tsujikawa
3576f20e5a nghttpx: Revert part of 6f58434d89
The reverted part of the change may use not connected socket in HTTP/1
backend.
2015-03-29 01:32:27 +09:00
Tatsuhiro Tsujikawa
7ae6e6b4c5 Exclude num_idle_streams when counting active stream 2015-03-29 00:59:15 +09:00
Tatsuhiro Tsujikawa
a2486daee1 nghttpd: Rename Http2Handler::on_connect as connection_made 2015-03-28 20:21:12 +09:00
Tatsuhiro Tsujikawa
8bf440b89c nghttpx: Rename Http2Session::on_connect as connection_made 2015-03-28 20:19:17 +09:00
Tatsuhiro Tsujikawa
e9cdb9c896 h2load: Remove unused fields in Client class 2015-03-28 20:17:30 +09:00
Tatsuhiro Tsujikawa
c4804ee50b h2load: Remove Client::noop 2015-03-28 20:14:12 +09:00
Tatsuhiro Tsujikawa
95cb284e27 h2load: Rename Client::on_connect as connection_made 2015-03-28 20:13:37 +09:00
Tatsuhiro Tsujikawa
c4ccc376df nghttp: Refactor function names
on_SOMETHING should be used only for I/O callback functions
2015-03-28 20:07:12 +09:00
Tatsuhiro Tsujikawa
6133110386 Remove dependency on libws2_32 on Windows build 2015-03-28 19:58:44 +09:00
Tatsuhiro Tsujikawa
6f58434d89 nghttpx, h2load: Perform write whenever read succeeds 2015-03-28 19:13:14 +09:00
Tatsuhiro Tsujikawa
3fd5d0af79 Don't consider num_active_streams in nghttp2_session_want_write() 2015-03-28 19:00:24 +09:00
Tatsuhiro Tsujikawa
1a6855ea7d Merge branch 'remoe-fix/win_build' 2015-03-28 18:41:03 +09:00
remoe
0312521ac9 - source file list updated
- zlib removed
- build of .def files removed
2015-03-27 21:54:44 +01:00
Tatsuhiro Tsujikawa
67b0e0c2d6 Fix "redefine WIN32" bug 2015-03-28 02:16:37 +09:00
Tatsuhiro Tsujikawa
966e3a1308 Define NGHTTP2_EXTERN macro to export function for Windows build 2015-03-28 01:58:59 +09:00
Tatsuhiro Tsujikawa
fd8f8e2708 Bump up version number to 0.7.10-DEV 2015-03-27 01:06:42 +09:00
Tatsuhiro Tsujikawa
d7fdcbb3d6 Update man pages 2015-03-27 00:37:12 +09:00
Tatsuhiro Tsujikawa
de2c2ad65c src: Update hexdump usage output so that help2rst.py can produce good output 2015-03-27 00:36:19 +09:00
Tatsuhiro Tsujikawa
862a0ee66b Bump up version number to 0.7.9, LT revision to 12:2:7 2015-03-27 00:27:49 +09:00
Tatsuhiro Tsujikawa
c2510a01a5 examples: Place AM_CPPFLAGS first to use in-package header files first
Fixes GH-192
2015-03-26 23:09:39 +09:00
Tatsuhiro Tsujikawa
dc85623060 nghttpx: Fix PUSH_PROMISE header field corruption
Fixes GH-194
2015-03-26 22:52:51 +09:00
Tatsuhiro Tsujikawa
8afbb6ca26 h2load: Fix crash if -t > -c 2015-03-26 19:57:37 +09:00
Tatsuhiro Tsujikawa
ed79637737 h2load: Add -d option to upload data to server 2015-03-26 19:53:42 +09:00
Tatsuhiro Tsujikawa
faa2c4467a Merge branch 'wzyboy-patch-1' 2015-03-25 23:26:20 +09:00
Zhuoyun Wei
c87fae463e Fix comments, too 2015-03-25 21:04:49 +08:00
Zhuoyun Wei
29b4b11e78 Change --spdy-proxy to --http2-proxy 2015-03-25 20:42:12 +08:00
Tatsuhiro Tsujikawa
3b24be3bcd src: Fix compile error with clang-3.6 2015-03-25 01:27:18 +09:00
Tatsuhiro Tsujikawa
ece8289aaf nghttpx: Forward only "trailers" keyword in te when forwarding HTTP/2 backend 2015-03-25 01:20:41 +09:00
Tatsuhiro Tsujikawa
4042ff0fc4 nghttpx: Fix te header field is duplicated when forwarding HTTP/2 backend 2015-03-25 01:17:06 +09:00
Tatsuhiro Tsujikawa
d3d6c5e314 Fix bug that inflater->nvbufs is not reset 2015-03-24 21:54:05 +09:00
Tatsuhiro Tsujikawa
125e32eb56 src: Refactor a bit 2015-03-24 21:45:59 +09:00
Tatsuhiro Tsujikawa
94bf8dcd4e src: Refactor util::hexdump 2015-03-24 21:43:28 +09:00
Tatsuhiro Tsujikawa
89b8039466 nghttp, nghttpd: Add --hexdump option to hexdump incoming traffic
The output format is similar to `hexdump -C`
2015-03-24 02:30:51 +09:00
Tatsuhiro Tsujikawa
72843b33d0 Bump up version number to 0.7.9-DEV 2015-03-24 00:14:56 +09:00
Tatsuhiro Tsujikawa
03e699e013 Update man pages 2015-03-24 00:04:07 +09:00
Tatsuhiro Tsujikawa
fcf99fa8fc Bump up version number to 0.7.8, LT revision to 12:1:7 2015-03-24 00:00:22 +09:00
Tatsuhiro Tsujikawa
661fb2eb0e NULL-terminate name and value in nghttp2_nv
Guaranteeing NULL-termination is very useful when name or value are
used with C functions which requires NULL-terminated string.
2015-03-23 23:25:57 +09:00
Tatsuhiro Tsujikawa
42496d638b Merge branch 'Lekensteyn-documentation' 2015-03-22 17:03:31 +09:00
Peter Wu
c0a6a0a6d1 README.rst: OpenSSL 1.0.2 has already been released
OpenSSL 1.0.2 is already released. Avoid the confusing wording that
seems to suggest that a development version of OpenSSL 1.0.2 provides
ALPN support.
2015-03-21 23:16:56 +01:00
Tatsuhiro Tsujikawa
b7bda783c5 Update doc 2015-03-21 23:09:17 +09:00
Tatsuhiro Tsujikawa
6893608ae2 Use literal instead of computed value in token lookup 2015-03-21 23:03:37 +09:00
Tatsuhiro Tsujikawa
ef913bc929 Validate :path header field
For "http" or "https" URIs, :path header field must start with "/".
The only exception is OPTIONS method, which can contain "*" to
represent system-wide OPTIONS request.
2015-03-21 23:03:37 +09:00
Tatsuhiro Tsujikawa
a5ed70bcfe Merge branch 'rasa-patch-1' 2015-03-21 19:47:27 +09:00
Tatsuhiro Tsujikawa
9bf2ca6916 Merge branch 'patch-1' of https://github.com/rasa/nghttp2 into rasa-patch-1 2015-03-21 19:46:22 +09:00
Ross Smith II
57729d0a23 Removed errant markdown 2015-03-20 08:37:06 -07:00
Tatsuhiro Tsujikawa
e86b81ec10 Merge branch 'icing-h2load-reserver-fix' 2015-03-20 23:32:43 +09:00
mod-h2-dev
076eefbed6 fix for segfault by reserving correct worker count 2015-03-16 17:42:22 +02:00
Ross Smith II
58a735dc68 Update README.rst 2015-03-15 23:42:19 -07:00
Tatsuhiro Tsujikawa
948d4d43d5 Bump up version number to 0.7.8-DEV 2015-03-14 18:53:43 +09:00
Tatsuhiro Tsujikawa
ef581e94bb Update man pages 2015-03-14 18:52:50 +09:00
Tatsuhiro Tsujikawa
ad84af2b2b Bump up version number to 0.7.7 2015-03-14 18:50:12 +09:00
Tatsuhiro Tsujikawa
0e65e1254d Bump up version number to 0.7.7-DEV 2015-03-14 18:36:18 +09:00
Tatsuhiro Tsujikawa
08ec5b3fc0 nghttp: Restore same message displayed when some requests failed 2015-03-14 18:32:53 +09:00
Tatsuhiro Tsujikawa
8c491d5917 Bump up version number to 0.7.6, LT revision to 12:0:7 2015-03-14 18:20:23 +09:00
Tatsuhiro Tsujikawa
4219fe7822 Bump up libnghttp2_asio LT revision to 1:0:0 2015-03-14 18:20:00 +09:00
Tatsuhiro Tsujikawa
d4eb2b2c75 Update doc 2015-03-14 17:59:30 +09:00
Tatsuhiro Tsujikawa
8ea26fddfd Fix compile error "chosen constructor is explicit in copy-initialization" 2015-03-14 15:54:55 +09:00
Tatsuhiro Tsujikawa
98add63cdf nghttp: Treat stream as success if we see END_STREAM from peer 2015-03-14 00:09:10 +09:00
Tatsuhiro Tsujikawa
7b90404072 nghttpx: Omit well-known port from hostport in downstream request 2015-03-14 00:09:10 +09:00
Tatsuhiro Tsujikawa
de0543f684 nghttpx: Refactor a bit 2015-03-14 00:09:10 +09:00
Tatsuhiro Tsujikawa
46e3be7b5b nghttpx: Simplify backend request line construction
It turns out that the cause of complication in backend request line
construction is a absolute-form in HTTP/1 request.  In HTTP/2, we have
separated pseudo-header fields and no problem at all.  In this commit,
we parse request URI in HTTP/1 frontend and extract values from it to
make backend logic simpler.  This patch removes host header field
emission in HTTP/2 backend if :authority is emitted.  It also rewrites
host header field with authority part in absolute-form URI as per RFC
7230.
2015-03-14 00:09:10 +09:00
Tatsuhiro Tsujikawa
7c675b1505 Merge branch 'bagder-fix-trailing-comma' 2015-03-13 23:10:38 +09:00
Daniel Stenberg
d287ea986f nghttp2.h: remove trailing comma last in enum
... since gcc -pedantic warns on it.
2015-03-13 09:05:30 +01:00
Tatsuhiro Tsujikawa
399328cb49 Depend on spdylay >= 1.3.2 for spdylay_session_set_stream_user_data 2015-03-12 01:18:04 +09:00
Tatsuhiro Tsujikawa
d46e50b112 nghttpx: Refactor DownstreamQueue to avoid expensive std::map 2015-03-12 01:13:55 +09:00
Tatsuhiro Tsujikawa
0f87cedc2d nghttpx: Use doubly linked list for dconns_ and streams_ 2015-03-11 21:35:47 +09:00
Tatsuhiro Tsujikawa
d34095cf49 nghttpx: Pin HTTP/2 upstream to one Http2Session to improve performance 2015-03-11 21:14:55 +09:00
Tatsuhiro Tsujikawa
6039bacb1b Update doc 2015-03-11 00:56:15 +09:00
Tatsuhiro Tsujikawa
4877f72a75 nghttpx: Optimize a bit 2015-03-11 00:42:18 +09:00
Tatsuhiro Tsujikawa
274b3a2296 nghttpx: Reset connection check timer on successful write while not checking 2015-03-11 00:27:51 +09:00
Tatsuhiro Tsujikawa
93013f4205 nghttpx: Remove --backend-http2-connection-check option, enable it by default 2015-03-11 00:22:05 +09:00
Tatsuhiro Tsujikawa
5789987ca3 Update doc 2015-03-11 00:16:29 +09:00
Tatsuhiro Tsujikawa
a0524ef05d Fix busy loop 2015-03-11 00:11:51 +09:00
Tatsuhiro Tsujikawa
0e3ae63965 nghttpx: Add --backend-http2-connections-per-worker 2015-03-10 23:43:25 +09:00
Tatsuhiro Tsujikawa
3e14261ebf nghttpx: Setting failure mode in on_connect() may affect other backends 2015-03-10 23:21:48 +09:00
Tatsuhiro Tsujikawa
446de923f3 nghttpx: Support multiple HTTP/2 session per worker
Currently, we use same number of HTTP/2 sessions per worker with given
backend addresses.  New option to specify the number of HTTP/2 session
per worker will follow.
2015-03-10 23:20:21 +09:00
Tatsuhiro Tsujikawa
c5860fc6f4 nghttpx: Support multiple -b option for HTTP/2 backend 2015-03-10 21:54:29 +09:00
Tatsuhiro Tsujikawa
6b714030dd nghttpx: Disable acceptor temporarily when process runs out of fd 2015-03-10 21:25:20 +09:00
Tatsuhiro Tsujikawa
8483225839 nghttpx: Don't rewrite host for CONNECT method 2015-03-10 00:44:35 +09:00
Tatsuhiro Tsujikawa
585af93828 nghttpx: Remove last write/read fields for TLS
It seems that we don't care about this since we don't change buffer
pointer between would-block write/read and next write/read.  Somehow
we decided we need these fields.  As a precaution, we set
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER in SSL_set_mode() for both server
and client contexts.
2015-03-10 00:11:11 +09:00
Tatsuhiro Tsujikawa
41e266181e nghttpx: Attempt to improve HTTP/2 backend connection check
It turns out that writing successfully to network is not enough.
After apparently successful network write, read fails and then we
first know network has been lost (at least my android mobile network).
In this change, we say connection check is successful only when
successful read.  We already send PING in this case, so we just wait
PING ACK with short timeout.  If timeout has expired, drop connection.
Since waiting for PING ACK could degrade performance for fast reliably
connected network, we decided to disable connection check by default.
Use --backend-http2-connection-check to enable it.
2015-03-09 23:37:54 +09:00
Tatsuhiro Tsujikawa
6b7e6166f9 Merge branch 'kazuho-kazuho/issues/177' 2015-03-09 21:11:10 +09:00
Kazuho Oku
2a4f347dbc do not send pseudo-headers when in HTTP/1 2015-03-09 11:40:13 +09:00
Tatsuhiro Tsujikawa
bff5a28d12 Merge branch 'nghttpx-trailer' 2015-03-08 19:32:49 +09:00
Tatsuhiro Tsujikawa
5c31c130bd integration: Add test case for trailer part 2015-03-08 19:31:43 +09:00
Tatsuhiro Tsujikawa
b9d6fff962 nghttpx: Allow accepting trailer part in h1 frontend
Downstream's headers mutation functions have been rewritten to share
code.
2015-03-08 18:39:45 +09:00
Tatsuhiro Tsujikawa
9ffbc45ba6 nghttpx: Allow sending trailer part in h1 backend link 2015-03-08 17:58:00 +09:00
Tatsuhiro Tsujikawa
961f41d7ce nghttp, nghttpd: Add trailer header field when sending trailer part 2015-03-08 17:52:36 +09:00
Tatsuhiro Tsujikawa
928d3e5f3f nghttpx: Allow sending trailer header field 2015-03-08 17:51:52 +09:00
Tatsuhiro Tsujikawa
42eeebc7f6 nghttpx: Add function to send trailer part in h1 frontend 2015-03-08 17:32:38 +09:00
Tatsuhiro Tsujikawa
991baf9e69 nghttpx: Use http2::copy_headers_to_nva in trailer part handling 2015-03-08 17:32:01 +09:00
Tatsuhiro Tsujikawa
6ad63a06b0 nghttpx: Support response trailer part handling in h1 backend 2015-03-08 17:20:38 +09:00
Tatsuhiro Tsujikawa
60c2fe5a2e nghttpx: Support trailer-part in h2 <- h2 path 2015-03-08 16:48:45 +09:00
Tatsuhiro Tsujikawa
41b5077330 nghttpx: Support trailer part in h2 -> h2 path 2015-03-08 16:33:40 +09:00
Tatsuhiro Tsujikawa
d10dc4bb9b nghttp, nghttpd: Clean up around NGHTTP2_DATA_FLAG_NO_END_STREAM 2015-03-08 16:28:23 +09:00
Tatsuhiro Tsujikawa
c4b487be05 asio: Add client::request::write_trailer() 2015-03-07 23:04:31 +09:00
Tatsuhiro Tsujikawa
c976a0fcd1 asio: Add server::response::write_trailer() 2015-03-07 19:26:42 +09:00
Tatsuhiro Tsujikawa
5b5034f19c Merge branch 'trailer' 2015-03-07 18:02:50 +09:00
Tatsuhiro Tsujikawa
dd9e829ee1 Document NGHTTP2_DATA_FLAG_NO_END_STREAM in nghttp2_data_source_read_callback 2015-03-07 17:59:58 +09:00
Tatsuhiro Tsujikawa
80a7523b49 nghttpd: Add --trailer to send trailer header fields 2015-03-07 17:50:03 +09:00
Tatsuhiro Tsujikawa
4c55a2340b nghttp: Add --trailer optiont to send trailer header fields with -d option 2015-03-07 17:45:46 +09:00
Tatsuhiro Tsujikawa
2f2a535113 Add a way to send trailer with nghttp2_submit_request/nghttp2_submit_response
nghttp2_submit_request and nghttp2_submit_response will set
NGHTTP2_FLAG_END_STREAM after all given data is sent (data could be
0).  This means we have no way to send trailers.  In this commit, we
added NGHTTP2_DATA_FLAG_NO_END_STREAM flag.  The application can set
this flag in *data_flags inside nghttp2_data_source_read_callback.  If
NGHTTP2_DATA_FLAG_EOF is set, library automatically set
NGHTTP2_FLAG_END_STREAM.  But if both NGHTTP2_DATA_FLAG_EOF and
NGHTTP2_DATA_FLAG_NO_END_STREAM are set, NGHTTP2_FLAG_END_STREAM will
not set by library.  Then application can use new
nghttp2_submit_trailer() to send trailers.  nghttp2_submit_trailer()
will set NGHTTP2_FLAG_END_STREAM and it is actually thing wrapper of
nghttp2_submit_headers().
2015-03-07 17:09:29 +09:00
Tatsuhiro Tsujikawa
505a300d93 Refuse PUSH_PROMISE while unacked local ENABLE_PUSH is 0
After we sent SETTINGS including ENABLE_PUSH = 0, peer may already
issue PUSH_PROMISE before receiving our SETTINGS and react it to
SETTINGS ACK.  Previously we accept this PUSH_PROMISE.  In this
commit, we check the pending ENABLE_PUSH value and if it means
disabling push, we refuse PUSH_PROMISE with RST_STREAM of error
REFUSED_STREAM.
2015-03-07 16:17:40 +09:00
Tatsuhiro Tsujikawa
4236fa603f Document asio linking 2015-03-07 15:55:47 +09:00
Tatsuhiro Tsujikawa
196d7da53f nghttpx: Use http2::expect_response_body() 2015-03-07 15:50:52 +09:00
Tatsuhiro Tsujikawa
6824319fe6 asio: Link with http-parser 2015-03-07 15:48:38 +09:00
Tatsuhiro Tsujikawa
66d00954a5 asio: Quote ServeMux documents in http2::handle() 2015-03-07 03:17:13 +09:00
Tatsuhiro Tsujikawa
76eb3193ab Update documents using updated libnghttp2_asio API, including client API 2015-03-07 03:12:13 +09:00
Tatsuhiro Tsujikawa
66f5438dc9 asio: Remove eof check in asio-cl.cc 2015-03-07 03:10:37 +09:00
Tatsuhiro Tsujikawa
45164b6761 asio: asio-cl: Shutdown session on closure of first stream 2015-03-07 01:42:01 +09:00
Tatsuhiro Tsujikawa
ceefddd332 asio: Remove unused captured variable 2015-03-07 01:39:25 +09:00
Tatsuhiro Tsujikawa
a043230371 asio: Fix crach in client code 2015-03-07 01:38:59 +09:00
Tatsuhiro Tsujikawa
c2f49fa478 nghttpd: Fix bug that date header field value is not updated 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
fe17a20f84 Update README.rst 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
773b108eeb asio: Add noexcept for move constructor and move assignment operator 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
36a9cbf41f asio: Use large window size for client 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
f8182333b4 asio: Improve date header field precision 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
c3265de625 asio: Remove signal handling from server 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
b24bd3d8cb asio: Use host_service_from_uri in asio-cl2.cc 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
fa21b95274 asio: Provide move constructor and move assignment operator to server::http2 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
5dccc88a7c asio: Add host_service_from_uri() to extract remote address from URI 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
2cadd38b6b asio: Fix path matching in server 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
d7cfe464a2 asio: client::configure_tls_context takes error_code 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
018e9eaf6d asio: Clean up server API to explicitly set error code 2015-03-07 01:10:49 +09:00
Tatsuhiro Tsujikawa
94ca9705ef asio: Rewrite response body handling if response body is not expected 2015-03-06 21:36:40 +09:00
Tatsuhiro Tsujikawa
d6f810d91a examples: Update .gitignore 2015-03-06 03:14:26 +09:00
Tatsuhiro Tsujikawa
d8cf29c202 examples: Add less complicated asio client example 2015-03-06 03:13:22 +09:00
Tatsuhiro Tsujikawa
bf46539d10 python: Fix bug push response header fields are not passed to callback 2015-03-06 03:03:55 +09:00
Tatsuhiro Tsujikawa
2ed47cdd19 Merge branch 'asio-client' 2015-03-06 02:46:06 +09:00
Tatsuhiro Tsujikawa
a3f79232c6 asio: Use proper cookie syntax 2015-03-06 02:41:07 +09:00
Tatsuhiro Tsujikawa
421bf85808 Update README.rst 2015-03-06 02:36:50 +09:00
Tatsuhiro Tsujikawa
05a847b6b8 asio: Use passed URI for request 2015-03-06 02:35:44 +09:00
Tatsuhiro Tsujikawa
1e3afe0646 Update README for asio server example 2015-03-06 02:23:17 +09:00
Tatsuhiro Tsujikawa
38788d707b asio: Don't send response body if it is not expected by status code or method 2015-03-06 02:15:34 +09:00
Tatsuhiro Tsujikawa
44c0d32a1b asio: Fix compile error with gcc 2015-03-06 02:05:01 +09:00
Tatsuhiro Tsujikawa
36aae8c310 asio: Move server::http2 to its own file 2015-03-06 01:58:56 +09:00
Tatsuhiro Tsujikawa
34ac90443f asio: Rename http2::listen as http2::listen_and_serve 2015-03-06 01:54:28 +09:00
Tatsuhiro Tsujikawa
992c14e354 asio: Rename *_reader as *_generator and read_cb as generator_cb 2015-03-06 01:47:55 +09:00
Tatsuhiro Tsujikawa
529fc937dc asio: Document public APIs 2015-03-06 01:41:06 +09:00
Tatsuhiro Tsujikawa
42c174e803 asio: Add example to use timer to achieve delayed response 2015-03-06 01:04:46 +09:00
Tatsuhiro Tsujikawa
05b8d8c5b7 asio: Start sending response header when write_head is called 2015-03-06 00:06:53 +09:00
Tatsuhiro Tsujikawa
a1c937a007 src: Add missing dquote in HTML 2015-03-05 23:34:42 +09:00
Tatsuhiro Tsujikawa
8baec366f0 asio: Make redirect_handler and status_handler part of public API 2015-03-05 23:32:21 +09:00
Tatsuhiro Tsujikawa
c64bb62ffe asio: Make redirect_handler use passed uri as is and percent-encode path part 2015-03-05 23:23:17 +09:00
Tatsuhiro Tsujikawa
6020b727d8 asio: Add signal_write() to server::http2_handler to avoid scattered ifs 2015-03-05 22:00:14 +09:00
Tatsuhiro Tsujikawa
7f04968950 asio: Add dtor to API classes 2015-03-05 21:51:44 +09:00
Tatsuhiro Tsujikawa
ca1f43dfca asio: Export session_impl* from stream rather than delegating everything 2015-03-05 21:48:37 +09:00
Tatsuhiro Tsujikawa
9efb62f40b asio: Move server classes to dedicated files 2015-03-05 21:42:48 +09:00
Tatsuhiro Tsujikawa
f1c7d3edfd asio: Rename server::http2_stream as server::stream 2015-03-05 21:03:03 +09:00
Tatsuhiro Tsujikawa
7ff38eeb2e asio: Start writing on cancel 2015-03-05 03:00:18 +09:00
Tatsuhiro Tsujikawa
e4ce595ebb asio: Add serve_mux class to route incoming requet by path
serve_mux is direct port of ServeMux from go
2015-03-05 02:12:32 +09:00
Tatsuhiro Tsujikawa
8accf3898a asio: Add client::request::resume() member function 2015-03-05 02:12:32 +09:00
Tatsuhiro Tsujikawa
690a1622aa asio: Add const qualifier to client::session member functions 2015-03-05 02:12:32 +09:00
Tatsuhiro Tsujikawa
aaef798566 asio: Add server::response::io_service() 2015-03-05 02:12:32 +09:00
Tatsuhiro Tsujikawa
0753fcd6e5 asio: Add error_code parameter to cancel() 2015-03-05 02:12:32 +09:00
Tatsuhiro Tsujikawa
a14029744c asio:: Add cancel() and on_close() to server::response 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
7e46d0b142 asio: Call signal_write() on session_impl::cancel() 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
726e6c087d asio: server: Move push member function to response object 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
ff0eaf8399 asio: Indicate EOF by passing 0 to the second parameter to data_cb 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
7fb7575f78 asio: read_cb: Use similar semantics with nghttp2_data_source_read_callback 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
44642af227 asio: Remove unused struct header 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
e7d052100c asio: Utilize aggregate or value-initialization for header_value 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
fc2170e488 asio: Use uri_ref in server code 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
0cda2282dd asio: Assign values to uri_ref directly 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
566baab307 asio: asio-cl: Disable peer verification to make development easier
Don't do this in practice
2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
6753b6d61e asio: Use header_map in server code 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
35817876fe asio: Move server API to asio_http2_server.h 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
7d753d779e asio: Fix resource leak (socket not closed) in server code 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
f6f908a541 asio: Make impl() const 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
b0c1986a46 asio: Avoid shared_ptr for request and response 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
9671eaa850 asio: Set stream pointer to request and response in stream ctor 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
062b42918c asio: Remove threaded task runner
This is too complicated and not suitable for event driven server.  We
plan to expose io_service instead.
2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
2fa28e790d asio: Separate client API to asio_http2_client.h 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
76eab3faa0 asio: Pass connected address to connect_cb 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
70ea774f23 asio: Clear up TLS peer verification 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
e15d302985 asio: Introduce uri_ref 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
b2196f215a asio: Use boost::system::error_code for on_error callback 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
8afd75ca47 Make request, response const 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
0676535caf Do async-resove in ctor 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
dd741a58ae Use header_map instead of wrapping it 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
26304546c4 [WIP] Add asio client interface 2015-03-05 02:12:31 +09:00
Tatsuhiro Tsujikawa
838fb33892 Merge branch 'icing-pthread-getspecific' 2015-03-05 02:07:11 +09:00
Tatsuhiro Tsujikawa
7f802b623d Remove thread_local check, since we use pthread_* directly for now 2015-03-05 02:06:31 +09:00
Tatsuhiro Tsujikawa
c2426bc732 Merge branch 'pthread-getspecific' of https://github.com/icing/nghttp2 into icing-pthread-getspecific 2015-03-05 02:04:56 +09:00
Tatsuhiro Tsujikawa
08d0cdfd31 Fix typo 2015-03-04 02:48:20 +09:00
Stefan Eissing
1fd44b1567 replacing thread_local, which does not exist on OS X, with pthread_getspecific call 2015-03-03 17:09:15 +01:00
Tatsuhiro Tsujikawa
a2a9f15307 tests: Use nghttp2_mem instead of raw malloc()/free()
Fixes GH-170
2015-03-03 23:23:43 +09:00
Tatsuhiro Tsujikawa
291c27c940 Merge branch 'acesso-patch-2' 2015-03-03 22:45:46 +09:00
Tatsuhiro Tsujikawa
f86c11f07d Merge branch 'patch-2' of https://github.com/acesso/nghttp2 into acesso-patch-2 2015-03-03 22:45:13 +09:00
Tatsuhiro Tsujikawa
dbd0f032ce Fix -Werror=cast-align error on 32 bit platform
Fixes GH-172
2015-03-03 22:36:24 +09:00
acesso
6a2e6b744f Update shrpx_config.cc
declaration of make_socket_closeonexec need the proper scope here, it was there per request at https://github.com/tatsuhiro-t/nghttp2/pull/142 , not sure why is was removed.
2015-03-02 17:14:09 -03:00
Tatsuhiro Tsujikawa
4de8db523f nghttpx: Check frame type in HTTP/2 backend on_begin_headers_callback 2015-03-02 00:53:48 +09:00
Tatsuhiro Tsujikawa
cf5ac0f363 nghttpx: Fix broken server push after HTTP upgrade 2015-03-01 11:03:48 +09:00
Tatsuhiro Tsujikawa
185ebd7b79 nghttpx: Fix crash when upgrading HTTP/2 failed 2015-03-01 10:11:45 +09:00
Tatsuhiro Tsujikawa
38153e0f6e Update README.rst 2015-02-27 01:03:37 +09:00
Tatsuhiro Tsujikawa
f36f3ae1fa Bump up version number to 0.7.6-DEV 2015-02-27 01:01:29 +09:00
Tatsuhiro Tsujikawa
94d6320376 Update man pages 2015-02-27 00:57:13 +09:00
Tatsuhiro Tsujikawa
f3a0ab6552 nghttpd: Fix help output so that it can be generated in man/html nicely 2015-02-27 00:56:26 +09:00
Tatsuhiro Tsujikawa
568b744374 Bump up version number to 0.7.5, LT revision to 11:0:6 2015-02-27 00:53:43 +09:00
Tatsuhiro Tsujikawa
00e687506e COPYING: Add 2015 to copyright year 2015-02-27 00:49:36 +09:00
Tatsuhiro Tsujikawa
1c2c5bdd05 Revert "nghttpx: Add missing Downstream::end_upload_data() call in HTTP/2 and SPDY"
This reverts commit ef090d425e.
2015-02-27 00:32:48 +09:00
Tatsuhiro Tsujikawa
30acb41561 Merge branch 'bcard-bcard/address-nghttp2-server' 2015-02-27 00:04:58 +09:00
Tatsuhiro Tsujikawa
3715a89655 Merge branch 'bcard/address-nghttp2-server' of https://github.com/bcard/nghttp2 into bcard-bcard/address-nghttp2-server
Conflicts:
	src/nghttp.cc
2015-02-27 00:02:45 +09:00
Tatsuhiro Tsujikawa
ef090d425e nghttpx: Add missing Downstream::end_upload_data() call in HTTP/2 and SPDY
This ensures that all frontend code calls
Downstream::end_upload_data() when request was all received.
2015-02-26 23:50:21 +09:00
Tatsuhiro Tsujikawa
e1bb06d8ab nghttpx: Remove unused error check 2015-02-26 23:46:42 +09:00
Tatsuhiro Tsujikawa
d1793e3b5a Add missing entry to nghttp2_strerror() 2015-02-26 23:04:38 +09:00
Brian Card
1bdf664f4d Changing signature of numeric_name from numeric_name(addrinfo *addr)
to numeric_name(const struct sockaddr *sa, socklen_t salen) to remove
dependency on addrinfo struct.
2015-02-26 08:59:25 -05:00
Tatsuhiro Tsujikawa
05b8901d69 Call on_invalid_frame_recv_callback on bad HTTP messaging 2015-02-26 22:59:07 +09:00
Tatsuhiro Tsujikawa
1c0d617742 nghttpx: Rename WorkerConfig as LogConfig
This is a sign that we only use thread-local storage for logging only.
2015-02-26 00:02:29 +09:00
Tatsuhiro Tsujikawa
b161dfe573 nghttpx: Move graceful_shutdown flag from WorkerConfig to Worker
A part of an effort to eliminate thread_local WorkerConfig
2015-02-25 22:53:53 +09:00
Tatsuhiro Tsujikawa
c6d019da5f Update doc 2015-02-24 23:53:12 +09:00
Brian Card
b773d63b92 Moving nghttp's numeric_name function to util.cc and using this to generate the address name in HttpServer.cc 2015-02-24 09:50:18 -05:00
Tatsuhiro Tsujikawa
66b6787fbe src: Use "sensitive" to indicate "never indexed" header field 2015-02-24 23:12:12 +09:00
Tatsuhiro Tsujikawa
f2a498e3c4 Disallow upper-cased header field name 2015-02-24 18:45:59 +09:00
Tatsuhiro Tsujikawa
1a2bccd71c nghttpx: Share nghttp2_session_callbacks between objects 2015-02-24 15:21:10 +09:00
Tatsuhiro Tsujikawa
8417275368 nghttpx: Code cleanup 2015-02-24 15:11:09 +09:00
Tatsuhiro Tsujikawa
1646352f3c Update doc 2015-02-24 14:48:58 +09:00
Tatsuhiro Tsujikawa
c98cf045d6 nghttpx: Use omit minor version in case of HTTP/2 in via header and accesslog 2015-02-24 14:43:01 +09:00
Brian Card
933b9636e5 removing additional space after option variable 2015-02-23 07:15:54 -05:00
Brian Card
d10bce3dc8 fixing formatiing 2015-02-23 07:13:03 -05:00
Tatsuhiro Tsujikawa
814c7e68e0 Ignore regular headers if it includes illegal characters.
This commit only affects the library behaviour unless
nghttp2_option_set_no_http_messaging() is used.

We like strict validation against header field name and value against
RFC 7230, but we have already so much web sites and libraries in
public internet which do not obey these rules.  Simply just
terminating stream because of this may break web sites and it is too
disruptive.  So we decided that we should be conservative here so
those header fields containing illegal characters are just ignored.
But we are conservative only for regular headers.  We are strict for
pseudo headers since it is new to HTTP/2 and new implementations
should know the rules better.
2015-02-22 23:13:27 +09:00
Tatsuhiro Tsujikawa
c5c58ccd78 Add note for nghttpx UNIX domain socket support 2015-02-22 18:23:09 +09:00
Tatsuhiro Tsujikawa
1468bcd7b4 Update man pages 2015-02-22 18:10:55 +09:00
Tatsuhiro Tsujikawa
8b533e19bb nghttpx: Remove option name from unix path sample since it is a bit strange 2015-02-22 18:09:37 +09:00
Tatsuhiro Tsujikawa
a55a080b9c Update man pages 2015-02-22 18:02:57 +09:00
Tatsuhiro Tsujikawa
df32a534fc nghttpx: Rename ConnectionHandler::acceptor4_ as acceptor_
This change is motivated by that fact that we use it for UNIX domain
socket as well as IPv4.
2015-02-22 17:59:50 +09:00
Tatsuhiro Tsujikawa
e583a25a8b nghttpx: Fix error found by coverity scan 2015-02-22 17:53:12 +09:00
Tatsuhiro Tsujikawa
4430b06c71 Add parentheses around macro parameters 2015-02-22 17:43:14 +09:00
Tatsuhiro Tsujikawa
6051ff63e0 tests: Fix compile error with gcc-4.7 2015-02-22 17:43:00 +09:00
Tatsuhiro Tsujikawa
da2376effd nghttpx: Add host_unix field to DownstreamAddr to tell it is UNIX domain sock 2015-02-22 17:25:23 +09:00
Tatsuhiro Tsujikawa
0c4ae3dea5 nghttpx: Support UNIX domain socket on frontend
This commit also fixes environment variables used to tell inherited
file descriptors to new binary are stacked up each time new binary is
executed.
2015-02-22 17:25:23 +09:00
Tatsuhiro Tsujikawa
e457c9a414 src: Add util::strieq_l 2015-02-22 15:32:48 +09:00
Tatsuhiro Tsujikawa
997f9233bc nghttpx: Support UNIX domain socket in backend connections 2015-02-22 12:27:51 +09:00
Tatsuhiro Tsujikawa
49781da8f0 nghttpx: Don't need to const_cast to sockaddr* 2015-02-22 12:06:31 +09:00
Tatsuhiro Tsujikawa
7f9de007d0 nghttpx: Fix crash in http/1 backend when backend returns more bytes than CL
This is typically programming mistake that we did not check return
value before doing another.
2015-02-21 21:17:52 +09:00
Tatsuhiro Tsujikawa
c506386997 Add libxml2.m4 for convenience to build nghttp2 from git repo easily 2015-02-21 21:06:19 +09:00
Tatsuhiro Tsujikawa
3144f7de72 asio-sv2: Fix compile error with OS X
Use struct stat.st_mtime instead of st_mtim which seems to be Linux
specific.
2015-02-21 21:02:40 +09:00
Tatsuhiro Tsujikawa
c84a190ac7 nghttpx: Use return 0 instead of break for readability 2015-02-21 17:08:03 +09:00
Tatsuhiro Tsujikawa
a26a597453 nghttpx: Cast configuration value to rlim_t to avoid compile error on 32bit 2015-02-21 16:57:02 +09:00
Tatsuhiro Tsujikawa
20a689ef44 Update doc 2015-02-21 16:53:41 +09:00
Tatsuhiro Tsujikawa
62928ddbcd python: Remove validation offered by nghttp2 lib 2015-02-21 00:20:30 +09:00
Tatsuhiro Tsujikawa
04ef26473a asio-lib: Increase output buffer size 2015-02-21 00:08:10 +09:00
Tatsuhiro Tsujikawa
7897f5b94b asio-lib: Remove validation offered by nghttp2 lib 2015-02-21 00:06:05 +09:00
Tatsuhiro Tsujikawa
9302e3edf4 src: Use util::streq_l to compare against string literal 2015-02-20 23:57:40 +09:00
Tatsuhiro Tsujikawa
ab93a700ce src: Announce h2 ALPN 2015-02-20 23:50:17 +09:00
Tatsuhiro Tsujikawa
2fc1dd77d2 Update doc 2015-02-20 23:30:57 +09:00
Tatsuhiro Tsujikawa
e45c523dc7 Add nghttp2_option_set_no_http_messaging() API function
This API function with nonzero |val| parameter disables HTTP Messaging
validation in nghttp2 library, so that application can use nghttp2
library for non-HTTP use.
2015-02-20 23:26:56 +09:00
Tatsuhiro Tsujikawa
b3846d6c27 Rename NGHTTP2_OPTMASK_NO_HTTP_SEMANTICS with NGHTTP2_OPTMASK_NO_HTTP_MESSAGING 2015-02-20 23:07:48 +09:00
Tatsuhiro Tsujikawa
dec115cff3 Document HTTP Messaging enforcement performed by nghttp2 library 2015-02-20 23:06:14 +09:00
Tatsuhiro Tsujikawa
fe84ec5e8b tiny-nghttpd: Add token lookup for slight optimization 2015-02-20 21:50:02 +09:00
Tatsuhiro Tsujikawa
b39aa43537 Use C-style comment 2015-02-20 21:49:47 +09:00
Tatsuhiro Tsujikawa
2216fd2bc1 tiny-nghttpd: Remove validations offered by lib 2015-02-20 20:58:11 +09:00
Tatsuhiro Tsujikawa
83d9ee1fd1 Update http-parser 2015-02-20 19:51:41 +09:00
Tatsuhiro Tsujikawa
4424cf5b65 nghttpx: Fix 1 second delay in HTTP/2 backend connection 2015-02-20 19:48:35 +09:00
Tatsuhiro Tsujikawa
00a83a44b4 nghttp: Simplify checking 2015-02-20 19:35:54 +09:00
Tatsuhiro Tsujikawa
83952ef0af Insert '_' before header name nghttp2_http_flag to consistent with token 2015-02-20 19:30:34 +09:00
Tatsuhiro Tsujikawa
3dbd2d31bd Early return after :method is seen 2015-02-20 19:26:34 +09:00
Tatsuhiro Tsujikawa
f755ea3894 nghttpx: Simplify HttpsUpstream::on_read 2015-02-20 19:24:48 +09:00
Tatsuhiro Tsujikawa
50c4aa061f nghttpx: Response with 503 when re-submission to backend failed 2015-02-20 19:23:52 +09:00
Tatsuhiro Tsujikawa
6657966334 nghttpx: HttpsUpdatem: Don't send error_page if response state is MSG_COMPLETE 2015-02-20 01:25:18 +09:00
Tatsuhiro Tsujikawa
512aa8942a nghttp: Fix -H does not work with -u upgrade request 2015-02-20 01:16:49 +09:00
Tatsuhiro Tsujikawa
b371331297 Merge branch 'enforce-http-semantics' 2015-02-20 01:02:06 +09:00
Tatsuhiro Tsujikawa
489b4f307c nghttp, nghttpd, nghttpx: Remove validations libnghttp2 offers 2015-02-20 01:01:10 +09:00
Tatsuhiro Tsujikawa
b157d4ebb2 Validate HTTP semantics by default
Previously we did not check HTTP semantics and it is left out for
application.  Although checking is relatively easy, but they are
scattered and error prone.  We have implemented these checks in our
applications and also feel they are tedious.  To make application
development a bit easier, this commit adds basic HTTP semantics
validation to library code.  We do following checks:

server:

* HEADERS is either request header or trailer header.  Other type of
header is disallowed.

client:

* HEADERS is either zero or more non-final response header or final
  response header or trailer header.  Other type of header is
  disallowed.

For both:

* Check mandatory pseudo header fields.
* Make sure that content-length matches the amount of DATA we
  received.

If validation fails, RST_STREAM of type PROTOCOL_ERROR is issued.
2015-02-20 01:01:10 +09:00
Tatsuhiro Tsujikawa
9845729709 nghttp: Update resource timing terminology according to Resource Timing TR 2015-02-18 00:45:52 +09:00
Tatsuhiro Tsujikawa
dbfc02cba0 nghttpx: Issue RST_STREAM if END_STREAM seen without final response 2015-02-18 00:36:49 +09:00
Tatsuhiro Tsujikawa
d1a1e882bf nghttpx: Fix request re-submission bug in HTTP/2 backend 2015-02-17 23:15:53 +09:00
Tatsuhiro Tsujikawa
799778af69 Revert "nghttpx: Fix request resubmit bug on HTTP/2 backend connection check"
This reverts commit d45f5a51e4.
2015-02-17 22:28:03 +09:00
Tatsuhiro Tsujikawa
d45f5a51e4 nghttpx: Fix request resubmit bug on HTTP/2 backend connection check 2015-02-17 21:50:32 +09:00
Tatsuhiro Tsujikawa
e479abc4ab Update README.rst 2015-02-15 16:48:37 +09:00
Tatsuhiro Tsujikawa
37706c2930 Untabify README.rst 2015-02-15 16:38:42 +09:00
Tatsuhiro Tsujikawa
bb856fe4c5 nghttp: Fix unaligned field output in --stat 2015-02-15 16:24:04 +09:00
Tatsuhiro Tsujikawa
f4c0a243e7 Bump up version number to 0.7.5-DEV 2015-02-15 13:14:07 +09:00
Tatsuhiro Tsujikawa
ba9ea1831c Update man pages 2015-02-15 13:07:23 +09:00
Tatsuhiro Tsujikawa
c7126663df Bump up version number to 0.7.4, LT revision to 10:0:5 2015-02-15 13:06:35 +09:00
Tatsuhiro Tsujikawa
aa1339d9c0 Update README.rst 2015-02-15 13:00:19 +09:00
Tatsuhiro Tsujikawa
f87aaf1fbf nghttp: Show '*' to mark pushed resources in --stat output 2015-02-15 12:46:00 +09:00
Tatsuhiro Tsujikawa
685dabc2d6 nghttp: Don't request already pushed resources 2015-02-15 12:36:18 +09:00
Tatsuhiro Tsujikawa
4cafdb7670 nghttp: Show received size in --stat 2015-02-15 12:36:13 +09:00
Tatsuhiro Tsujikawa
a8889971db doc: Make html rule html-local 2015-02-15 12:18:13 +09:00
Tatsuhiro Tsujikawa
1fbaae837c Sort sphix theme files 2015-02-15 12:13:36 +09:00
Tatsuhiro Tsujikawa
e8c294b701 Add bash_completion files for nghttp, nghttpd, nghttpx and h2load 2015-02-15 12:05:27 +09:00
Tatsuhiro Tsujikawa
9c30211da9 Ignore all incoming bytes when first SETTINGS is not received 2015-02-15 01:20:10 +09:00
Tatsuhiro Tsujikawa
58d3b5b4a0 nghttpx: Fix occasional HTTP/2 backend connection failure with proxy
Previously if HTTP/1 proxy is used for backend connection, we read all
incoming bytes from proxy including response body, which may be part
of HTTP/2 protocol.  While investigating this issue, we found that
http_parser_execute() returns 1-less length when we call
http_parser_pause() inside on_headers_complete callback.  To
workaround this, we increment the return value by 1.  This commit also
fixes possible segmentation fault error, which could be caused by the
lack of stopping libev watcher in disconnect().
2015-02-15 01:09:10 +09:00
Tatsuhiro Tsujikawa
442572c1f4 Handle situation where request HEADERS in queue is reset by RST_STREAM
Previously we did not handle the situation where RST_STREAM is
submitted against a stream while requet HEADERS which opens that
stream is still in queue.  Due to max concurrent streams limit,
RST_STREAM is sent first, and then request HEADERS, which effectively
voids RST_STREAM.

In this commit, we checks RST_STREAM against currently pending request
HEADERS in queue and if stream ID matches, we mark that HEADERS as
canceled and RST_STREAM is not sent in this case.  The library will
call on_frame_not_sent_callback for the canceled HEADERS with error
code from RST_STREAM.
2015-02-13 23:48:16 +09:00
Tatsuhiro Tsujikawa
011e3b325d nghttpx: Cancel backend request when frontend HTTP/1 connection is lost 2015-02-13 22:41:50 +09:00
Tatsuhiro Tsujikawa
a473641e3f Update doc 2015-02-12 23:54:38 +09:00
Tatsuhiro Tsujikawa
6f4f252907 nghttpd: Handle return value from server.run() 2015-02-12 23:18:25 +09:00
Tatsuhiro Tsujikawa
0d2bbead9d Add test to submit PUSH_PROMISE without associated stream open 2015-02-12 23:09:01 +09:00
Tatsuhiro Tsujikawa
16475f6613 Update doc 2015-02-12 23:04:21 +09:00
Tatsuhiro Tsujikawa
0bdacd3e77 Code cleanup 2015-02-12 23:02:17 +09:00
Tatsuhiro Tsujikawa
57a50f981b Refactor session_prep_frame to eliminate framerv 2015-02-12 22:58:43 +09:00
Tatsuhiro Tsujikawa
115d7133a0 nghttpx: Don't check HEADERS category in on_frame_not_send_callback 2015-02-12 22:44:29 +09:00
Tatsuhiro Tsujikawa
eb94603c51 Make nghttp2_session_get_stream_user_data work inside nghttp2_on_frame_not_send_callback 2015-02-12 22:41:57 +09:00
Tatsuhiro Tsujikawa
7d4a6aa179 Add test for submission ordering of HEADERS and its RST_STREAM 2015-02-12 21:28:20 +09:00
Tatsuhiro Tsujikawa
354de30874 Make default min frame payload size to 16K
Previously we use 16K - 9 bytes (frame header) as frame payload size
so that whole frame fits in 1 TLS record size (16K).  But it turns out
that in proxy use case, we will receive 16K payload from backend and
we have to split it into 2 odd looking frames (16K - 9 and 9), and
latter is highly inefficient.  To avoid this situation, we decided to
use min frame payload size to 16K.  Since we operates on TLS as stream
of data, we are not so much restricted in its record size.
2015-02-12 00:09:18 +09:00
Tatsuhiro Tsujikawa
c462093555 src: Use same convention for len parameter in TLS I/O with cleartext I/O 2015-02-11 23:22:53 +09:00
Tatsuhiro Tsujikawa
364772f508 src: Fix error reported by coverity scan 2015-02-11 23:20:13 +09:00
Tatsuhiro Tsujikawa
ae0100a9ab nghttpx: Refactor worker interface 2015-02-11 22:49:03 +09:00
Tatsuhiro Tsujikawa
756e2b3e9b nghttp, h2load: Fix regression introduced in 795a22a
We missed wb.reset(), which makes write buffer's capacity becomes 0
and communication stalls eventually.
2015-02-11 21:42:11 +09:00
Tatsuhiro Tsujikawa
57d02f5c57 Update README.rst 2015-02-11 01:05:58 +09:00
Tatsuhiro Tsujikawa
73b999a662 src: Fix crash 2015-02-11 01:05:22 +09:00
Tatsuhiro Tsujikawa
4401f697e5 src: Try to write immediately after read 2015-02-11 00:44:30 +09:00
Tatsuhiro Tsujikawa
f360b5c1e3 src: Prefer std::equal 2015-02-11 00:20:33 +09:00
Tatsuhiro Tsujikawa
07fdaaba45 src: Use case-insensitive match when parsing Link header field 2015-02-10 23:29:45 +09:00
Tatsuhiro Tsujikawa
7fa62c9904 src: Clean up string utlity functions 2015-02-10 23:16:34 +09:00
Tatsuhiro Tsujikawa
3e2714810a src: Fix invalid memory access 2015-02-10 21:28:17 +09:00
Tatsuhiro Tsujikawa
68866f53b0 src: Use nullptr instead of 0, since they are char* 2015-02-09 23:45:20 +09:00
Tatsuhiro Tsujikawa
ad8e9a4741 src: Ignore URI with non-empty anchor parameter 2015-02-09 23:25:10 +09:00
Tatsuhiro Tsujikawa
3c5d8f446b src: Fix typo 2015-02-09 23:25:10 +09:00
Tatsuhiro Tsujikawa
2e425e3cb6 src: Support backslash escapes in quoted-string when parsing Link header 2015-02-09 23:25:10 +09:00
Tatsuhiro Tsujikawa
1b00bc1929 src: Support rel with quoted value in Link header parser 2015-02-09 23:25:10 +09:00
Tatsuhiro Tsujikawa
6b28e033de Fix compile error and memory leak 2015-02-09 22:37:11 +09:00
Tatsuhiro Tsujikawa
eec8870ac1 Fix bug that client may send PROTOCOL_ERROR upon canceled push stream
Previously we treat stream in NGHTTP2_STREAM_RESERVED state specially,
that is we don't increment or decrement streams counts if stream is in
that state.  Because of this, we don't change the stream state to
NGHTTP2_STREAM_CLOSING if stream is in NGHTTP2_STREAM_RESERVED.  But
it turns out that it causes a problem.  If client canceled pushed
stream before push response HEADERS, stream is still in
NGHTTP2_STREAM_RESERVED state.  If push response HEADERS arrived in
this state, library happily accepts it and passed to application.

With this commit, this bug was corrected.  We now change stream state
to NGHTTP2_STREAM_CLOSING even if it was in NGHTTP2_STREAM_RESERVED
state.  We now use NGHTTP2_STREAM_FLAG_PUSH to determine whether we
have to increase/decrase stream count.
2015-02-09 22:23:20 +09:00
Tatsuhiro Tsujikawa
d151759f8a nghttpx: Fix location rewrite, take 2 2015-02-08 21:26:47 +09:00
Tatsuhiro Tsujikawa
807d39abe3 nghttpx: Fix location rewrite does not work 2015-02-08 18:54:24 +09:00
Tatsuhiro Tsujikawa
7b81136bb3 Merge branch 'nghttpx-server-push' 2015-02-08 17:49:13 +09:00
Tatsuhiro Tsujikawa
75d7e5abe0 Update man pages 2015-02-08 17:48:18 +09:00
Tatsuhiro Tsujikawa
4d47c31ebe src: Refactor parse_next_link_header_once 2015-02-08 17:47:21 +09:00
Tatsuhiro Tsujikawa
9e723b6b1d src: Rename LinkHeader.url as LinkHeader.uri 2015-02-08 17:29:38 +09:00
Tatsuhiro Tsujikawa
7aff00496a nghttpx: Log push request headers 2015-02-08 17:25:21 +09:00
Tatsuhiro Tsujikawa
0efdeab1db nghttpx: Fix handling of return value from nghttp2_submit_push_promise 2015-02-08 17:21:27 +09:00
Tatsuhiro Tsujikawa
b01d0c88fe Document nghttpx server push feature 2015-02-08 17:13:36 +09:00
Tatsuhiro Tsujikawa
502b552b68 nghttpx: Add --no-server-push option 2015-02-08 16:19:12 +09:00
Tatsuhiro Tsujikawa
8c90e5314d src: Update doc 2015-02-08 16:10:01 +09:00
Tatsuhiro Tsujikawa
af960f1982 nghttpx: Don't push if http2 proxy is used 2015-02-08 16:10:01 +09:00
Tatsuhiro Tsujikawa
8b4291edcb integration: Add server push test 2015-02-08 16:10:01 +09:00
Tatsuhiro Tsujikawa
45a47936e0 integration: Update doc 2015-02-08 16:10:01 +09:00
Tatsuhiro Tsujikawa
7c09d5eb8d nghttpx: PUSH_PROMISE from client is handled by library 2015-02-08 16:10:01 +09:00
Tatsuhiro Tsujikawa
88f0bc70c4 nghttpx: Reworkd inherited request headers in PUSH_PROMISE 2015-02-08 16:10:01 +09:00
Tatsuhiro Tsujikawa
b14cfaf308 src: Store token in Header object to avoid additional lookups 2015-02-08 16:10:01 +09:00
Tatsuhiro Tsujikawa
8dd8d68b83 src: Make index of header int16_t 2015-02-08 16:10:01 +09:00
Tatsuhiro Tsujikawa
c55d7343ca nghttpx: Support server push using Link header field
nghttpx server push is initiated by looking for Link header field from
backend server response.  Currently we only enable server push for
HTTP/1 backend and without HTTP/2 proxy mode.  The URIs which have
rel=preload are eligible to resource to be pushed.
2015-02-08 16:10:00 +09:00
Tatsuhiro Tsujikawa
4dea318b5b nghttpx: Fix compile error if SOCK_NONBLOCK is undefined 2015-02-08 00:49:56 +09:00
Tatsuhiro Tsujikawa
795a22a320 src: Remove ringbuf.h, use buffer.h instead 2015-02-06 23:40:34 +09:00
Tatsuhiro Tsujikawa
b4b2ddad3b src: Rewrite defer function template 2015-02-06 23:27:15 +09:00
Tatsuhiro Tsujikawa
6ff67ae869 src: Move array_size to nghttp2 namespace 2015-02-06 22:44:09 +09:00
Tatsuhiro Tsujikawa
33879219ff Refactor ALPN/NPN protocol selection and introduce NGHTTP2_PROTO_ALPN macro 2015-02-06 22:35:30 +09:00
Tatsuhiro Tsujikawa
4956bdc4da src: Use std::copy_n 2015-02-06 21:35:03 +09:00
Tatsuhiro Tsujikawa
b165775811 nghttpx: Refactor CertLookupTree 2015-02-06 21:25:43 +09:00
Tatsuhiro Tsujikawa
90746cdd0e nghttpx: Fix compile error with OpenSSL 1.0.2 2015-02-06 21:14:04 +09:00
Tatsuhiro Tsujikawa
f93a2b71a1 Treat first SETTINGS bearing ACK as connection error 2015-02-06 01:22:41 +09:00
Tatsuhiro Tsujikawa
2dd6353e24 examples/client: Send SETTINGS 2015-02-06 01:22:29 +09:00
Tatsuhiro Tsujikawa
208abd8cc5 Fix debug output 2015-02-06 01:18:23 +09:00
Tatsuhiro Tsujikawa
4cda09beff src: Prefer std::array 2015-02-06 00:15:43 +09:00
Tatsuhiro Tsujikawa
9a2d36fc6c src: Use std::copy instead of std::copy_n since gcc-4.7 does not have it 2015-02-06 00:15:43 +09:00
Tatsuhiro Tsujikawa
ab6663c785 src: Use std::array instead of std::vector if size is compile time constant 2015-02-06 00:15:43 +09:00
Tatsuhiro Tsujikawa
54851ef7a6 src: Move make_unique to nghttp2 namespace 2015-02-06 00:15:43 +09:00
Tatsuhiro Tsujikawa
f8f9b36acd http2: Use std::array for indexing headers 2015-02-06 00:15:43 +09:00
Tatsuhiro Tsujikawa
6774fa6e07 buffer: Refactor 2015-02-06 00:15:43 +09:00
Tatsuhiro Tsujikawa
7baf6f781e memchunk: Refactor 2015-02-06 00:15:42 +09:00
Tatsuhiro Tsujikawa
2349a03882 nghttpx: Fix regression HTTP/2 upgrade does not work 2015-02-06 00:15:13 +09:00
Tatsuhiro Tsujikawa
3904550d5d nghttpd: Shut up travis 2015-02-05 22:49:19 +09:00
Tatsuhiro Tsujikawa
be3ee91e90 nghttpd: Fix compile error on travis 2015-02-05 21:50:20 +09:00
Tatsuhiro Tsujikawa
d4f87ce29f nghttpd: Fix multiple push configuration does not work 2015-02-05 21:31:16 +09:00
Tatsuhiro Tsujikawa
1216d7d912 nghttpx: Connection: Explicit assignment to double field 2015-02-05 21:26:55 +09:00
Tatsuhiro Tsujikawa
f3b247e4c8 nghttpx: Add missing rev start in HTTP/2 backend 2015-02-05 03:05:34 +09:00
Tatsuhiro Tsujikawa
7c75d9db98 nghttpx: Set nghttp2_option_set_peer_max_concurrent_streams for HTTP/2 backend 2015-02-05 03:05:34 +09:00
Tatsuhiro Tsujikawa
b2fb888363 Share I/O code with all upstreams/downstream objects 2015-02-05 03:05:34 +09:00
Tatsuhiro Tsujikawa
a4d729d36b nghttpx: Return HTTP error on downstream parser failure on HTTPS upstream 2015-02-04 21:30:05 +09:00
Tatsuhiro Tsujikawa
83200f3080 Merge branch 'rewrite-host' 2015-02-04 01:44:40 +09:00
Tatsuhiro Tsujikawa
a14c614c10 Document use case of --no-host-rewrite 2015-02-04 01:43:48 +09:00
Tatsuhiro Tsujikawa
a68c4c1e3c nghttpx: Add --no-host-rewrite option 2015-02-04 01:42:26 +09:00
Tatsuhiro Tsujikawa
82f90f9030 nghttpx: Rewrite :authority and host header field
We don't rewrite them if -s or -p is used
2015-02-04 01:42:19 +09:00
Tatsuhiro Tsujikawa
b707cfe986 nghttpx: Fix busy loop when HTTP/2 backend reset after connection established
We have now Downstream retry count to be limited to 5 times.  At 6th
failure, we send 503 message to client.
2015-02-03 01:47:04 +09:00
Tatsuhiro Tsujikawa
d37fc8f3a6 src: Fix compiler warning 2015-02-02 22:40:41 +09:00
Tatsuhiro Tsujikawa
9f5f724147 nghttpd, nghttpx: Don't log error NGHTTP2_ERR_BAD_PREFACE 2015-02-02 00:20:44 +09:00
Tatsuhiro Tsujikawa
e2bbc94616 Use NGHTTP2_PROTOCOL_ERROR when peer exceeds MAX_CONCURRENT_STREAMS limit
Kudos to h2spec to find this details
2015-02-02 00:14:17 +09:00
Tatsuhiro Tsujikawa
928b49a916 Update man pages 2015-02-01 18:33:24 +09:00
Tatsuhiro Tsujikawa
56c2fd6c5b help2rst.py: Strip trailing ':' after section 2015-02-01 18:32:51 +09:00
Tatsuhiro Tsujikawa
267f877255 Update man pages 2015-02-01 18:19:16 +09:00
Tatsuhiro Tsujikawa
36e216d24a src: Delete unused source files 2015-02-01 18:12:57 +09:00
Tatsuhiro Tsujikawa
73d231b1bb Update README.rst 2015-02-01 18:08:54 +09:00
Tatsuhiro Tsujikawa
cabb7c73cd nghttp: Widen column for complete and request to account for + 2015-02-01 18:07:53 +09:00
Tatsuhiro Tsujikawa
3a37ed97f4 nghttp: Rewrite statistics output with -s option
Now timing information (completion, request, processing), status code
and request path are listed in the order by completion time.  This
ordering is very convenient to check resource prioritization
validation.
2015-02-01 17:59:49 +09:00
Tatsuhiro Tsujikawa
0f14c93fa4 nghttp: Refactor 2015-02-01 17:21:13 +09:00
Tatsuhiro Tsujikawa
f321ee5a61 nghttp: Record request time just before transmission of request 2015-02-01 16:58:58 +09:00
Tatsuhiro Tsujikawa
e9eae3fb61 doc: Add output section to h2load man page 2015-02-01 16:36:58 +09:00
Tatsuhiro Tsujikawa
17de036d85 h2load: Code cleanup 2015-01-31 23:54:03 +09:00
Tatsuhiro Tsujikawa
a91e0de06c h2load: Add request stats (time for request min, max, mean and sd) 2015-01-31 23:49:30 +09:00
Tatsuhiro Tsujikawa
bbc34904c1 Workaround stream treated inferior when it hits connection window limit 2015-01-31 15:49:10 +09:00
Tatsuhiro Tsujikawa
f1049a66e2 nghttpx: Detach DownstreamConnection early 2015-01-31 01:11:55 +09:00
Tatsuhiro Tsujikawa
5a497b9f30 nghttpx: Update doc 2015-01-30 21:33:18 +09:00
Tatsuhiro Tsujikawa
b4ad0a30af Fix typo 2015-01-30 21:32:41 +09:00
Tatsuhiro Tsujikawa
1816738b3c nghttpx: Change frontend write buffer size to 32768 2015-01-30 21:32:21 +09:00
Tatsuhiro Tsujikawa
4b0b036d3b Update man pages 2015-01-29 23:29:52 +09:00
Tatsuhiro Tsujikawa
0a0618baac nghttpx: Add test for util::duration_str, rename util::parse_duration_with_unit 2015-01-29 23:28:47 +09:00
Tatsuhiro Tsujikawa
e03f36eeeb nghttpx: Use <DURATION> instead of <T> 2015-01-29 23:23:30 +09:00
Tatsuhiro Tsujikawa
6b1ef95d3f nghttpx: Replace RingBuf with sequential Buffer
It turns out that we don't need circular buffer functionality.  We
replaced RingBuf with simple sequential Buffer.
2015-01-29 22:57:56 +09:00
Tatsuhiro Tsujikawa
147bc45658 nghttpx: Refactor memchunk a bit 2015-01-29 21:18:30 +09:00
Tatsuhiro Tsujikawa
00555dc7bb nghttpx: Use TCP_DEFER_ACCEPT if available 2015-01-29 21:14:44 +09:00
Tatsuhiro Tsujikawa
d1a4002b22 nghttpx: Remove --accept-delay and --num-accept options 2015-01-29 20:58:47 +09:00
Tatsuhiro Tsujikawa
8ddad1a53d nghttpx: Remove shrinking memchunks for now
It requires more careful optimization.  Remove it for now.
2015-01-28 21:25:22 +09:00
Tatsuhiro Tsujikawa
96e66b1a81 nghttpx: Make num_accept 0 on graceful shutdown
Make num_accept unlimited so that we can accept all pending
connections waiting in listen queue.
2015-01-28 21:02:31 +09:00
Tatsuhiro Tsujikawa
19429abd07 nghttpx: Make --accept-delay default to 10ms 2015-01-28 21:00:47 +09:00
Tatsuhiro Tsujikawa
243a8135a6 Merge branch 'B4dM4n-supplementary_group_access' 2015-01-28 20:58:38 +09:00
Fabian Möller
3167aa4081 nghttpx: set the supplementary group access list 2015-01-28 20:56:05 +09:00
Tatsuhiro Tsujikawa
10a4926648 Merge branch 'szepeviktor-patch-1' 2015-01-28 20:51:45 +09:00
Tatsuhiro Tsujikawa
67f50770f5 Merge branch 'patch-1' of https://github.com/szepeviktor/nghttp2 into szepeviktor-patch-1 2015-01-28 20:51:03 +09:00
Tatsuhiro Tsujikawa
93daa98608 src: Make option suggestion work with unknown option followed by '=' 2015-01-28 00:58:42 +09:00
Viktor Szépe
63675f0a47 Better usability for apt packages 2015-01-27 16:58:08 +01:00
Tatsuhiro Tsujikawa
f8765be817 nghttpx: Make --backend-keep-alive-timeout default to 2s 2015-01-28 00:47:09 +09:00
Tatsuhiro Tsujikawa
f0c7839f25 nghttpx: Clarify --num-accept=0 case 2015-01-28 00:39:56 +09:00
Tatsuhiro Tsujikawa
6a39de0ae5 nghttpx: Accept s or ms as unit for <T> argument 2015-01-28 00:36:44 +09:00
Tatsuhiro Tsujikawa
402ebb277f nghttpx: Add --num-accept and --accept-delay options 2015-01-27 23:47:56 +09:00
Tatsuhiro Tsujikawa
4e68ca8233 integration: Add tests about via header field manipulation
This test reveals bug in SPDY upstream code, and contains its fix.
2015-01-27 00:19:57 +09:00
Tatsuhiro Tsujikawa
95b3e2f140 integration: Fix typo 2015-01-27 00:19:41 +09:00
Tatsuhiro Tsujikawa
f412ae442b Bump up version number to v0.7.4-DEV 2015-01-25 23:02:43 +09:00
Tatsuhiro Tsujikawa
01313c1241 Update man pages 2015-01-25 23:00:43 +09:00
Tatsuhiro Tsujikawa
99afea05b9 Bump up version number to 0.7.3 2015-01-25 22:58:43 +09:00
Tatsuhiro Tsujikawa
b99b83812b nghttpd: RST_STREAM if te header field contains value other than trailers 2015-01-25 22:58:43 +09:00
Tatsuhiro Tsujikawa
0b48448270 nghttpx: RST_STREAM for invalid request header values 2015-01-25 22:58:43 +09:00
Tatsuhiro Tsujikawa
2a56a3d9ea nghttpx: Fix te request header handling
Checking against "trailers" is enough for now.
2015-01-25 22:58:43 +09:00
Tatsuhiro Tsujikawa
1883bdaf1d Bump up version number to 0.7.3-DEV 2015-01-25 22:53:34 +09:00
Tatsuhiro Tsujikawa
82cd23e40b Update man pages 2015-01-25 21:49:12 +09:00
Tatsuhiro Tsujikawa
d56e167c54 Bump up version number to 0.7.2, LT revision to 9:0:4 2015-01-25 21:48:36 +09:00
Tatsuhiro Tsujikawa
3e5765831f integration: Add missing alt-server.key and alt-server.crt to EXTRA_DIST 2015-01-25 21:35:45 +09:00
Tatsuhiro Tsujikawa
b9c6162cd5 nghttp: Use compatible cipher list 2015-01-25 17:53:17 +09:00
Tatsuhiro Tsujikawa
68510f1282 nghttpx: SpdyUpstream: Handle error from error_reply 2015-01-25 15:37:09 +09:00
Tatsuhiro Tsujikawa
4b58b25c19 nghttpx: Refactor code to build cert_tree, add SNI test 2015-01-25 15:36:14 +09:00
Brian Card
516a2f0efc Adding an address parameter that allows nghttpd to bind to a non-default address. Both IPv4 and IPv6 addresses are supported. In addition with verbose mode enable the address that the webserver binds to is now printed in addition to the port. 2015-01-24 15:26:49 -05:00
Tatsuhiro Tsujikawa
fbd9bcb00e Use _LDADD to specify libraries instead of _LDFLAGS
This is because _LDFLAGS comes before _LDADD.  If we specify a library
and another library in _LDADD depends on it, we get undefined
reference error.
2015-01-25 00:58:30 +09:00
Tatsuhiro Tsujikawa
682db00ba9 integration: Add tests for TE request header field 2015-01-24 16:02:03 +09:00
Tatsuhiro Tsujikawa
434e80dc7b nghttpx: Reset stream if TE header field contains other than trailer 2015-01-24 15:31:59 +09:00
Tatsuhiro Tsujikawa
5c93a113f3 Document about make itprep 2015-01-24 01:05:20 +09:00
Tatsuhiro Tsujikawa
6b4b7bef23 nghttpx: Reset stream if request header field name is malformed 2015-01-24 00:37:26 +09:00
Tatsuhiro Tsujikawa
8d5c893929 integration: Add Cookie crumbling tests 2015-01-24 00:27:12 +09:00
Tatsuhiro Tsujikawa
b943fbb002 integration: Add test for assembling Cookie works toward HTTP/1 link 2015-01-24 00:17:11 +09:00
Tatsuhiro Tsujikawa
9a89db575a nghttpx: Reject multiple Content-Length even if their values are identical 2015-01-24 00:07:28 +09:00
Tatsuhiro Tsujikawa
0fcfe16dc5 integration: Document each test cases 2015-01-24 00:01:14 +09:00
Tatsuhiro Tsujikawa
990f9ed4de integration: Split up single file to 3 based on frontend type 2015-01-23 23:37:11 +09:00
Tatsuhiro Tsujikawa
0f4b0966ef nghttpx: Merge all options settings in one SSL_CTX_set_options 2015-01-23 23:32:01 +09:00
Tatsuhiro Tsujikawa
ecfd593076 nghttpx: Call ConnectBlocker::on_success when connection is established 2015-01-23 23:00:18 +09:00
Tatsuhiro Tsujikawa
3c6b75fb2b Add make itprep target to go get dependencies 2015-01-23 22:55:42 +09:00
Tatsuhiro Tsujikawa
d1f06b09cd integration: Add TLS key and certificate for testing 2015-01-23 21:25:21 +09:00
Tatsuhiro Tsujikawa
3a94ad709c Merge branch 'acesso-patch-1' 2015-01-23 21:17:33 +09:00
acesso
7ea8037ee1 Use fcntl and FD_CLOEXEC if O_CLOEXEC is undefined
Same reported at #87 but at src/shrpx_config.cc src/instead of util.cc
2015-01-23 21:17:06 +09:00
Tatsuhiro Tsujikawa
064bfcc9d2 Fix test failure 2015-01-23 01:29:41 +09:00
Tatsuhiro Tsujikawa
a0028ea8ef nghttpx: Add logging when downstream connect is blocked by connect_blocker 2015-01-23 00:15:38 +09:00
Tatsuhiro Tsujikawa
d174ffeb00 memchunk: Rename append_cstr as append
We may later add append(const T &), where we require T for .size() and
.data().  We can coexist former append_cstr and new one.  If we pass
string literal, append(const (&)[N]) is selected.
2015-01-22 23:54:30 +09:00
Tatsuhiro Tsujikawa
5a93bedf72 nghttpx: Make error page modern 2015-01-22 23:51:22 +09:00
Tatsuhiro Tsujikawa
4a0dba08b9 nghttpx: Set Connection: close after graceful shutdown in HTTP/1 upstream 2015-01-22 23:46:35 +09:00
Tatsuhiro Tsujikawa
b685747643 Add nghttp2_submit_shutdown_notice() to start graceful shutdown
nghttp2_submit_shutdown_notice() is used to notify the client that
graceful shutdown is started.  We expect that after this call, the
server application should send another GOAWAY using
nghttp2_submit_goaway() with appropriate last_stream_id.  In this
commit, we also added nghttp2_session_get_last_proc_stream_id(), which
can be used as last_stream_id parameter.

This commit implements graceful shutdown in nghttpx.  The integration
test for graceful shutdown is also added.
2015-01-22 23:21:58 +09:00
Tatsuhiro Tsujikawa
76a97b9718 nghttpx: Update last_write_time_ after SSL_write
SSL_write may return error indicating blocking until all given data
are written.  Because of this, it is preferable to update
last_write_time_ after SSL_write regardless of its return value.
2015-01-22 21:14:16 +09:00
Tatsuhiro Tsujikawa
ac1cc56fbb nghttpx: Stop wev_ on h1 backend connect failure 2015-01-22 21:13:34 +09:00
Tatsuhiro Tsujikawa
f604cbae70 nghttpx: Fix shutdown too early with QUIT signal if num_worker == 1 2015-01-22 01:46:25 +09:00
Tatsuhiro Tsujikawa
91ae5291cc nghttpx: Cache string representation of time for logging 2015-01-21 23:52:30 +09:00
Tatsuhiro Tsujikawa
5770c6bd04 nghttpx: Return 503 on hard disconnect in HTTP/2 backend 2015-01-21 23:30:48 +09:00
Tatsuhiro Tsujikawa
7492f628aa nghttpx: Use ConnectBlocker on h1 backend connect attempt failure 2015-01-21 23:11:47 +09:00
Tatsuhiro Tsujikawa
2f788aa214 nghttpx: Return 503 when h1 backend connect attempt failed 2015-01-21 23:08:13 +09:00
Tatsuhiro Tsujikawa
cee22df073 nghttpx: Always close connection in HttpsUpstream::error_reply 2015-01-21 23:03:39 +09:00
Tatsuhiro Tsujikawa
e219d6a94f nghttpx: Clarify error_reply upstream method
There is no application level failure in h1 upstream.  For h2, SPDY
upstreams, don't call DIE(), instead return -1 to delete handler.
2015-01-21 22:55:00 +09:00
Tatsuhiro Tsujikawa
41e72064e0 nghttpx: Log error in INFO level when frame cannot be sent 2015-01-21 22:49:00 +09:00
Tatsuhiro Tsujikawa
f302f1a830 integration: Fix typo 2015-01-21 22:47:22 +09:00
Tatsuhiro Tsujikawa
c0fc726955 nghttpx: Call signal_write in HttpsUpstream::on_downstream_abort_request 2015-01-21 22:45:52 +09:00
Tatsuhiro Tsujikawa
041d9863c2 nghttpx: Set request_start_time_ at Downstream ctor
.. so that we can avoid the problem that request_start_time_ is 0
2015-01-21 22:28:15 +09:00
Tatsuhiro Tsujikawa
3c5ca63b6f nghttpx: Fix TLS write limit does not work 2015-01-21 21:47:25 +09:00
Tatsuhiro Tsujikawa
53a41c953d nghttpx: Don't call ev_TYPE_set macro while watcher is active 2015-01-21 21:43:49 +09:00
Tatsuhiro Tsujikawa
c39f2b2c91 Merge branch 'antbryan-patch-2' 2015-01-21 21:19:16 +09:00
Ant Bryan
603b0ae501 Update README.rst
small text fixes
2015-01-20 23:54:22 -05:00
Tatsuhiro Tsujikawa
9938a4e952 Remove AM_EXTRA_RECURSIVE_TARGETS since travis automake is too old 2015-01-21 02:07:16 +09:00
Tatsuhiro Tsujikawa
8997e4369d nghttpx: Adjust backend buffers 2015-01-21 01:47:43 +09:00
Tatsuhiro Tsujikawa
5a6d6ccbd4 nghttpx: Read from backend eagerly in all upstreams 2015-01-21 01:41:17 +09:00
Tatsuhiro Tsujikawa
426fbda799 Update README about integration tests 2015-01-21 01:06:28 +09:00
Tatsuhiro Tsujikawa
16e91746d9 nghttpx: Return 400 error if multiple CLs are received in SPDY upstream
This change adds SPDY upstream tests.
2015-01-21 01:03:56 +09:00
Tatsuhiro Tsujikawa
b9a9a23b1e nghttpx: Close connection when error_reply is used for HTTP/1 upstream 2015-01-20 23:37:00 +09:00
Tatsuhiro Tsujikawa
8059380fb0 nghttpx: Don't need to set response state to MSG_COMPLETE after error_reply 2015-01-20 23:33:45 +09:00
Tatsuhiro Tsujikawa
039d9db5a3 integration: Make multiline string a bit readable 2015-01-20 23:30:38 +09:00
Tatsuhiro Tsujikawa
b9f41e34ef nghttpx: Return error when downstream HTTP/1 connection attempt failed 2015-01-20 23:27:30 +09:00
Tatsuhiro Tsujikawa
ca7288ae38 nghttpx: Return 502 if HTTP/1 downstream receives multiple CLs 2015-01-20 23:11:54 +09:00
Tatsuhiro Tsujikawa
a789008f17 integration: Treat blocking error as fatal 2015-01-20 22:59:09 +09:00
Tatsuhiro Tsujikawa
53142222fe integration: Code cleanup 2015-01-20 22:56:36 +09:00
Tatsuhiro Tsujikawa
f1bec6f05c nghttpx: Return 400 for multiple CLs for HTTP/1 upstream 2015-01-20 22:55:01 +09:00
Tatsuhiro Tsujikawa
506177e1bd integration: Ensure that proxy does not forward bad request 2015-01-20 22:31:21 +09:00
Tatsuhiro Tsujikawa
91151f1f56 integration: Fix minor typo 2015-01-20 22:25:56 +09:00
Tatsuhiro Tsujikawa
daec7c16d3 nghttpx: Don't discard data on HTTP/1 backend EOF
Also HTTP/1 frontend testing method was added.
2015-01-20 22:19:28 +09:00
Tatsuhiro Tsujikawa
6e446934d4 integration: Add recursive it target 2015-01-20 21:19:52 +09:00
Tatsuhiro Tsujikawa
9ab71305d1 integration: Add Makefile and make it to run integration tests 2015-01-20 01:14:22 +09:00
Tatsuhiro Tsujikawa
ae1aac26a7 integration: Set test naming convention 2015-01-20 00:59:09 +09:00
Tatsuhiro Tsujikawa
8eb2160890 integration: Add tests for HTTP/2 backend using go-nghttp2 2015-01-20 00:45:51 +09:00
Tatsuhiro Tsujikawa
a440bdf15e nghttpx: Response 502 if HTTP/2 backend receives invalid Content-Length 2015-01-19 23:44:23 +09:00
Tatsuhiro Tsujikawa
8004ea9726 nghttpx: Return 400 if request CL is invalid or multiple CLs 2015-01-19 22:40:37 +09:00
Tatsuhiro Tsujikawa
5436c95788 integration: Add HTTP/2 chunked request body test 2015-01-19 22:20:56 +09:00
Tatsuhiro Tsujikawa
467565589c integration: Use smaller interval to check server availability 2015-01-19 21:25:59 +09:00
Tatsuhiro Tsujikawa
8f45bf7b9e integration: Use []hpack.HeaderField instead of http.Header in requestParam
With array, we can control the order of header field directly.
2015-01-19 21:24:18 +09:00
Tatsuhiro Tsujikawa
09939cf6bc integration: Code cleanup
Don't close channel to avoid potential write-after-close.
Use time.After instead of time.NewTimer
2015-01-19 21:18:35 +09:00
Tatsuhiro Tsujikawa
e8053ac931 nghttpx: Check Content-Length only when Transfer-Encoding is not found 2015-01-19 21:16:47 +09:00
Tatsuhiro Tsujikawa
fff785178d Add integration tests for nghttpx using golang testing framework
The integration tests reside in integration-tests directory.  To run
integration tests, cd integration-tests, then run "go test".  Tests
depends on https://github.com/bradfitz/http2.
2015-01-19 00:27:24 +09:00
Tatsuhiro Tsujikawa
af24f8394e nghttpx: Fix nghttp2 error code use in SPDY upstream 2015-01-17 21:35:36 +09:00
Tatsuhiro Tsujikawa
62b9e4bb56 nghttpx: Validate received request body length against content-length 2015-01-17 21:33:23 +09:00
Tatsuhiro Tsujikawa
441f1cc282 nghttpx: Validate received response body length against content-length 2015-01-17 21:33:23 +09:00
Tatsuhiro Tsujikawa
f92110c54c nghttpx: Http2Upstream: Try to read data from backend if buffer is empty 2015-01-17 17:37:32 +09:00
Tatsuhiro Tsujikawa
1cb6d5cb6d Define NOTHREADS to 1 if thread_local keyword is not available 2015-01-17 15:52:28 +09:00
Tatsuhiro Tsujikawa
3817798905 Compile with g++-4.7
g++-4.7 lacks thread_local, which can be workaround by
--disable-threads.  What left remaining is std::map::emplace, which is
what this change deals with.  First check availability of
std::map::emplace, if there is none, use std::map::insert.
2015-01-17 15:32:49 +09:00
Tatsuhiro Tsujikawa
13a14ecda8 nghttpx: Workaround IRIX's struct sockaddr which contains union 2015-01-17 14:59:24 +09:00
Tatsuhiro Tsujikawa
2b458666ba nghttpd: Fix compiler warning 2015-01-16 23:22:10 +09:00
Tatsuhiro Tsujikawa
06a8d684a6 Fixed typo 2015-01-16 22:29:22 +09:00
Tatsuhiro Tsujikawa
18d42b411b Update man pages 2015-01-16 00:10:16 +09:00
Tatsuhiro Tsujikawa
cbd878bbd5 nghttp, nghttpd: Allow unit for --header-table-size option 2015-01-16 00:07:52 +09:00
Tatsuhiro Tsujikawa
49eeed8420 help2rst.py: Update number of indentation 2015-01-16 00:07:52 +09:00
Tatsuhiro Tsujikawa
5f36d91afd nghttp, nghttpd, h2load: Same indentation with nghttpx 2015-01-16 00:07:52 +09:00
Tatsuhiro Tsujikawa
a08ce38bcf nghttpd: Cache date by comparing ev_now 2015-01-15 23:27:52 +09:00
Tatsuhiro Tsujikawa
5d204fc3aa nghttpx: Add more option categories 2015-01-15 23:19:35 +09:00
Tatsuhiro Tsujikawa
84ead30e58 nghttpx: Remove NGHTTP2_HCAT_REQUEST halding since already handled in lib 2015-01-15 23:16:24 +09:00
Tatsuhiro Tsujikawa
b11e1afc91 nghttpx: Remove unused noop function 2015-01-15 23:14:25 +09:00
Tatsuhiro Tsujikawa
c3aa02f003 nghttpd: Use Http2Handler::submit_rst_stream 2015-01-15 23:11:14 +09:00
Tatsuhiro Tsujikawa
d142830109 nghttpd: Issue RST_STREAM if content-length does not match uploaded bytes 2015-01-15 23:07:25 +09:00
Tatsuhiro Tsujikawa
22e41bab3f nghttpd: Issue RST_STREAM if received header field contains invalid chars 2015-01-15 22:45:18 +09:00
Tatsuhiro Tsujikawa
b0078a2379 Suppress to send frames other than GOAWAY if NGHTTP2_GOAWAY_TERM_ON_SEND is set
This change makes sure that GOAWAY which terminates session is
immediately sent without blocked by other frames.
NGHTTP2_ERR_SESSION_CLOSING library error code was added to indicate
this situation to callback.
2015-01-15 22:32:29 +09:00
Tatsuhiro Tsujikawa
50109bb307 Use NGHTTP2_STREAM_CLOSED when DATA arrived to stream which is not open 2015-01-14 23:31:21 +09:00
Tatsuhiro Tsujikawa
aa1c8d1fa4 nghttpx: Don't forward Trailer header field 2015-01-14 21:33:22 +09:00
Tatsuhiro Tsujikawa
1de20c1232 nghttpx: Ignore trailer headers in HTTP/1.1 2015-01-14 21:28:31 +09:00
Tatsuhiro Tsujikawa
8fe093de1d nghttpx: Set initial backlog to 512 2015-01-14 21:24:12 +09:00
Tatsuhiro Tsujikawa
f004361ef2 nghttpx: Add --backend-request-buffer option 2015-01-13 23:30:28 +09:00
Tatsuhiro Tsujikawa
d6db38a318 nghttpx: Clean up integer configuration range checking 2015-01-13 23:23:35 +09:00
Tatsuhiro Tsujikawa
c88a5291b7 nghttpx: Add --backend-response-buffer option 2015-01-13 23:20:06 +09:00
Tatsuhiro Tsujikawa
0d614cf103 nghttpx: Longer help message 2015-01-13 23:02:18 +09:00
Tatsuhiro Tsujikawa
29d6cfae80 nghttpx: Add explanation about units in <SIZE> 2015-01-13 22:42:52 +09:00
Tatsuhiro Tsujikawa
c48a6e73e8 nghttpx: Clean up metavar 2015-01-13 22:39:35 +09:00
Tatsuhiro Tsujikawa
956c11388c nghttpx: Allow units (k, m, and g) in --{read,write}-{rate,burst}
So that you can specify --read-rate=1M --read-burst=4M
2015-01-13 21:54:53 +09:00
Tatsuhiro Tsujikawa
5e8eb926f2 nghttpx: Fix server error with -n1 and --tls-ctx-per-worker 2015-01-13 21:53:53 +09:00
Tatsuhiro Tsujikawa
1e4f8f27fd nghttpx: Add --tls-ctx-per-worker option
When same SSL_CTX is used by multiple thread simultaneously we have to
setup some number of mutex locks for it.  We could not check how this
locking affects scalability since we have 4 cores at best in our
development machine.  Good side of sharing SSL_CTX across threads is
we can share session ID pool.

If --tls-ctx-per-worker is enabled, SSL_CTX is created per thread
basis and we can eliminate mutex locks.  The downside is session ID is
no longer shared, which means if session ID generated by one thread
cannot be acceptable by another thread.  But we have now session
ticket enabled and its keys are shared by all threads.
2015-01-13 00:25:02 +09:00
Tatsuhiro Tsujikawa
0ea041e8cb nghttpx: Add doc and clean up 2015-01-12 22:47:30 +09:00
Tatsuhiro Tsujikawa
e048deb64c nghttpx: Fix error message 2015-01-12 22:35:45 +09:00
Tatsuhiro Tsujikawa
8ece08e1a3 Bump up version number to 0.7.2-DEV 2015-01-11 19:24:21 +09:00
Tatsuhiro Tsujikawa
bdfb2b9a0d Update man pages 2015-01-11 19:03:45 +09:00
Tatsuhiro Tsujikawa
3fd37462bb Bump up version number to 0.7.1, LT revision to 8:1:3 2015-01-11 19:00:49 +09:00
Tatsuhiro Tsujikawa
1164e931c5 Use clang for android build
With androideabi-4.9, android build now supports threading.
2015-01-11 18:50:54 +09:00
Tatsuhiro Tsujikawa
0e8afdb050 Add extra doc to FILES section in nghttpx man pages 2015-01-11 17:34:43 +09:00
Tatsuhiro Tsujikawa
23119a6f12 Update sphinx_rtd_theme 2015-01-11 17:20:46 +09:00
Tatsuhiro Tsujikawa
8001f226b9 Update instruction and Dockerfile to build android binary 2015-01-11 17:04:50 +09:00
Tatsuhiro Tsujikawa
1c0fa46dfa nghttpx: RateLimit: Use ev_timer_again for clarity 2015-01-11 00:32:08 +09:00
Tatsuhiro Tsujikawa
f7455d48cc Compile with android NDK
This also fixes the bug that nghttpx's acceptor fd is blocking if
SOCK_NONBLOCK is undefined.
2015-01-11 00:28:00 +09:00
Tatsuhiro Tsujikawa
a86d78216c Merge branch 'alagoutte-misc' 2015-01-10 23:21:07 +09:00
Tatsuhiro Tsujikawa
47c0b0326d Merge branch 'misc' of https://github.com/alagoutte/nghttp2 into alagoutte-misc 2015-01-10 23:19:33 +09:00
Tatsuhiro Tsujikawa
0ca979b453 nghttpx: Add --rlimit-nofile option 2015-01-10 23:17:48 +09:00
Alexis La Goutte
c87631c2e6 Fix other shorten-64-to-32 casting error found by MSVC (64bits)
Thanks to Pascal
2015-01-10 15:17:31 +01:00
Tatsuhiro Tsujikawa
987aa2dd85 nghttpx: Define max iovcnt for http1 backend write operation 2015-01-10 23:04:54 +09:00
Tatsuhiro Tsujikawa
91b40d1e84 src: Add test for memchunk.h 2015-01-10 23:01:03 +09:00
Tatsuhiro Tsujikawa
bc17f95c80 src: Move ipv6_numeric_addr to util and add test 2015-01-10 21:33:53 +09:00
Tatsuhiro Tsujikawa
0069ca9ce8 nghttp: Fix compile error with libstdc++ 2015-01-10 17:57:44 +09:00
Tatsuhiro Tsujikawa
fe750240c8 Update doc about nghttpx feature 2015-01-10 17:12:24 +09:00
Tatsuhiro Tsujikawa
1795d3ea27 nghttp: Add include file to clarify used objects 2015-01-10 16:44:09 +09:00
Tatsuhiro Tsujikawa
b933ee8e78 h2load: Don't retry connection on read error
Connection failure is handled by connected() and other errors lead to
just failure, no retry is needed.
2015-01-10 16:02:15 +09:00
Tatsuhiro Tsujikawa
a3dcf1e004 Produce man pages using sphinx
Previously to create manual page for bundled programs, we use help2man
to create man page from program's help output.  Then our man2rst.py
script converts man page to rst document.  Sphinx generates html from
rst documents.

Now help2rst.py produces rst document from programs output.  We use
Sphinx solely to produce both man pages and html files.
2015-01-10 00:37:42 +09:00
Tatsuhiro Tsujikawa
b2411d949e Remove return in void function 2015-01-09 20:56:37 +09:00
Tatsuhiro Tsujikawa
19101f7f4a Revert "nghttpx: Use smaller write buffer"
This reverts commit 742d80aac4.
2015-01-09 20:55:39 +09:00
Tatsuhiro Tsujikawa
a2e4a1eb26 tests: Remove unintended debug output 2015-01-09 10:07:57 +09:00
Tatsuhiro Tsujikawa
742d80aac4 nghttpx: Use smaller write buffer 2015-01-09 09:51:46 +09:00
Tatsuhiro Tsujikawa
473f1d71ff src: Clear OpenSSL error queue before SSL_shutdown 2015-01-09 09:15:01 +09:00
Tatsuhiro Tsujikawa
8f40bd4675 nghttp, nghttpd, h2load: Clear OpenSSL error queue and handle renegotiation 2015-01-09 09:10:59 +09:00
Tatsuhiro Tsujikawa
7add262721 nghttpx: Detect TLS renegotiation after SSL_read and SSL_write 2015-01-09 00:49:27 +09:00
Tatsuhiro Tsujikawa
4a218f1b79 nghttpx: Clear OpenSSL error and handle limit change in read_tls 2015-01-09 00:08:34 +09:00
Tatsuhiro Tsujikawa
419c03daa2 nghttpx: Fix TLS write error
SSL_write requires the same arguments (buf pointer and its length) on
SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.  get_write_limit() may
return smaller length than previously passed to SSL_write, which
violates OpenSSL assumption.  To avoid this, we keep last legnth
passed to SSL_write to tls_last_writelen_ if SSL_write indicated I/O
blocking.
2015-01-08 23:03:56 +09:00
Tatsuhiro Tsujikawa
019f1e9fc7 nghttpx: Remove useless comments 2015-01-08 22:28:30 +09:00
Tatsuhiro Tsujikawa
53604782e5 nghttpx: Clean up worker_event handling 2015-01-08 22:24:29 +09:00
Tatsuhiro Tsujikawa
689e8c0ee3 nghttpx: Don't copy ticket_keys std::shared_ptr 2015-01-08 21:49:19 +09:00
Tatsuhiro Tsujikawa
0173929538 nghttpx: Rename ListenHandler as ConnectionHandler 2015-01-08 21:48:39 +09:00
Tatsuhiro Tsujikawa
f570757701 nghttpd: Fix data race when updating cached_date 2015-01-08 21:41:26 +09:00
Tatsuhiro Tsujikawa
5473e870eb nghttpx: Use smaller buffer for reading 2015-01-08 21:28:52 +09:00
Tatsuhiro Tsujikawa
a41b7baf81 nghttpx: Handle NEW_CONNECTION event first 2015-01-08 21:20:17 +09:00
Tatsuhiro Tsujikawa
fcddb5c06c nghttpx: Distribute session ticket keys to workers without mutex 2015-01-08 21:15:45 +09:00
Tatsuhiro Tsujikawa
5d3544185c nghttpx: Fix crash in SSL_CTX_set_tlsext_ticket_key_cb
It seems that returning 0 when enc == 0 crashes OpenSSL.
2015-01-08 20:46:35 +09:00
Tatsuhiro Tsujikawa
5dce9501a6 Fix compile error with libstdc++ and/or --disable-threads 2015-01-08 01:57:59 +09:00
Tatsuhiro Tsujikawa
b313068cab Fix compile error with --enable-werror 2015-01-08 01:33:09 +09:00
Tatsuhiro Tsujikawa
08e8cc1915 nghttpx: Add --tls-ticket-key-file option
This option specifies files contains 48 random bytes to construct
session ticket key data.  This option can be used repeatedly to
specify multiple keys, but only the first one is used to encrypt
tickets.
2015-01-08 01:26:30 +09:00
Tatsuhiro Tsujikawa
52f3572d5b nghttpx: Enable TLS session tickets with session key rotation every 12hrs 2015-01-08 00:01:09 +09:00
Tatsuhiro Tsujikawa
a804117c83 Fix GOAWAY handling
On reception of GOAWAY, new stream creation is disallowed regardless
of last-stream-id in GOAWAY is larger than next stream ID.
2015-01-07 22:53:43 +09:00
Tatsuhiro Tsujikawa
2b14e4a617 Bump up version number to 0.7.1-DEV 2015-01-07 01:57:30 +09:00
Tatsuhiro Tsujikawa
ad57435953 Update man pages 2015-01-07 01:40:55 +09:00
Tatsuhiro Tsujikawa
7702d38699 Bump up version number to 0.7.0, LT revision to 8:0:3 2015-01-07 01:39:36 +09:00
Tatsuhiro Tsujikawa
90914b38f1 nghttpx: Do not limit DATA frame length 2015-01-07 01:25:43 +09:00
Tatsuhiro Tsujikawa
8bfd900be5 src, examples: Check return value 2015-01-07 00:26:17 +09:00
Tatsuhiro Tsujikawa
40e8eaf5fd nghttpx: Fix uninitialized pointer member 2015-01-07 00:25:42 +09:00
Tatsuhiro Tsujikawa
d3a606e9d9 nghttpx: open_file_for_write: Use O_CLOEXEC flag 2015-01-07 00:25:10 +09:00
Tatsuhiro Tsujikawa
2fb3d5fd1f nghttpx: Remove Http2Upstream::deferred_ for now 2015-01-06 23:32:58 +09:00
Tatsuhiro Tsujikawa
ba795d86f0 nghttpx: Don't cache time for logging
Update is done by main event loop which is stopped after graceful
shutdown is commenced, which means time is no longer update.  To avoid
this situation, we just avoid caching and get time for each logging.
2015-01-06 23:17:09 +09:00
Tatsuhiro Tsujikawa
e8107b68c8 nghttpx: Avoid std::chrono::high_resolution_clock as wall clock
This is because std::chrono::high_resolution_clock may not be wall
clock; it may be alias of std::chrono::stead_clock.
2015-01-06 23:10:11 +09:00
Tatsuhiro Tsujikawa
94e69d5e30 nghttpx: Remove commented lines 2015-01-06 22:55:01 +09:00
Tatsuhiro Tsujikawa
d1391f1db7 nghttpx: Process buffered data first without reading additional data 2015-01-06 22:48:17 +09:00
Tatsuhiro Tsujikawa
b9174b828e nghttpx: Use util::make_socket_closeonexec instead of calling fcntl 2015-01-06 22:03:44 +09:00
Tatsuhiro Tsujikawa
a6cf6c00ea nghttpx: Add SSL_read/write error logging 2015-01-06 22:02:24 +09:00
Tatsuhiro Tsujikawa
f6097ce6d0 nghttp: Fix compile error with openssl >= 1.0.2 2015-01-06 01:40:24 +09:00
Tatsuhiro Tsujikawa
1474f755cf Merge branch 'libev' 2015-01-06 01:33:55 +09:00
Tatsuhiro Tsujikawa
dcdbd5ab20 h2load: Fix wrong kbytes/s value 2015-01-06 01:24:03 +09:00
Tatsuhiro Tsujikawa
cbc02bbc4c nghttpx: Code cleanup 2015-01-06 00:51:52 +09:00
Tatsuhiro Tsujikawa
b5796c6b96 nghttp: Add missing initialization Request::res_hdidx on res_nva.clear() 2015-01-06 00:51:18 +09:00
Tatsuhiro Tsujikawa
d80952a2bc nghttpx: Implement stream level timeout using ev_timer 2015-01-06 00:30:57 +09:00
Tatsuhiro Tsujikawa
2e8544f48d Update http-parser to 167dcdfc063e16adba1af2f7ad5ad77b3994c8d3 2015-01-05 18:28:25 +09:00
Tatsuhiro Tsujikawa
f26d436ee6 src: http2::lookup_token: Don't need to make char lowcase 2015-01-05 18:17:52 +09:00
Tatsuhiro Tsujikawa
6052a86df1 python: Fix request header ordering 2015-01-05 17:00:07 +09:00
Tatsuhiro Tsujikawa
9854e3746f src: Fix compile error with libstdc++ 2015-01-05 16:20:35 +09:00
Tatsuhiro Tsujikawa
7a50299cb0 nghttpx: Handle connect error 2015-01-05 16:14:10 +09:00
Tatsuhiro Tsujikawa
7dba426db4 nghttpx: Use accept if accept4 is not available 2015-01-05 16:04:28 +09:00
Tatsuhiro Tsujikawa
fcf0ceeac6 nghttpd: Make use of accept4 2015-01-05 15:59:51 +09:00
Tatsuhiro Tsujikawa
e253d8f6db h2load: Retry next address when connection cannot be established 2015-01-05 01:56:02 +09:00
Tatsuhiro Tsujikawa
8fb544523c nghttpx: Fix HTTP/2 settings timer for HTTP/2 backend 2015-01-05 01:46:41 +09:00
Tatsuhiro Tsujikawa
3ae44ef2f3 nghttpd, nghttpx: Rework incoming header handling 2015-01-05 01:46:41 +09:00
Tatsuhiro Tsujikawa
730d47f7ad src: Add unittest for http2::index_header 2015-01-03 22:03:00 +09:00
Tatsuhiro Tsujikawa
ea0ab938c4 src: Only index header in lowercase 2015-01-03 21:56:59 +09:00
Tatsuhiro Tsujikawa
9763ea768d travis: Add libev-dev 2015-01-03 00:25:19 +09:00
Tatsuhiro Tsujikawa
8e3406ad20 nghttpd: Use faster request header handling 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
aaf0dc825d Update README.rst 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
8729d1e4c2 src: Remove libevent dependency 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
db6eec653b Fix errors reported by scan-build 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
c654549d35 nghttpx: Remove commented code 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
645897503d nghttpx: Reset buffer on empty 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
fe8f2a4603 nghttpd: Use larger write buffer 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
0a4330ee3c nghttpd: Fix handling pending data and rename rb_ as wb_ 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
d157744fb2 nghttpx: Fix handling of pending data 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
82320d6e55 nghttpd: Reset write buffer on empty 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
7db1864766 nghttpx: Add --backend-http1-connections-per-frontend option 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
a55a07940c nghttpx: Show not implemented warning for per wroker rate limit 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
37c01a0a4d nghttpx: Remove unused IOControl::set_lim 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
2003be8dc5 src: Fix unit tests failure 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
bfac015d61 src: Use libev for rest of the applications 2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
cd7258a7cd Use libev for nghttpd
Benchmark shows 10% faster with libev compared to libevent.  Also
response time in high load condition is much faster.
2015-01-03 00:19:41 +09:00
Tatsuhiro Tsujikawa
c3215af5f6 Fix missing error handling for session_after_frame_sent1 2015-01-02 14:49:36 +09:00
Tatsuhiro Tsujikawa
ba0f4d77a0 Merge branch 'alagoutte-travis' 2015-01-02 13:02:41 +09:00
Tatsuhiro Tsujikawa
eb681c827d Merge branch 'travis' of https://github.com/alagoutte/nghttp2 into alagoutte-travis 2015-01-02 13:02:18 +09:00
Tatsuhiro Tsujikawa
e82c53803f Merge branch 'alagoutte-misc' 2015-01-02 13:00:54 +09:00
Alexis La Goutte
781d570ec1 Travis: Remove python (No needed)
and it is now valided by http://lint.travis-ci.org/

(Hooray, your .travis.yml seems to be solid!)
2014-12-31 11:16:24 +01:00
Alexis La Goutte
fef9530ca5 fix error: variable 'mem' set but not used [-Werror=unused-but-set-variable] 2014-12-30 16:18:52 +01:00
Tatsuhiro Tsujikawa
ab1dd11705 nghttpd: Fix typo :host, which should be host 2014-12-25 00:49:36 +09:00
Tatsuhiro Tsujikawa
7bf5be9c17 nghttpd: Reserve 10 headers for request headers 2014-12-24 01:05:12 +09:00
Tatsuhiro Tsujikawa
ac11ba32ee nghttpd: Use stack allocated array for headers in submit_file_response 2014-12-24 00:56:25 +09:00
Tatsuhiro Tsujikawa
a20ad03f7b nghttpd: Use evbuffer_pullup(input, -1) cause buffer is most likely just one 2014-12-24 00:46:04 +09:00
Tatsuhiro Tsujikawa
292f219900 nghttpd: Avoid sending last 0-sized DATA 2014-12-24 00:31:21 +09:00
Tatsuhiro Tsujikawa
55e550f08f nghttpd: Remove unused variable 2014-12-24 00:23:01 +09:00
Tatsuhiro Tsujikawa
32943a74b2 nghttpd: Just use socket send buffer and don't count our own buffer size 2014-12-24 00:19:16 +09:00
Tatsuhiro Tsujikawa
89291e4010 nghttpx: Improve priority handling in http2 upstream 2014-12-23 17:45:57 +09:00
Tatsuhiro Tsujikawa
a8a66843db Merge branch 'kazuho-kazuho/issues/133' 2014-12-22 21:30:51 +09:00
Tatsuhiro Tsujikawa
32b34c4b80 Merge branch 'kazuho/issues/133' of https://github.com/kazuho/nghttp2 into kazuho-kazuho/issues/133 2014-12-22 21:29:26 +09:00
Kazuho Oku
45d0d731eb fill-in data_stat after copying the request entity into the temporary file 2014-12-22 07:26:02 +09:00
Kazuho Oku
125f62b71e unlink the temporary file immediately after calling mkstemp 2014-12-22 07:24:36 +09:00
Kazuho Oku
eb6ba2a703 copy the request entity to temporary file if the source is stdin and if it is not a regular file 2014-12-21 14:06:44 +09:00
Tatsuhiro Tsujikawa
e559168bd7 Enable failmalloc test by default 2014-12-20 23:56:33 +09:00
Tatsuhiro Tsujikawa
959d05e6f8 failmalloc: Use nghttp2_mem instead of using dlsym 2014-12-20 23:56:33 +09:00
Tatsuhiro Tsujikawa
e60183313b Document that calling nghttp2_submit_response to same stream twice is bad idea 2014-12-20 21:53:33 +09:00
Tatsuhiro Tsujikawa
7c0a0c495d Rename nghttp2_stream.data_item to nghttp2_stream.item and related functions
Initially, we use nghttp2_stream.data_item to refer only item with
DATA frame.  But recently we use it to refer HEADERS frame as well.
So it is better to call just item rather than data_item.  This applies
to all related functions.
2014-12-20 21:48:31 +09:00
Tatsuhiro Tsujikawa
39eb1e4753 nghttp: Adjust priority upon upgrade 2014-12-19 23:33:13 +09:00
Tatsuhiro Tsujikawa
079682f313 deflatehd: Fix crash 2014-12-19 23:23:42 +09:00
Tatsuhiro Tsujikawa
e8513b3241 Make huffman encoding faster 2014-12-19 23:22:55 +09:00
Tatsuhiro Tsujikawa
8bac2087cf nghttp2_session_mem_send: Handle stream closure early
Previously session_after_frame_sent is called after we detected all
data is sent.  In nghttp2_session_mem_send, we only detect it in the
next call of the function.  It means that if a frame data bearing
END_STREAM is on flight to the peer as a result of
nghttp2_session_mem_send, peer may get that data and knows the stream
closure and issues new stream.  We may receive this new stream before
the next nghttp2_session_mem_send call, which means that we may
incorrectly assumes that peer violates maximum concurrent stream
limit.  To fix this issue, we separate session_after_frame_sent into 2
functions: session_after_frame_sent1 and session_after_frame_sent2.
session_after_frame_sent1 handles on_frame_send_callback and stream
closure and we call this early in nghttp2_session_mem_send.  This
makes number of streams are synchronized correctly with peer.
2014-12-18 21:52:17 +09:00
Tatsuhiro Tsujikawa
ce1bf11d4b Fix memory leak 2014-12-18 21:02:44 +09:00
Tatsuhiro Tsujikawa
eb8138bfbd nghttp: Advance next stream ID only when --idle-dep is used 2014-12-17 23:36:29 +09:00
Tatsuhiro Tsujikawa
5180eb93e5 Merge branch 'alagoutte-misc' 2014-12-17 23:25:22 +09:00
Alexis La Goutte
27fa4d310a Fix: error pointer target types incompatible in C++ [-Werror=c++-compat] 2014-12-16 17:54:47 +01:00
Tatsuhiro Tsujikawa
adc22ec80b nghttp: Print failed address 2014-12-17 00:26:41 +09:00
Tatsuhiro Tsujikawa
4bc9f2422b Add nghttp2_mem example 2014-12-16 23:21:50 +09:00
Tatsuhiro Tsujikawa
d695d2ccc0 nghttp, nghttpx, nghttpd, h2load: Support h2-16 in NPN/ALPN
The nghttp2 library itself is still h2-14.  To experiment with the
implementations to require h2-16 to test new features (e.g.,
prioritization), nghttp, nghttpx, nghttpd and h2load now support h2-16
as well as h2-14.  Cleartext HTTP Upgrade is still limited to h2-14
however.
2014-12-16 22:57:58 +09:00
Tatsuhiro Tsujikawa
5fa9dd7cd5 nghttpx: Remove unused variable 2014-12-16 01:10:54 +09:00
Tatsuhiro Tsujikawa
b352ae03a9 src: Fix undefined reference error 2014-12-16 01:09:19 +09:00
Tatsuhiro Tsujikawa
c93da867e0 nghttpx: Fix bug SPDY upstream requires content-length if no FIN in SYN_STREAM 2014-12-15 23:42:59 +09:00
Tatsuhiro Tsujikawa
556811ec64 nghttpx: Don't connect backend if connection is not establish up front 2014-12-15 23:34:00 +09:00
Tatsuhiro Tsujikawa
403ece66e3 nghttpd: Fail if listen failed 2014-12-15 23:17:50 +09:00
Tatsuhiro Tsujikawa
9a35dbc4ab src: Just check emptiness for value since spaces around value are stripped 2014-12-15 23:14:07 +09:00
Tatsuhiro Tsujikawa
6f70a53da6 src: http2::add_header: strip white spaces in value 2014-12-15 23:04:45 +09:00
Tatsuhiro Tsujikawa
93ee9e30d8 nghttp, h2load: Use recommended ciphers and assign sane SSL_CTX options 2014-12-13 01:37:57 +09:00
Tatsuhiro Tsujikawa
a84c319d62 src: Print stream ID in priority field as dep_stream_id 2014-12-13 01:20:58 +09:00
Tatsuhiro Tsujikawa
467b419947 nghttp: Add --dep-idle option to create anchor idle node for dependency 2014-12-13 01:19:27 +09:00
Tatsuhiro Tsujikawa
ee158fb0aa Add nghttp2_session_{set,get}_next_stream_id API function 2014-12-13 01:18:15 +09:00
Tatsuhiro Tsujikawa
280c9dfcf3 Keep idle streams in separate list
Previously we handle idle streams as closed streams.  We only keeps
sum of closed streams and active streams under max concurrent streams
limit, idle streams gets deleted earlier than client expects.

In this change, idle streams are kept in separate list and not handled
as closed streams.  To mitigate possible attack vector to make
unlimited idle streams, we cap the number of idle streams in a half of
max concurrent streams.  This is arbitrary choice.  It may be adjusted
in the future when we have interop experience.
2014-12-13 00:14:52 +09:00
Tatsuhiro Tsujikawa
e4c59dd164 nghttpd: Fix next_session_id_ is not incremented 2014-12-10 01:21:12 +09:00
Tatsuhiro Tsujikawa
f705b2aec4 Use NGHTTP2_PROTOCOL_ERROR for WINDOW_UPDATE with increments == 0 2014-12-10 01:02:30 +09:00
Tatsuhiro Tsujikawa
dce20c3e6a nghttpx: Check HTTP/2 downstream connection after certain idle time
Previously when requests are issued to HTTP/2 downstream connection,
but it turns out that connection is down, handlers of those requests
are deleted.  In some situations, we only know connection is down when
we write something to network, so we'd like to handle this kind of
situation in more robust manner.  In this change, certain seconds
passed after last network activity, we first issue PING frame to
downstream connection before issuing new HTTP request.  If writing
PING frame is failed, it means connection was lost.  In this case,
instead of deleting handler, pending requests are migrated to new
HTTP2/ downstream connection, so that it can continue without
affecting upstream connection.
2014-12-09 21:41:29 +09:00
Tatsuhiro Tsujikawa
e0a2353c56 Fix crash with custom memory allocator 2014-12-08 21:22:20 +09:00
Tatsuhiro Tsujikawa
c0ffed7788 Support custom memory allocator
nghttp2_mem structure is introduced to hold custom memory allocator
functions and user supplied pointer.  nghttp2_mem object can be passed
to nghttp2_session_client_new3(), nghttp2_session_server_new3(),
nghttp2_hd_deflate_new2() and nghttp2_hd_inflate_new2() to replace
standard malloc(), free(), calloc() and realloc().  nghttp2_mem
structure has user supplied pointer mem_user_data which can be used as
per session/object memory pool.
2014-12-08 00:55:55 +09:00
Tatsuhiro Tsujikawa
21b48d24e4 Remove altsvc 2014-12-07 23:11:54 +09:00
Tatsuhiro Tsujikawa
e13c9102b8 Update man pages 2014-12-06 23:03:50 +09:00
Tatsuhiro Tsujikawa
14d8894b40 Update doc 2014-12-06 23:00:04 +09:00
Tatsuhiro Tsujikawa
b607a22076 nghttpx: Support multiple HTTP/1 backend address
For HTTP/1 backend, -b option can be used several times to specify
multiple backend address.  HTTP/2 backend does not support multiple
addresses and only uses first address even if multiple addresses are
specified.
2014-12-06 19:30:27 +09:00
Tatsuhiro Tsujikawa
b8dafbdf5e nghttpx: Pass NI_NUMERICSERV to getnameinfo to get numeric service name 2014-12-06 01:07:05 +09:00
Tatsuhiro Tsujikawa
3b03ff626a nghttpx: Don't log access log for blocked streams 2014-12-05 21:29:31 +09:00
Tatsuhiro Tsujikawa
9614611969 nghttpx: Limit # of downstream connections per host when h2 proxy is used
This commit limits the number of concurrent HTTP/1 downstream
connections to same host.  By defualt, it is limited to 8 connections.
--backend-connections-per-frontend option was replaced with
--backend-http1-connections-per-host, which changes the maximum number
of connections per host.  This limitation only kicks in when h2 proxy
is used (-s option).
2014-12-05 01:47:03 +09:00
Tatsuhiro Tsujikawa
f178b78816 nghttpx: Longer read timeouts 2014-12-03 23:45:44 +09:00
Tatsuhiro Tsujikawa
381488a9bd doc: Add link to nghttp2.org 2014-12-03 23:14:44 +09:00
Tatsuhiro Tsujikawa
0cbc78656e building-android-binary.rst: Highlight sh code 2014-12-03 23:09:16 +09:00
Tatsuhiro Tsujikawa
e180d8e594 nghttpx: Longer downstream HTTP/1 idle connection timeout 2014-12-03 23:00:53 +09:00
Tatsuhiro Tsujikawa
cbb5da5285 nghttpx: Fix --backend-http-proxy-uri does not work 2014-12-02 03:03:14 +09:00
Tatsuhiro Tsujikawa
03877c3752 asio-lib: Put ${AM_CPPFLAGS} before ${BOOST_CPPFLAGS} 2014-12-01 23:20:53 +09:00
Tatsuhiro Tsujikawa
54a3209cf5 configure.ac: Rename some variables so that they follow automake convention 2014-12-01 23:14:28 +09:00
Tatsuhiro Tsujikawa
9eb554a843 configure.ac: Categorize configure result 2014-12-01 23:10:34 +09:00
Tatsuhiro Tsujikawa
7036859823 Do not change user variable CFLAGS in configure.ac 2014-12-01 23:06:11 +09:00
Tatsuhiro Tsujikawa
60cb3f67f2 Refactor nghttp2_adjust_local_window_size 2014-12-01 21:49:32 +09:00
Tatsuhiro Tsujikawa
6b59609f9b Fix typo: s/.PONY/.PHONY/ 2014-12-01 21:13:56 +09:00
Tatsuhiro Tsujikawa
a3c5ac4730 Bump up version number to 0.6.8-DEV 2014-11-30 23:43:24 +09:00
Tatsuhiro Tsujikawa
ed1ea91a6f Update man pages 2014-11-30 23:14:02 +09:00
Tatsuhiro Tsujikawa
209d1b0946 Bump up version number to 0.6.7, LT revision to 7:2:2 2014-11-30 23:02:40 +09:00
Tatsuhiro Tsujikawa
761cb97090 Update README.rst 2014-11-30 22:54:55 +09:00
Tatsuhiro Tsujikawa
dcc7b23980 nghttpx: Remove cipher suite requirement
This makes the library h2-16 compatible now.
2014-11-30 22:52:34 +09:00
Tatsuhiro Tsujikawa
b9667fd209 asio: Listen to all resolved addresses 2014-11-30 22:39:16 +09:00
Tatsuhiro Tsujikawa
d23105ccb7 Add note about pseudo header ordering validation in on_header_callback 2014-11-30 21:30:48 +09:00
Tatsuhiro Tsujikawa
30499005f8 Reformat source code in libnghttp2_asio.rst 2014-11-30 21:26:13 +09:00
Tatsuhiro Tsujikawa
f2cd057e89 Update tutorial 2014-11-30 21:10:59 +09:00
Tatsuhiro Tsujikawa
2b465ee65f libevent-client: Disable SSLv3 2014-11-30 21:09:23 +09:00
Tatsuhiro Tsujikawa
7e092a7658 Make sure that head_stream is not NULL 2014-11-30 19:52:05 +09:00
Tatsuhiro Tsujikawa
d39b56adaa Remove unused nghttp2_stream.blocked_sent 2014-11-30 17:41:40 +09:00
Tatsuhiro Tsujikawa
152a20a416 Influence last_stream_id to nghttp2_session_want_{read,write} 2014-11-29 23:13:42 +09:00
Tatsuhiro Tsujikawa
7ff0797535 Rewrite session_is_new_peer_stream_id() 2014-11-29 17:24:49 +09:00
Tatsuhiro Tsujikawa
ca57c2f6b6 Rename NGHTTP2_GOAWAY_FAIL_ON_SEND with NGHTTP2_GOAWAY_TERM_ON_FAIL 2014-11-29 16:28:08 +09:00
Tatsuhiro Tsujikawa
d75ba74bbd Return error if invalid stream_id is given to nghttp2_submit_push_promise 2014-11-29 16:17:02 +09:00
Tatsuhiro Tsujikawa
9ff1925538 Robust GOAWAY handling
This change will utilize last_stream_id in GOAWAY extensively.  When
GOAWAY is received with a last_stream_id, library closes all outgoing
streams whose stream_id > received last_stream_id.
nghttp2_on_stream_callback is called for each stream to be closed.

When GOAWAY is sent with a last_stream_id, library closes all incoming
streams whose stream_id > sent last_stream_id.
nghttp2_on_stream_callback is called for each stream to be closed.
2014-11-29 16:02:13 +09:00
Tatsuhiro Tsujikawa
1915408096 doc: Add language attribute in asio_http2.h.rst.in 2014-11-28 02:01:59 +09:00
Tatsuhiro Tsujikawa
45801883ba Cleanup previous commit 2014-11-28 01:35:12 +09:00
Tatsuhiro Tsujikawa
382a328ead Issue connection error if client receives HEADERS with idle stream ID
If stream ID is not idle, it might be valid HEADERS.  If stream ID is
idle, it is invalid regardless stream ID is even or odd, since client
is not expected to recieve request from server.  nghttp2 library
historically allows this, but now we forbids this.
2014-11-28 01:22:57 +09:00
Tatsuhiro Tsujikawa
babfa41424 Just ignore HEADERS with non-idle stream ID and not found in stream map 2014-11-28 01:01:33 +09:00
Tatsuhiro Tsujikawa
204ff787fa nghttpx: Submit RST_STREAM if HEADERS appears in the middle of a stream 2014-11-28 00:23:46 +09:00
Tatsuhiro Tsujikawa
2a68cc7076 Merge branch 'clang-format' 2014-11-27 23:56:53 +09:00
Tatsuhiro Tsujikawa
b1f807abd1 Reformat lines with clang-format-3.5 2014-11-27 23:56:30 +09:00
Tatsuhiro Tsujikawa
2c830a4698 Add make clang-format 2014-11-27 23:56:29 +09:00
Tatsuhiro Tsujikawa
87ce5068bb Add pre-commit script 2014-11-27 23:56:29 +09:00
Tatsuhiro Tsujikawa
7c794b8d93 Add .clang-format config file and git-clang-format from clang project 2014-11-27 23:56:29 +09:00
Tatsuhiro Tsujikawa
0a406eab94 Add contribution guidelines 2014-11-27 23:56:29 +09:00
Tatsuhiro Tsujikawa
c67ccad74d nghttpx: Use cached get_config()->pid in save_pid() 2014-11-27 22:41:14 +09:00
Tatsuhiro Tsujikawa
5d59adc52b libevent-server: Disable SSLv3 2014-11-27 21:40:34 +09:00
Tatsuhiro Tsujikawa
770cfcaae9 libevent-server: Enable ECDHE ciphers 2014-11-27 21:38:54 +09:00
Tatsuhiro Tsujikawa
04dae32509 nghttpx: Store PID to Config again after daemon() 2014-11-27 21:32:34 +09:00
Tatsuhiro Tsujikawa
3e0813d407 Merge branch 'alagoutte-scan-build' 2014-11-27 21:27:52 +09:00
Tatsuhiro Tsujikawa
c8b83d7024 Merge branch 'scan-build' of https://github.com/alagoutte/nghttp2 into alagoutte-scan-build 2014-11-27 21:25:56 +09:00
Alexis La Goutte
d1285255eb Fix last warning found by Clang Analyzer
nghttp2_session.c:636:3: warning: Branch condition evaluates to a garbage value
2014-11-26 18:20:16 +01:00
Tatsuhiro Tsujikawa
dfbc6e6a57 examples: Guard include config.h with HAVE_CONFIG_H 2014-11-27 00:12:42 +09:00
Tatsuhiro Tsujikawa
2eab5d03fd Merge branch 'alagoutte-Wunused-parameter' 2014-11-26 01:20:21 +09:00
Tatsuhiro Tsujikawa
fe634e5326 Merge branch 'Wunused-parameter' of https://github.com/alagoutte/nghttp2 into alagoutte-Wunused-parameter 2014-11-26 01:16:52 +09:00
Alexis La Goutte
bac44d7ffb Fix -Werror=unused-parameter using _U_ macro 2014-11-25 17:08:09 +01:00
Alexis La Goutte
51b59bc8f0 Remove -Wno-unused-parameter (and add _U_ macro) 2014-11-25 17:08:09 +01:00
Tatsuhiro Tsujikawa
2d10e31931 Merge branch 'andydavies-master' 2014-11-26 00:04:40 +09:00
Andy Davies
4cf7b3cebd Fixed minor typo
turotial -> tutorial
2014-11-25 10:03:10 +00:00
Tatsuhiro Tsujikawa
e11834d1c9 src: Add code in case struct tm.tm_gmtoff is not available 2014-11-24 18:39:35 +09:00
Tatsuhiro Tsujikawa
8f22ff3032 Update man pages 2014-11-24 15:27:41 +09:00
Tatsuhiro Tsujikawa
8e94551881 Handle idle stream in priority field 2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
6e1470c9d3 Remove duplicated code 2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
9416bf9079 Update doc 2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
24f83eef7c Reduce nghttp2_session_get_stream() call before sending frame 2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
b7c0576eb5 Make certain type of HEADERS subject to priority
We make following HEADERS under priority control:
* push response HEADERS
* HEADERS submitted by nghttp2_submit_response

Currently, HEADERS submitted by nghttp2_submit_headers is not attached
to stream.  This is because it may be used as non-final response
header and application may submit final response using
nghttp2_submit_response without checking non-final response header
transmission.
2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
5a48750e16 Assign default weight if NGHTTP2_MAX_DEP_TREE_LENGTH is exceeded 2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
ae93f6345c Allow PRIORITY frame at anytime.
Allowing PRIORITY frame at anytime so that PRIORITY frame to idle
stream can create anchor node in dependency tree.  In this change, we
open stream with new NGHTTP2_STREAM_IDLE state, which is linked in
session->closed_stream_head and is treated as if it is closed stream.
One difference is that if the stream is opened, we remove it from
linked list and change the state to the appropriate one.  To O(1)
removal from linked list, we change session->closed_stream_head to
doubly linked list.
2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
9bba616426 nghttpx: Add $alpn variable to accesslog formatting
$alpn is a variable which represents ALPN identifier of the protocol
which generates the response.
2014-11-24 15:24:09 +09:00
Tatsuhiro Tsujikawa
1fe50f272b nghttpx: Add $pid to --accesslog-format variable
$pid refers to the PID of the running process.
2014-11-24 14:34:43 +09:00
Tatsuhiro Tsujikawa
93023acc6c nghttpx: Make --accesslog-format usage doc help2man friendly
This is unfortunate but help2man behaves badly when there is indented
lines in help messages in commnad-line args.  We removed indentations
to make help2man happy.
2014-11-24 14:16:48 +09:00
Tatsuhiro Tsujikawa
daf659c64e nghttpx: Note the conversion made in <VAR> 2014-11-24 14:04:37 +09:00
Tatsuhiro Tsujikawa
de2a855572 Implement faster formatting for format_iso8601 and format_common_log 2014-11-24 14:00:52 +09:00
Tatsuhiro Tsujikawa
df401f57a2 Merge branch 'LPardue-accesslog_port' 2014-11-24 13:35:47 +09:00
Lucas Pardue
6e178653a5 fixed conflict 2014-11-23 21:10:51 +00:00
Lucas Pardue
9cf1a0c77c Add features to logging, client and server port,
time_iso8601 and request_time.
2014-11-23 20:37:51 +00:00
Tatsuhiro Tsujikawa
ebdbe88bc0 Add contrib/.gitignore 2014-11-23 19:32:54 +09:00
Tatsuhiro Tsujikawa
74ec1d3377 nghttpx: Write accesslog when upstream connection is lost for HTTP/2 and SPDY 2014-11-23 17:24:23 +09:00
Tatsuhiro Tsujikawa
1e4f288a7c nghttpx: Remove misleading logging 2014-11-23 16:45:36 +09:00
Tatsuhiro Tsujikawa
6a21a6f148 Merge branch 'alagoutte-http_parser' 2014-11-22 23:16:40 +09:00
Tatsuhiro Tsujikawa
661b99ec17 Merge branch 'http_parser' of https://github.com/alagoutte/nghttp2 into alagoutte-http_parser 2014-11-22 23:14:44 +09:00
Tatsuhiro Tsujikawa
ecd143fcc2 nghttpx: Send RST_STREAM with NO_ERROR when closing upgraded connection 2014-11-22 23:13:29 +09:00
Tatsuhiro Tsujikawa
bd9389b956 nghttpx: Refactor http2_data_read_callback 2014-11-22 21:12:28 +09:00
Tatsuhiro Tsujikawa
1a09cef0ef nghttpx: Avoid 0-length DATA in HTTP/2 upstream 2014-11-22 21:12:28 +09:00
Alexis La Goutte
aa3a6d5916 Update Third Party lib (http-parser) 2014-11-21 19:45:55 +01:00
Tatsuhiro Tsujikawa
bded1d1115 h2load: Support ALPN 2014-11-22 01:13:18 +09:00
Tatsuhiro Tsujikawa
fa4f03525e nghttp: Fix compile error and warning with libc++ 2014-11-22 00:37:37 +09:00
Tatsuhiro Tsujikawa
4ee89e62fc nghttp2_hd: Refactor a bit 2014-11-21 01:59:20 +09:00
Tatsuhiro Tsujikawa
ee65dea8af nghttp: Fix compile error without libjansson 2014-11-19 21:18:31 +09:00
Tatsuhiro Tsujikawa
27609327ee nghttpx: Fix heap-after-free crash in https upstream
Add Upstream::on_handler_delete() hook to safely write log for
HttpsUpstream.
2014-11-19 01:59:09 +09:00
Tatsuhiro Tsujikawa
958cd0de64 nghttpx: Add configurable access logging format
This commit adds functionality to customize access logging format in
nghttpx.  The format variables are inspired by nginx.  The default
format is combined format.
2014-11-19 01:29:55 +09:00
Tatsuhiro Tsujikawa
1d7601edfb nghttpx: Better handling EOF from downstream connection to tunnel stream 2014-11-18 00:03:52 +09:00
Tatsuhiro Tsujikawa
8a0fdcfea9 nghttpd: Fix crash 2014-11-17 19:01:06 +09:00
Tatsuhiro Tsujikawa
75a1ad8bdb src: format_iso8601: Fix invalid millisecond formatting 2014-11-16 17:32:35 +09:00
Tatsuhiro Tsujikawa
5bac7f0ca6 python: Fix request is not sent without TLS 2014-11-16 17:31:11 +09:00
Tatsuhiro Tsujikawa
08fea5705a python: Fix bug that settings timer is started when SETTINGS with ACK is sent 2014-11-16 17:30:33 +09:00
Tatsuhiro Tsujikawa
8e5b5d00e1 Merge branch 'scoky-master' 2014-11-16 17:27:16 +09:00
Tatsuhiro Tsujikawa
97e8482348 Merge branch 'master' of https://github.com/scoky/nghttp2 into scoky-master 2014-11-16 16:48:07 +09:00
Kyle Schomp
0cc73e279e Pull of the client Python bindings 2014-11-15 16:37:41 +01:00
Tatsuhiro Tsujikawa
54232c6542 nghttp: Add --no-dep option to disable sending priority hints to server 2014-11-15 23:42:26 +09:00
Tatsuhiro Tsujikawa
ee2856f9bc nghttp: Update doc 2014-11-15 23:34:37 +09:00
Tatsuhiro Tsujikawa
737cea0b38 nghttp: Add -r, --har option to output HTTP transactions in HAR format 2014-11-15 23:34:10 +09:00
Tatsuhiro Tsujikawa
a8eeea0b18 Initialize frame header for upgrade SETTINGS frame 2014-11-15 11:30:01 +09:00
Tatsuhiro Tsujikawa
a2bc88f6db nghttpx: Check max length of ALPN field 2014-11-14 23:19:16 +09:00
Tatsuhiro Tsujikawa
5ce8ae79f0 nghttpx: Disable spdy/3 and spdy/2 by default 2014-11-14 23:16:06 +09:00
Tatsuhiro Tsujikawa
d98e9a63d0 src: Refactor code around ALPN setup 2014-11-14 23:14:39 +09:00
Tatsuhiro Tsujikawa
8e30adbca0 asio: Add http2::backlog API function 2014-11-10 23:26:01 +09:00
Tatsuhiro Tsujikawa
9adfd08848 asio_http2_handler: Use util::utos instead of std::to_string 2014-11-10 22:39:20 +09:00
Tatsuhiro Tsujikawa
2e3419ccbb nghttpd: Cache formatted date string 2014-11-10 22:35:08 +09:00
Tatsuhiro Tsujikawa
5b6b6dc1b7 src: Rewrite http_date 2014-11-10 21:53:19 +09:00
Tatsuhiro Tsujikawa
d0271a90b5 nghttpd: Use util::utos instead of slow util::to_str 2014-11-10 21:23:26 +09:00
Tatsuhiro Tsujikawa
20ffe2b2a0 tiny-nghttpd: Fix memory leak 2014-11-10 21:20:44 +09:00
Tatsuhiro Tsujikawa
94c80e2507 Bump up version number to 0.6.7-DEV 2014-11-08 23:40:23 +09:00
354 changed files with 56093 additions and 34220 deletions

57
.clang-format Normal file
View File

@@ -0,0 +1,57 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AlwaysBreakTemplateDeclarations: false
AlwaysBreakBeforeMultilineStrings: false
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: false
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: false
IndentWrappedFunctionNames: false
IndentFunctionDeclarationAfterType: false
MaxEmptyLinesToKeep: 1
KeepEmptyLinesAtTheStartOfBlocks: true
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
SpacesBeforeTrailingComments: 1
Cpp11BracedListStyle: true
Standard: Cpp11
IndentWidth: 2
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Attach
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
SpaceBeforeParens: ControlStatements
DisableFormat: false
...

47
.gitignore vendored
View File

@@ -1,14 +1,18 @@
# emacs backup file
*~
*.o
*.lo
# autotools
*.la
depcomp
*.lo
*.m4
*.o
.deps/
.libs/
INSTALL
Makefile
Makefile.in
libtool
missing
autom4te.cache/
compile
config.guess
config.h
config.h.in
@@ -16,33 +20,14 @@ config.log
config.status
config.sub
configure
depcomp
install-sh
.deps/
.libs
lib/includes/nghttp2/nghttp2ver.h
lib/libnghttp2.pc
src/libnghttp2_asio.pc
libtool
ltmain.sh
missing
stamp-h1
.deps/
INSTALL
.DS_STORE
compile
test-driver
.dirstamp
doc/index.rst
doc/nghttp2.h.rst
doc/nghttp2ver.h.rst
doc/package_README.rst
doc/tutorial-client.rst
doc/tutorial-server.rst
doc/nghttpx-howto.rst
doc/h2load-howto.rst
doc/tutorial-hpack.rst
doc/python-apiref.rst
doc/building-android-binary.rst
doc/asio_http2.h.rst
doc/libnghttp2_asio.rst
python/setup.py
python/dist
python/MANIFEST
# test logs generated by `make check`
*.log
*.trs

View File

@@ -1,32 +1,31 @@
language: cpp
compiler:
- clang
#Disable gcc build for the moment...
# - gcc
python:
- "3.4"
- gcc
sudo: false
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.9
- libstdc++-4.9-dev
- autoconf
- automake
- autotools-dev
- libtool
- pkg-config
- zlib1g-dev
- libcunit1-dev
- libssl-dev
- libxml2-dev
- libev-dev
- libevent-dev
- libjansson-dev
- libjemalloc-dev
before_install:
- $CC --version
- sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
#Install and use gcc-4.8 (don't build with gcc-4.6)
#libstdc++-4.8 is needed by Clang to build too
- sudo apt-get -qq install g++-4.8 libstdc++-4.8-dev
- >
sudo apt-get install --no-install-recommends -qq
autoconf
automake
autotools-dev
libtool
pkg-config
zlib1g-dev
libcunit1-dev
libssl-dev
libxml2-dev
libevent-dev
libjansson-dev
libjemalloc-dev
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
- $CC --version
before_script:
- autoreconf -i

18
CONTRIBUTION Normal file
View File

@@ -0,0 +1,18 @@
[The text below was composed based on 1.2. License section of
curl/libcurl project.]
When contributing with code, you agree to put your changes and new
code under the same license nghttp2 is already using unless stated and
agreed otherwise.
When changing existing source code, you do not alter the copyright of
the original file(s). The copyright will still be owned by the
original creator(s) or those who have been assigned copyright by the
original author(s).
By submitting a patch to the nghttp2 project, you are assumed to have
the right to the code and to be allowed by your employer or whatever
to hand over that patch/code to us. We will credit you for your
changes as far as possible, to give credit but also to keep a trace
back to who made what changes. Please always provide us with your
full real name when contributing!

21
COPYING
View File

@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2012, 2014 Tatsuhiro Tsujikawa
Copyright (c) 2012, 2014, 2015 Tatsuhiro Tsujikawa
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -20,22 +20,3 @@ 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.
[The text below was composed based on 1.2. License section of
curl/libcurl project.]
When contributing with code, you agree to put your changes and new
code under the same license nghttp2 is already using unless stated and
agreed otherwise.
When changing existing source code, you do not alter the copyright of
the original file(s). The copyright will still be owned by the
original creator(s) or those who have been assigned copyright by the
original author(s).
By submitting a patch to the nghttp2 project, you are assumed to have
the right to the code and to be allowed by your employer or whatever
to hand over that patch/code to us. We will credit you for your
changes as far as possible, to give credit but also to keep a trace
back to who made what changes. Please always provide us with your
full real name when contributing!

View File

@@ -1,3 +1,4 @@
# vim: ft=dockerfile:
# Dockerfile to build nghttp2 android binary
#
# $ sudo docker build -t nghttp2-android - < Dockerfile.android
@@ -9,7 +10,7 @@
#
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
FROM ubuntu
FROM ubuntu:vivid
MAINTAINER Tatsuhiro Tsujikawa
@@ -29,11 +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
RUN chmod a+x android-ndk-r10c-linux-x86_64.bin
RUN ./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 \
@@ -57,18 +59,24 @@ RUN autoreconf -i && \
make install
WORKDIR /root/build
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.1j.tar.gz
RUN tar xf openssl-1.0.1j.tar.gz
WORKDIR /root/build/openssl-1.0.1j
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.2a.tar.gz && \
tar xf openssl-1.0.2a.tar.gz && \
rm openssl-1.0.2a.tar.gz
WORKDIR /root/build/openssl-1.0.2a
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
./Configure --prefix=$PREFIX android && \
make && make install_sw
WORKDIR /root/build
RUN curl -L -O https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
RUN tar xf libevent-2.0.21-stable.tar.gz
WORKDIR /root/build/libevent-2.0.21-stable
RUN ./configure \
RUN curl -L -O http://dist.schmorp.de/libev/libev-4.19.tar.gz && \
curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch && \
tar xf libev-4.19.tar.gz && \
rm libev-4.19.tar.gz
WORKDIR /root/build/libev-4.19
RUN patch -p1 < ../libev-4.19-android.patch && \
./configure \
--host=arm-linux-androideabi \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--prefix=$PREFIX \
@@ -78,6 +86,25 @@ RUN ./configure \
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
@@ -93,8 +120,9 @@ RUN autoreconf -i && \
--disable-threads \
LIBSPDYLAY_CFLAGS=-I$PREFIX/usr/local/include \
LIBSPDYLAY_LIBS="-L$PREFIX/usr/local/lib -lspdylay" \
CPPFLAGS="-I$PREFIX/include" \
CPPFLAGS="-fPIE -I$PREFIX/include" \
CXXFLAGS="-fno-strict-aliasing" \
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-L$PREFIX/lib" && \
LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
make && \
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp

View File

@@ -20,7 +20,8 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = lib third-party src examples python tests doc contrib
SUBDIRS = lib third-party src examples python tests integration-tests \
doc contrib script
ACLOCAL_AMFLAGS = -I m4
@@ -28,3 +29,15 @@ dist_doc_DATA = README.rst
EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make \
Dockerfile.android
.PHONY: clang-format
# Format source files using clang-format. Don't format source files
# under third-party directory since we are not responsible for thier
# coding style.
clang-format:
CLANGFORMAT=`git config --get clangformat.binary`; \
test -z $${CLANGFORMAT} && CLANGFORMAT="clang-format"; \
$${CLANGFORMAT} -i lib/*.{c,h} lib/includes/nghttp2/*.h \
src/*.{c,cc,h} src/includes/nghttp2/*.h examples/*.{c,cc} \
tests/*.{c,h}

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,9 @@ PATH=$TOOLCHAIN/bin:$PATH
--without-libxml2 \
--disable-python-bindings \
--disable-examples \
--disable-threads \
CPPFLAGS="-I$PREFIX/include" \
--enable-werror \
CC=clang \
CXX=clang++ \
CPPFLAGS="-fPIE -I$PREFIX/include" \
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-L$PREFIX/lib"
LDFLAGS="-fPIE -pie -L$PREFIX/lib"

View File

@@ -1,6 +1,6 @@
dnl nghttp2 - HTTP/2 C Library
dnl Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
dnl Copyright (c) 2012, 2013, 2014, 2015 Tatsuhiro Tsujikawa
dnl Permission is hereby granted, free of charge, to any person obtaining
dnl a copy of this software and associated documentation files (the
@@ -20,15 +20,36 @@ dnl NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
dnl LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
dnl OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
dnl WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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.6.6], [t-tujikawa@users.sourceforge.net])
AC_INIT([nghttp2], [1.0.4], [t-tujikawa@users.sourceforge.net])
AC_USE_SYSTEM_EXTENSIONS
LT_PREREQ([2.2.6])
LT_INIT()
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([subdir-objects])
# comment out for now since this requires automake 1.13 or higher and
# travis has older one.
# AM_EXTRA_RECURSIVE_TARGETS([it])
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, 7)
AC_SUBST(LT_REVISION, 1)
AC_SUBST(LT_AGE, 2)
AC_SUBST(LT_CURRENT, 14)
AC_SUBST(LT_REVISION, 4)
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"`
@@ -38,18 +59,6 @@ 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])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_HEADERS([config.h])
dnl Checks for command-line options
AC_ARG_ENABLE([werror],
[AS_HELP_STRING([--enable-werror],
@@ -92,9 +101,9 @@ AC_ARG_ENABLE([python-bindings],
[request_python_bindings=$enableval], [request_python_bindings=check])
AC_ARG_ENABLE([failmalloc],
[AS_HELP_STRING([--enable-failmalloc],
[Build failmalloc test program [default=no]])],
[request_failmalloc=$enableval], [request_failmalloc=no])
[AS_HELP_STRING([--disable-failmalloc],
[Do not build failmalloc test program])],
[request_failmalloc=$enableval], [request_failmalloc=yes])
AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2],
@@ -122,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
@@ -140,6 +152,20 @@ else
AC_SUBST([CYTHON])
fi
#
# If we're running GCC or clang define _U_ to be "__attribute__((unused))"
# so we can use _U_ to flag unused function parameters and not get warnings
# about them. Otherwise, define _U_ to be an empty string so that _U_ used
# to flag an unused function parameters will compile with other compilers.
#
# XXX - similar hints for other compilers?
#
if test "x$GCC" = "xyes" -o "x$CC" = "xclang" ; then
AC_DEFINE([_U_], [__attribute__((unused))], [Hint to the compiler that a function parameters is not used])
else
AC_DEFINE([_U_], , [Hint to the compiler that a function parameters is not used])
fi
AX_CXX_COMPILE_STDCXX_11([noext], [optional])
AC_LANG_PUSH(C++)
@@ -179,53 +205,49 @@ std::vector<std::future<int>> v;
[have_std_future=no
AC_MSG_RESULT([no])])
# Check that std::map::emplace is available for g++-4.7.
AC_MSG_CHECKING([whether std::map::emplace is available])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[
#include <map>
]],
[[
std::map<int, int>().emplace(1, 2);
]])],
[AC_DEFINE([HAVE_STD_MAP_EMPLACE], [1],
[Define to 1 if you have the `std::map::emplace`.])
have_std_map_emplace=yes
AC_MSG_RESULT([yes])],
[have_std_map_emplace=no
AC_MSG_RESULT([no])])
AC_LANG_POP()
# Checks for libraries.
# Additional libraries required for tests.
TESTS_LIBS=
TESTLDADD=
# Additional libraries required for programs under src directory.
SRC_LIBS=
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])
TESTS_LIBS="$LIBS $TESTS_LIBS"
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`.])])
SRC_LIBS="$LIBS $SRC_LIBS"
LIBS=$LIBS_OLD
APPLDFLAGS=
case "$host" in
*android*)
android_build=yes
# android does not need -pthread, but needs followng 2 libs for C++
SRC_LIBS="$SRC_LIBS -lstdc++ -lsupc++"
# android does not need -pthread, but needs followng 3 libs for C++
APPLDFLAGS="$APPLDFLAGS -lstdc++ -latomic -lsupc++"
;;
*)
PTHREAD_LDFLAGS="-pthread"
SRC_LIBS="$SRC_LIBS $PTHREAD_LDFLAGS"
APPLDFLAGS="$APPLDFLAGS $PTHREAD_LDFLAGS"
;;
esac
# zlib
if test "x$android_build" = "xyes"; then
# Use zlib provided by NDK
SRC_LIBS="-lz $SRC_LIBS"
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
AC_MSG_NOTICE($ZLIB_PKG_ERRORS)
fi
if test "x${have_zlib}" = "xno"; then
AC_MSG_NOTICE($ZLIB_PKG_ERRORS)
fi
# cunit
@@ -257,6 +279,22 @@ fi
AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ])
# libev (for src)
# libev does not have pkg-config file. Check it in an old way.
LIBS_OLD=$LIBS
# android requires -lm for floor
AC_CHECK_LIB([ev], [ev_time], [have_libev=yes], [have_libev=no], [-lm])
if test "x${have_libev}" = "xyes"; then
AC_CHECK_HEADER([ev.h], [have_libev=yes], [have_libev=no])
if test "x${have_libev}" = "xyes"; then
LIBEV_LIBS=-lev
LIBEV_CFLAGS=
AC_SUBST([LIBEV_LIBS])
AC_SUBST([LIBEV_CFLAGS])
fi
fi
LIBS=$LIBS_OLD
# openssl (for src)
PKG_CHECK_MODULES([OPENSSL], [openssl >= 1.0.1],
[have_openssl=yes], [have_openssl=no])
@@ -264,7 +302,7 @@ if test "x${have_openssl}" = "xno"; then
AC_MSG_NOTICE($OPENSSL_PKG_ERRORS)
fi
# libevent_openssl (for src)
# libevent_openssl (for examples)
# 2.0.8 is required because we use evconnlistener_set_error_cb()
PKG_CHECK_MODULES([LIBEVENT_OPENSSL], [libevent_openssl >= 2.0.8],
[have_libevent_openssl=yes], [have_libevent_openssl=no])
@@ -272,10 +310,13 @@ if test "x${have_libevent_openssl}" = "xno"; then
AC_MSG_NOTICE($LIBEVENT_OPENSSL_PKG_ERRORS)
fi
# jansson (for hdtest/deflatehd and hdtest/inflatehd)
# 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}" == "xno"; then
if test "x${have_jansson}" = "xyes"; then
AC_DEFINE([HAVE_JANSSON], [1],
[Define to 1 if you have `libjansson` library.])
else
AC_MSG_NOTICE($JANSSON_PKG_ERRORS)
fi
@@ -302,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
@@ -317,7 +372,7 @@ fi
# spdylay (for src/nghttpx and src/h2load)
have_spdylay=no
if test "x${request_spdylay}" != "xno"; then
PKG_CHECK_MODULES([LIBSPDYLAY], [libspdylay >= 1.3.0],
PKG_CHECK_MODULES([LIBSPDYLAY], [libspdylay >= 1.3.2],
[have_spdylay=yes], [have_spdylay=no])
if test "x${have_spdylay}" = "xyes"; then
AC_DEFINE([HAVE_SPDYLAY], [1], [Define to 1 if you have `spdylay` library.])
@@ -354,12 +409,12 @@ if test "x${request_asio_lib}" = "xyes"; then
fi
# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL
# and libevent_openssl
# and libev
enable_app=no
if test "x${request_app}" != "xno" &&
test "x${have_zlib}" = "xyes" &&
test "x${have_openssl}" = "xyes" &&
test "x${have_libevent_openssl}" = "xyes"; then
test "x${have_libev}" = "xyes"; then
enable_app=yes
fi
@@ -409,6 +464,17 @@ fi
AM_CONDITIONAL([ENABLE_EXAMPLES], [ test "x${enable_examples}" = "xyes" ])
# third-party only be built when needed
enable_third_party=no
if test "x${enable_examples}" = "xyes" ||
test "x${enable_app}" = "xyes" ||
test "x${enable_asio_lib}" = "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" &&
@@ -431,29 +497,34 @@ AM_CONDITIONAL([ENABLE_PYTHON_BINDINGS],
AM_CONDITIONAL([HAVE_CYTHON], [test "x${CYTHON}" != "x"])
# failmalloc tests
enable_failmalloc=no
if test "x${request_failmalloc}" = "xyes"; then
enable_failmalloc=yes
fi
AM_CONDITIONAL([ENABLE_FAILMALLOC], [ test "x${enable_failmalloc}" = "xyes" ])
# Checks for header files.
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 \
])
case "${host}" in
*mingw*)
# For ntohl, ntohs in Windows
AC_CHECK_HEADERS([winsock2.h])
;;
esac
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
@@ -461,19 +532,62 @@ 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],
[have_struct_tm_tm_gmtoff=no], [[#include <time.h>]])
if test "x$have_struct_tm_tm_gmtoff" = "xyes"; then
AC_DEFINE([HAVE_STRUCT_TM_TM_GMTOFF], [1],
[Define to 1 if you have `struct tm.tm_gmtoff` member.])
fi
# Check size of pointer to decide we need 8 bytes alignment
# adjustment.
AC_CHECK_SIZEOF([int *])
# Checks for library functions.
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 \
])
@@ -490,12 +604,8 @@ AM_CONDITIONAL([ENABLE_TINY_NGHTTPD],
[ test "x${have_epoll}" = "xyes" &&
test "x${have_timerfd_create}" = "xyes"])
dnl Windows library for winsock2
case "${host}" in
*mingw*)
LIBS="$LIBS -lws2_32"
;;
esac
ac_save_CFLAGS=$CFLAGS
CFLAGS=
if test "x$werror" != "xno"; then
AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"])
@@ -518,7 +628,6 @@ if test "x$werror" != "xno"; then
AX_CHECK_COMPILE_FLAG([-Wcast-align], [CFLAGS="$CFLAGS -Wcast-align"])
AX_CHECK_COMPILE_FLAG([-Wclobbered], [CFLAGS="$CFLAGS -Wclobbered"])
AX_CHECK_COMPILE_FLAG([-Wvla], [CFLAGS="$CFLAGS -Wvla"])
AX_CHECK_COMPILE_FLAG([-Wno-unused-parameter], [CFLAGS="$CFLAGS -Wno-unused-parameter"])
AX_CHECK_COMPILE_FLAG([-Wpragmas], [CFLAGS="$CFLAGS -Wpragmas"])
AX_CHECK_COMPILE_FLAG([-Wunreachable-code], [CFLAGS="$CFLAGS -Wunreachable-code"])
AX_CHECK_COMPILE_FLAG([-Waddress], [CFLAGS="$CFLAGS -Waddress"])
@@ -530,18 +639,26 @@ if test "x$werror" != "xno"; then
AX_CHECK_COMPILE_FLAG([-Wheader-guard], [CFLAGS="$CFLAGS -Wheader-guard"])
fi
WARNCFLAGS=$CFLAGS
CFLAGS=$ac_save_CFLAGS
AC_SUBST([WARNCFLAGS])
if test "x$debug" != "xno"; then
AC_DEFINE([DEBUGBUILD], [1], [Define to 1 to enable debug output.])
fi
enable_threads=yes
# Some platform does not have working std::future. We disable
# threading for those platforms to exclude std::future use.
if test "x$threads" != "xyes" || test "x$have_std_future" != "xyes"; then
# threading for those platforms.
if test "x$threads" != "xyes" ||
test "x$have_std_future" != "xyes"; then
enable_threads=no
AC_DEFINE([NOTHREADS], [1], [Define to 1 if you want to disable threads.])
fi
AC_SUBST([TESTS_LIBS])
AC_SUBST([SRC_LIBS])
AC_SUBST([TESTLDADD])
AC_SUBST([APPLDFLAGS])
AC_CONFIG_FILES([
Makefile
@@ -558,6 +675,9 @@ AC_CONFIG_FILES([
examples/Makefile
python/Makefile
python/setup.py
integration-tests/Makefile
integration-tests/config.go
integration-tests/setenv
doc/Makefile
doc/conf.py
doc/index.rst
@@ -573,7 +693,11 @@ AC_CONFIG_FILES([
doc/nghttp2.h.rst
doc/nghttp2ver.h.rst
doc/asio_http2.h.rst
doc/asio_http2_server.h.rst
doc/asio_http2_client.h.rst
doc/contribute.rst
contrib/Makefile
script/Makefile
])
AC_OUTPUT
@@ -584,6 +708,7 @@ AC_MSG_NOTICE([summary of build options:
Install prefix: ${prefix}
C compiler: ${CC}
CFLAGS: ${CFLAGS}
WARNCFLAGS: ${WARNCFLAGS}
LDFLAGS: ${LDFLAGS}
LIBS: ${LIBS}
CPPFLAGS: ${CPPFLAGS}
@@ -592,29 +717,37 @@ AC_MSG_NOTICE([summary of build options:
CXXFLAGS: ${CXXFLAGS}
CXXCPP: ${CXXCPP}
Library types: Shared=${enable_shared}, Static=${enable_static}
Python: ${PYTHON}
PYTHON_VERSION: ${PYTHON_VERSION}
pyexecdir: ${pyexecdir}
Python-dev: ${have_python_dev}
PYTHON_CPPFLAGS:${PYTHON_CPPFLAGS}
PYTHON_LDFLAGS: ${PYTHON_LDFLAGS}
Cython: ${CYTHON}
CUnit: ${have_cunit}
OpenSSL: ${have_openssl}
Libxml2: ${have_libxml2}
Libevent(SSL): ${have_libevent_openssl}
Spdylay: ${have_spdylay}
Jansson: ${have_jansson}
Jemalloc: ${have_jemalloc}
Boost CPPFLAGS: ${BOOST_CPPFLAGS}
Boost LDFLAGS: ${BOOST_LDFLAGS}
Boost::ASIO: ${BOOST_ASIO_LIB}
Boost::System: ${BOOST_SYSTEM_LIB}
Boost::Thread: ${BOOST_THREAD_LIB}
Applications: ${enable_app}
HPACK tools: ${enable_hpack_tools}
Libnghttp2_asio:${enable_asio_lib}
Examples: ${enable_examples}
Python bindings:${enable_python_bindings}
Failmalloc: ${request_failmalloc}
Python:
Python: ${PYTHON}
PYTHON_VERSION: ${PYTHON_VERSION}
pyexecdir: ${pyexecdir}
Python-dev: ${have_python_dev}
PYTHON_CPPFLAGS:${PYTHON_CPPFLAGS}
PYTHON_LDFLAGS: ${PYTHON_LDFLAGS}
Cython: ${CYTHON}
Test:
CUnit: ${have_cunit}
Failmalloc: ${enable_failmalloc}
Libs:
OpenSSL: ${have_openssl}
Libxml2: ${have_libxml2}
Libev: ${have_libev}
Libevent(SSL): ${have_libevent_openssl}
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}
Boost::System: ${BOOST_SYSTEM_LIB}
Boost::Thread: ${BOOST_THREAD_LIB}
Features:
Applications: ${enable_app}
HPACK tools: ${enable_hpack_tools}
Libnghttp2_asio:${enable_asio_lib}
Examples: ${enable_examples}
Python bindings:${enable_python_bindings}
Threading: ${enable_threads}
Third-party: ${enable_third_party}
])

3
contrib/.gitignore vendored Normal file
View File

@@ -0,0 +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
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`
endscript
weekly
rotate 52
missingok
compress
delaycompress
notifempty
postrotate
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

23
doc/.gitignore vendored
View File

@@ -1,3 +1,24 @@
# generated files
apiref.rst
asio_http2.h.rst
asio_http2_client.h.rst
asio_http2_server.h.rst
building-android-binary.rst
conf.py
manual
contribute.rst
enums.rst
h2load-howto.rst
index.rst
libnghttp2_asio.rst
macros.rst
manual/
nghttp2.h.rst
nghttp2_*.rst
nghttp2ver.h.rst
nghttpx-howto.rst
package_README.rst
python-apiref.rst
tutorial-client.rst
tutorial-hpack.rst
tutorial-server.rst
types.rst

View File

@@ -23,10 +23,111 @@
man_MANS = nghttp.1 nghttpd.1 nghttpx.1 h2load.1
APIDOCS= \
apiref.rst \
macros.rst \
enums.rst \
types.rst \
nghttp2_check_header_name.rst \
nghttp2_check_header_value.rst \
nghttp2_hd_deflate_bound.rst \
nghttp2_hd_deflate_change_table_size.rst \
nghttp2_hd_deflate_del.rst \
nghttp2_hd_deflate_hd.rst \
nghttp2_hd_deflate_new.rst \
nghttp2_hd_deflate_new2.rst \
nghttp2_hd_inflate_change_table_size.rst \
nghttp2_hd_inflate_del.rst \
nghttp2_hd_inflate_end_headers.rst \
nghttp2_hd_inflate_hd.rst \
nghttp2_hd_inflate_new.rst \
nghttp2_hd_inflate_new2.rst \
nghttp2_is_fatal.rst \
nghttp2_nv_compare_name.rst \
nghttp2_option_del.rst \
nghttp2_option_new.rst \
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_no_recv_client_magic.rst \
nghttp2_pack_settings_payload.rst \
nghttp2_priority_spec_check_default.rst \
nghttp2_priority_spec_default_init.rst \
nghttp2_priority_spec_init.rst \
nghttp2_select_next_protocol.rst \
nghttp2_session_callbacks_del.rst \
nghttp2_session_callbacks_new.rst \
nghttp2_session_callbacks_set_before_frame_send_callback.rst \
nghttp2_session_callbacks_set_data_source_read_length_callback.rst \
nghttp2_session_callbacks_set_on_begin_frame_callback.rst \
nghttp2_session_callbacks_set_on_begin_headers_callback.rst \
nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst \
nghttp2_session_callbacks_set_on_frame_not_send_callback.rst \
nghttp2_session_callbacks_set_on_frame_recv_callback.rst \
nghttp2_session_callbacks_set_on_frame_send_callback.rst \
nghttp2_session_callbacks_set_on_header_callback.rst \
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback.rst \
nghttp2_session_callbacks_set_on_stream_close_callback.rst \
nghttp2_session_callbacks_set_recv_callback.rst \
nghttp2_session_callbacks_set_select_padding_callback.rst \
nghttp2_session_callbacks_set_send_callback.rst \
nghttp2_session_callbacks_set_send_data_callback.rst \
nghttp2_session_client_new.rst \
nghttp2_session_client_new2.rst \
nghttp2_session_client_new3.rst \
nghttp2_session_consume.rst \
nghttp2_session_consume_connection.rst \
nghttp2_session_consume_stream.rst \
nghttp2_session_del.rst \
nghttp2_session_get_effective_local_window_size.rst \
nghttp2_session_get_effective_recv_data_length.rst \
nghttp2_session_get_last_proc_stream_id.rst \
nghttp2_session_get_next_stream_id.rst \
nghttp2_session_get_outbound_queue_size.rst \
nghttp2_session_get_remote_settings.rst \
nghttp2_session_get_remote_window_size.rst \
nghttp2_session_get_stream_effective_local_window_size.rst \
nghttp2_session_get_stream_effective_recv_data_length.rst \
nghttp2_session_get_stream_local_close.rst \
nghttp2_session_get_stream_remote_close.rst \
nghttp2_session_get_stream_remote_window_size.rst \
nghttp2_session_get_stream_user_data.rst \
nghttp2_session_mem_recv.rst \
nghttp2_session_mem_send.rst \
nghttp2_session_recv.rst \
nghttp2_session_resume_data.rst \
nghttp2_session_send.rst \
nghttp2_session_server_new.rst \
nghttp2_session_server_new2.rst \
nghttp2_session_server_new3.rst \
nghttp2_session_set_next_stream_id.rst \
nghttp2_session_set_stream_user_data.rst \
nghttp2_session_terminate_session.rst \
nghttp2_session_terminate_session2.rst \
nghttp2_session_upgrade.rst \
nghttp2_session_want_read.rst \
nghttp2_session_want_write.rst \
nghttp2_strerror.rst \
nghttp2_submit_data.rst \
nghttp2_submit_goaway.rst \
nghttp2_submit_headers.rst \
nghttp2_submit_ping.rst \
nghttp2_submit_priority.rst \
nghttp2_submit_push_promise.rst \
nghttp2_submit_request.rst \
nghttp2_submit_response.rst \
nghttp2_submit_rst_stream.rst \
nghttp2_submit_settings.rst \
nghttp2_submit_shutdown_notice.rst \
nghttp2_submit_trailer.rst \
nghttp2_submit_window_update.rst \
nghttp2_version.rst
EXTRA_DIST = \
mkapiref.py \
README.rst \
apiref-header.rst \
programmers-guide.rst \
$(APIDOCS) \
nghttp.1.rst \
nghttpd.1.rst \
nghttpx.1.rst \
@@ -40,24 +141,29 @@ EXTRA_DIST = \
sources/libnghttp2_asio.rst \
sources/python-apiref.rst \
sources/building-android-binary.rst \
_themes/sphinx_rtd_theme/footer.html \
_themes/sphinx_rtd_theme/theme.conf \
_themes/sphinx_rtd_theme/layout_old.html \
sources/contribute.rst \
_themes/sphinx_rtd_theme/__init__.py \
_themes/sphinx_rtd_theme/layout.html \
_themes/sphinx_rtd_theme/search.html \
_themes/sphinx_rtd_theme/breadcrumbs.html \
_themes/sphinx_rtd_theme/versions.html \
_themes/sphinx_rtd_theme/footer.html \
_themes/sphinx_rtd_theme/layout.html \
_themes/sphinx_rtd_theme/layout_old.html \
_themes/sphinx_rtd_theme/search.html \
_themes/sphinx_rtd_theme/searchbox.html \
_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf \
_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg \
_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff \
_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot \
_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf \
_themes/sphinx_rtd_theme/static/js/theme.js \
_themes/sphinx_rtd_theme/static/css/theme.css \
_themes/sphinx_rtd_theme/static/css/badge_only.css \
$(man_MANS)
_themes/sphinx_rtd_theme/static/css/theme.css \
_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf \
_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot \
_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg \
_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf \
_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff \
_themes/sphinx_rtd_theme/static/js/theme.js \
_themes/sphinx_rtd_theme/theme.conf \
_themes/sphinx_rtd_theme/versions.html \
$(man_MANS) \
bash_completion/nghttp \
bash_completion/nghttpd \
bash_completion/nghttpx \
bash_completion/h2load
# Makefile for Sphinx documentation
#
@@ -94,16 +200,33 @@ help:
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
apiref.rst: $(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
apiref.rst macros.rst enums.rst types.rst: \
$(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
--header $(top_srcdir)/doc/apiref-header.rst $^ > $@
$@ macros.rst enums.rst types.rst . $^
# Inspired by
# http://www.gnu.org/savannah-checkouts/gnu/automake/manual/html_node/Multiple-Outputs.html
apidoc.stamp: $(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
@rm -f apidoc.tmp
@touch apidoc.tmp
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
$@ macros.rst enums.rst types.rst . $^
@mv -f apidoc.tmp $@
$(APIDOC): apidoc.stamp
## Recover from the removal of $@
@if test -f $@; then :; else \
rm -f apidoc.stamp; \
$(MAKE) $(AM_MAKEFLAGS) apidoc.stamp; \
fi
clean-local:
-rm apiref.rst
-rm $(APIDOCS)
-rm -rf $(BUILDDIR)/*
html: apiref.rst
html-local: apiref.rst
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
@@ -175,7 +298,7 @@ text:
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
man: apiref.rst
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."

View File

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

View File

@@ -6,12 +6,16 @@
{% endfor %}
<li>{{ title }}</li>
<li class="wy-breadcrumbs-aside">
{% if display_github %}
<a href="https://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 %}
<a href="https://bitbucket.org/{{ bitbucket_user }}/{{ bitbucket_repo }}/src/{{ bitbucket_version}}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-bitbucket"> Edit on Bitbucket</a>
{% elif show_source and has_source and sourcename %}
<a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow"> View page source</a>
{% 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 %}
<a href="https://bitbucket.org/{{ bitbucket_user }}/{{ bitbucket_repo }}/src/{{ bitbucket_version}}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-bitbucket"> Edit on Bitbucket</a>
{% elif show_source and source_url_prefix %}
<a href="{{ source_url_prefix }}{{ pagename }}{{ source_suffix }}">View page source</a>
{% 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>

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 %}
@@ -28,5 +28,9 @@
</p>
</div>
{% trans %}<a href="https://github.com/snide/sphinx_rtd_theme">Sphinx theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}
{%- if show_sphinx %}
{% trans %}Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}.
{%- endif %}
</footer>

View File

@@ -12,6 +12,7 @@
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
{{ metatags }}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block htmltitle %}
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
@@ -23,7 +24,6 @@
{% endif %}
{# CSS #}
<link href='https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
{# OPENSEARCH #}
{% if not embedded %}
@@ -42,6 +42,10 @@
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
{% endfor %}
{% for cssfile in extra_css_files %}
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
{% endfor %}
{%- block linktags %}
{%- if hasdoc('about') %}
<link rel="author" title="{{ _('About these documents') }}"
@@ -71,7 +75,7 @@
{%- block extrahead %} {% endblock %}
{# Keep modernizr in head - http://modernizr.com/docs/#installing #}
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js"></script>
<script src="_static/js/modernizr.min.js"></script>
</head>
@@ -83,19 +87,34 @@
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-nav-search">
{% block sidebartitle %}
<a href="{{ pathto(master_doc) }}" class="fa fa-home"> {{ project }}</a>
{% endblock %}
{% if logo and theme_logo_only %}
<a href="{{ pathto(master_doc) }}">
{% else %}
<a href="{{ pathto(master_doc) }}" class="icon icon-home"> {{ project }}
{% endif %}
{% if logo %}
{# Not strictly valid HTML, but it's the only way to display/scale it properly, without weird scripting or heaps of work #}
<img src="{{ pathto('_static/' + logo, 1) }}" class="logo" />
{% endif %}
</a>
{% include "searchbox.html" %}
{% endblock %}
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
{% set toctree = toctree(maxdepth=2, collapse=False, includehidden=True) %}
{% if toctree %}
{{ toctree }}
{% else %}
<!-- Local TOC -->
<div class="local-toc">{{ toc }}</div>
{% endif %}
{% block menu %}
{% set toctree = toctree(maxdepth=4, collapse=False, includehidden=True) %}
{% if toctree %}
{{ toctree }}
{% else %}
<!-- Local TOC -->
<div class="local-toc">{{ toc }}</div>
{% endif %}
{% endblock %}
</div>
&nbsp;
</nav>

View File

@@ -1,7 +1,9 @@
{%- if builder != 'singlehtml' %}
<div role="search">
<form id ="rtd-search-form" class="wy-form" action="{{ pathto('search') }}" method="get">
<form id="rtd-search-form" class="wy-form" action="{{ pathto('search') }}" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
{%- endif %}

View File

@@ -0,0 +1,7 @@
{
"version": 3,
"mappings": "CAyDA,SAAY,EACV,qBAAsB,EAAE,UAAW,EAqDrC,QAAS,EARP,IAAK,EAAE,AAAC,EACR,+BAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,cAAO,EACL,IAAK,EAAE,GAAI,EC1Gb,SAkBC,EAjBC,UAAW,ECFJ,UAAW,EDGlB,UAAW,EAHqC,KAAM,EAItD,SAAU,EAJsD,KAAM,EAapE,EAAG,EAAE,qCAAwB,EAC7B,EAAG,EAAE,0PAAyE,ECZpF,SAAU,EACR,MAAO,EAAE,WAAY,EACrB,UAAW,EAAE,UAAW,EACxB,SAAU,EAAE,KAAM,EAClB,UAAW,EAAE,KAAM,EACnB,UAAW,EAAE,AAAC,EACd,cAAe,EAAE,MAAO,EAG1B,IAAK,EACH,MAAO,EAAE,WAAY,EACrB,cAAe,EAAE,MAAO,EAIxB,KAAG,EACD,MAAO,EAAE,WAAY,EACvB,sCAAiB,EAGf,IAAK,EAAE,MAAY,EAEvB,KAAM,EACJ,cAAe,EAAE,GAAI,EACrB,UAAW,EAAE,EAAG,EAChB,UAAW,EAAE,KAAM,EAEjB,YAAG,EACD,IAAK,EAAE,IAAI,EACb,oDAAiB,EAGf,aAAc,EAAE,OAAQ,EAG9B,cAAe,EACb,MAAO,EAAE,EAAO,EAElB,gBAAiB,EACf,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,sBAAuB,EACrB,MAAO,EAAE,EAAO,EAElB,kBAAmB,EACjB,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,sBAAuB,EACrB,MAAO,EAAE,EAAO,EAElB,qBAAsB,EACpB,MAAO,EAAE,EAAO,EAElB,uBAAwB,EACtB,MAAO,EAAE,EAAO,ECnElB,YAAa,EACX,OAAQ,EAAE,IAAK,EACf,KAAM,EAAE,AAAC,EACT,GAAI,EAAE,AAAC,EACP,IAAK,EC6E+B,IAAK,ED5EzC,IAAK,ECE+B,MAAyB,EDD7D,SAAU,EAAE,MAAkC,EAC9C,SAAU,EAAE,iBAAiC,EAC7C,UAAW,EEAyB,sDAAM,EFC1C,MAAO,EC+E6B,EAAG,ED9EvC,cAAC,EACC,IAAK,ECqE6B,MAAW,EDpE7C,cAAe,EAAE,GAAI,EACvB,6BAAgB,EACd,MAAO,EAAE,GAAI,EACf,iCAAoB,EAClB,MAAO,EAAE,GAAqB,EAC9B,eAAgB,EAAE,MAAkC,EACpD,MAAO,EAAE,IAAK,EACd,SAAU,EAAE,IAAK,EACjB,QAAS,EAAE,EAAG,EACd,KAAM,EAAE,MAAO,EACf,IAAK,ECiD6B,MAAM,EJgC1C,IAAK,EAAE,AAAC,EACR,iFAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,uCAAO,EACL,IAAK,EAAE,GAAI,EGrFX,qCAAG,EACD,IAAK,EClB2B,MAAyB,EDmB3D,0CAAQ,EACN,IAAK,EAAE,GAAI,EACb,4CAAU,EACR,IAAK,EAAE,GAAI,EACb,iDAAiB,EACf,eAAgB,ECQgB,MAAI,EDPpC,IAAK,EC0B2B,GAAM,EDzBxC,wDAAwB,EACtB,eAAgB,ECXgB,MAAO,EDYvC,IAAK,ECzB2B,GAAI,ED0BxC,yCAA8B,EAC5B,MAAO,EAAE,IAAK,EAChB,gCAAmB,EACjB,QAAS,EAAE,EAAG,EACd,MAAO,EAAE,GAAqB,EAC9B,IAAK,ECE6B,GAAwB,EDD1D,MAAO,EAAE,GAAI,EACb,mCAAE,EACA,MAAO,EAAE,IAAK,EACd,KAAM,EAAE,EAAG,EACX,KAAM,EAAE,AAAC,EACT,KAAM,EAAE,KAAM,EACd,MAAO,EAAE,AAAC,EACV,SAAU,EAAE,gBAA6C,EAC3D,mCAAE,EACA,MAAO,EAAE,WAAY,EACrB,KAAM,EAAE,AAAC,EACT,qCAAC,EACC,MAAO,EAAE,WAAY,EACrB,MAAO,EAAE,EAAqB,EAC9B,IAAK,ECjDyB,MAAyB,EDkD7D,sBAAW,EACT,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI,EACZ,IAAK,EAAE,GAAI,EACX,GAAI,EAAE,GAAI,EACV,KAAM,EAAE,GAAI,EACZ,QAAS,ECkByB,IAAK,EDjBvC,iCAAU,EACR,IAAK,EAAE,GAAI,EACb,+BAAQ,EACN,IAAK,EAAE,GAAI,EACb,oDAA+B,EAC7B,SAAU,EAAE,IAAK,EACjB,6DAAQ,EACN,IAAK,EAAE,GAAI,EACb,+DAAU,EACR,IAAK,EAAE,GAAI,EACf,2CAAoB,EAClB,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI,EACZ,UAAW,EAAE,GAAI,EACjB,MAAO,EAAE,IAAuB,EAChC,MAAO,EAAE,IAAK,EACd,SAAU,EAAE,KAAM,EGhDpB,mCAAsB,EHmDxB,YAAa,EACX,IAAK,EAAE,EAAG,EACV,MAAO,EAAE,GAAI,EACb,kBAAO,EACL,MAAO,EAAE,IAAK,EAClB,EAAG,EACD,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI",
"sources": ["../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/bourbon/dist/css3/_font-face.scss","../../../sass/_theme_badge_fa.sass","../../../sass/_theme_badge.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss"],
"names": [],
"file": "badge_only.css"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -1,47 +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");
$("[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() {
$("[data-toggle='wy-nav-shift']").removeClass("shift");
$("[data-toggle='rst-versions']").toggleClass("shift");
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");
});
$("[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',
applyStickNav = function () {
if (navBar.height() <= win.height()) {
navBar.addClass(stickyNavCssClass);
} else {
navBar.removeClass(stickyNavCssClass);
}
},
winScroll = false,
linkScroll = false,
winPosition = 0,
enable = function () {
applyStickNav();
win.on('resize', applyStickNav);
init();
reset();
win.on('hashchange', reset);
// Set scrolling
win.on('scroll', function () {
if (!linkScroll) {
winScroll = true;
}
});
setInterval(function () {
if (winScroll) {
winScroll = false;
var newWinPosition = win.scrollTop(),
navPosition = navBar.scrollTop(),
newNavPosition = navPosition + (newWinPosition - winPosition);
navBar.scrollTop(newNavPosition);
winPosition = newWinPosition;
}
}, 25);
},
init = function () {
navBar = jquery('nav.wy-nav-side:first');
win = jquery(window);
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

@@ -6,3 +6,4 @@ stylesheet = css/theme.css
typekit_id = hiw1hhg
analytics_id =
sticky_navigation = False
logo_only =

View File

@@ -1,33 +0,0 @@
API Reference
=============
Includes
--------
To use the public APIs, include ``nghttp2/nghttp2.h``::
#include <nghttp2/nghttp2.h>
The header files are also available online: :doc:`nghttp2.h` and
:doc:`nghttp2ver.h`.
Remarks
-------
Do not call `nghttp2_session_send()`, `nghttp2_session_mem_send()`,
`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` from the
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.

View File

@@ -2,3 +2,4 @@ asio_http2.h
============
.. literalinclude:: @top_srcdir@/src/includes/nghttp2/asio_http2.h
:language: cpp

View File

@@ -0,0 +1,5 @@
asio_http2_client.h
===================
.. literalinclude:: @top_srcdir@/src/includes/nghttp2/asio_http2_client.h
:language: cpp

View File

@@ -0,0 +1,5 @@
asio_http2_server.h
===================
.. literalinclude:: @top_srcdir@/src/includes/nghttp2/asio_http2_server.h
:language: cpp

View File

@@ -0,0 +1,19 @@
_h2load()
{
local cur prev split=false
COMPREPLY=()
COMP_WORDBREAKS=${COMP_WORDBREAKS//=}
cmd=${COMP_WORDS[0]}
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--threads --connection-window-bits --input-file --help --requests --data --verbose --version --window-bits --clients --no-tls-proto --header --max-concurrent-streams ' -- "$cur" ) )
;;
*)
_filedir
return 0
esac
return 0
}
complete -F _h2load h2load

View File

@@ -0,0 +1,77 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import print_function
import subprocess
import io
import re
import sys
import os.path
class Option:
def __init__(self, long_opt, short_opt):
self.long_opt = long_opt
self.short_opt = short_opt
def get_all_options(cmd):
opt_pattern = re.compile(r' (?:(-.), )?(--[^\s\[=]+)(\[)?')
proc = subprocess.Popen([cmd, "--help"], stdout=subprocess.PIPE)
stdoutdata, _ = proc.communicate()
cur_option = None
opts = {}
for line in io.StringIO(stdoutdata.decode('utf-8')):
match = opt_pattern.match(line)
if not match:
continue
long_opt = match.group(2)
short_opt = match.group(1)
opts[long_opt] = Option(long_opt, short_opt)
return opts
def output_case(out, name, opts):
out.write('''\
_{name}()
{{
local cur prev split=false
COMPREPLY=()
COMP_WORDBREAKS=${{COMP_WORDBREAKS//=}}
cmd=${{COMP_WORDS[0]}}
_get_comp_words_by_ref cur prev
'''.format(name=name))
# Complete option name.
out.write('''\
case $cur in
-*)
COMPREPLY=( $( compgen -W '\
''')
for opt in opts.values():
out.write(opt.long_opt)
out.write(' ')
out.write('''\
' -- "$cur" ) )
;;
''')
# If no option found for completion then complete with files.
out.write('''\
*)
_filedir
return 0
esac
return 0
}}
complete -F _{name} {name}
'''.format(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")
exit(1)
name = os.path.basename(sys.argv[1])
opts = get_all_options(sys.argv[1])
output_case(sys.stdout, name, opts)

View File

@@ -0,0 +1,19 @@
_nghttp()
{
local cur prev split=false
COMPREPLY=()
COMP_WORDBREAKS=${COMP_WORDBREAKS//=}
cmd=${COMP_WORDS[0]}
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --padding --hexdump --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --trailer --weight --help --key --null-out --window-bits --stat --header ' -- "$cur" ) )
;;
*)
_filedir
return 0
esac
return 0
}
complete -F _nghttp nghttp

View File

@@ -0,0 +1,19 @@
_nghttpd()
{
local cur prev split=false
COMPREPLY=()
COMP_WORDBREAKS=${COMP_WORDBREAKS//=}
cmd=${COMP_WORDS[0]}
_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 --dh-param-file --daemon --verify-client --echo-upload --workers --no-tls --color --early-response --max-concurrent-streams ' -- "$cur" ) )
;;
*)
_filedir
return 0
esac
return 0
}
complete -F _nghttpd nghttpd

View File

@@ -0,0 +1,19 @@
_nghttpx()
{
local cur prev split=false
COMPREPLY=()
COMP_WORDBREAKS=${COMP_WORDBREAKS//=}
cmd=${COMP_WORDS[0]}
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--worker-read-rate --frontend-no-tls --frontend-http2-dump-response-header --backend-http1-connections-per-frontend --tls-ticket-key-file --verify-client-cacert --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
return 0
esac
return 0
}
complete -F _nghttpx nghttpx

View File

@@ -64,7 +64,7 @@ master_doc = 'index'
# General information about the project.
project = u'nghttp2'
copyright = u'2012, 2014, Tatsuhiro Tsujikawa'
copyright = u'2012, 2015, Tatsuhiro Tsujikawa'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -242,6 +242,12 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'nghttp2', u'nghttp2 Documentation',
('nghttp.1', 'nghttp', u'HTTP/2 experimental client',
[u'Tatsuhiro Tsujikawa'], 1),
('nghttpd.1', 'nghttpd', u'HTTP/2 experimental server',
[u'Tatsuhiro Tsujikawa'], 1),
('nghttpx.1', 'nghttpx', u'HTTP/2 experimental proxy',
[u'Tatsuhiro Tsujikawa'], 1),
('h2load.1', 'h2load', u'HTTP/2 benchmarking tool',
[u'Tatsuhiro Tsujikawa'], 1)
]

1
doc/contribute.rst.in Normal file
View File

@@ -0,0 +1 @@
.. include:: @top_srcdir@/doc/sources/contribute.rst

View File

@@ -1,75 +1,273 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
.TH H2LOAD "1" "November 2014" "h2load nghttp2/0.6.6" "User Commands"
.\" Man page generated from reStructuredText.
.
.TH "H2LOAD" "1" "June 23, 2015" "1.0.4" "nghttp2"
.SH NAME
h2load \- HTTP/2 benchmarking tool
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.B h2load
[\fI\,OPTIONS\/\fR]... [\fI\,URI\/\fR]...
.sp
\fBh2load\fP [OPTIONS]... [URI]...
.SH DESCRIPTION
.sp
benchmarking tool for HTTP/2 and SPDY server
.INDENT 0.0
.TP
<URI>
Specify URI to access. Multiple URIs can be
specified. URIs are used in this order for each
client. All URIs are used, then first URI is
used and then 2nd URI, and so on. The scheme,
host and port in the subsequent URIs, if present,
are ignored. Those in the first URI are used
solely.
.B <URI>
Specify URI to access. Multiple URIs can be specified.
URIs are used in this order for each client. All URIs
are used, then first URI is used and then 2nd URI, and
so on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the first URI
are used solely.
.UNINDENT
.SH OPTIONS
.HP
\fB\-n\fR, \fB\-\-requests=\fR<N> Number of requests. Default: 1
.INDENT 0.0
.TP
\fB\-c\fR, \fB\-\-clients=\fR<N>
Number of concurrent clients. Default: 1
.B \-n, \-\-requests=<N>
Number of requests.
.sp
Default: \fB1\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-t\fR, \fB\-\-threads=\fR<N>
Number of native threads. Default: 1
.B \-c, \-\-clients=<N>
Number of concurrent clients.
.sp
Default: \fB1\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-i\fR, \fB\-\-input\-file=\fR<FILE>
Path of a file with multiple URIs are seperated
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 are used,
then first URI is used and then 2nd URI, and so
on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the
first URI are used solely.
.B \-t, \-\-threads=<N>
Number of native threads.
.sp
Default: \fB1\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-m\fR, \fB\-\-max\-concurrent\-streams=\fR(auto|<N>)
Max concurrent streams to issue per session. If
"auto" is given, the number of given URIs is
used. Default: auto
.B \-i, \-\-input\-file=<FILE>
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
are used, then first URI is used and then 2nd URI, and
so on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the first URI
are used solely.
.UNINDENT
.INDENT 0.0
.TP
\fB\-w\fR, \fB\-\-window\-bits=\fR<N>
Sets the stream level initial window size to
(2**<N>)\-1. For SPDY, 2**<N> is used instead.
.B \-m, \-\-max\-concurrent\-streams=(auto|<N>)
Max concurrent streams to issue per session. If "auto"
is given, the number of given URIs is used.
.sp
Default: \fBauto\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-W\fR, \fB\-\-connection\-window\-bits=\fR<N>
Sets the connection level initial window size to
(2**<N>)\-1. For SPDY, if <N> is strictly less
than 16, this option is ignored. Otherwise
2**<N> is used for SPDY.
.B \-w, \-\-window\-bits=<N>
Sets the stream level initial window size to (2**<N>)\-1.
For SPDY, 2**<N> is used instead.
.sp
Default: \fB30\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-H\fR, \fB\-\-header=\fR<HEADER>
.B \-W, \-\-connection\-window\-bits=<N>
Sets the connection level initial window size to
(2**<N>)\-1. For SPDY, if <N> is strictly less than 16,
this option is ignored. Otherwise 2**<N> is used for
SPDY.
.sp
Default: \fB30\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-H, \-\-header=<HEADER>
Add/Override a header to the requests.
.UNINDENT
.INDENT 0.0
.TP
\fB\-p\fR, \fB\-\-no\-tls\-proto=\fR<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
Default: h2c\-14
.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
.sp
Default: \fBh2c\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-v\fR, \fB\-\-verbose\fR
.B \-d, \-\-data=<FILE>
Post FILE to server. The request method is changed to
POST.
.UNINDENT
.INDENT 0.0
.TP
.B \-v, \-\-verbose
Output debug information.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-version\fR
.B \-\-version
Display version information and exit.
.UNINDENT
.INDENT 0.0
.TP
\fB\-h\fR, \fB\-\-help\fR
.B \-h, \-\-help
Display this help and exit.
.SH "SEE ALSO"
nghttp(1), nghttpd(1), nghttpx(1)
.UNINDENT
.SH OUTPUT
.INDENT 0.0
.TP
.B requests
.INDENT 7.0
.TP
.B total
The number of requests h2load was instructed to make.
.TP
.B started
The number of requests h2load has started.
.TP
.B done
The number of requests completed.
.TP
.B succeeded
The number of requests completed successfully. Only HTTP status
code 2xx or3xx are considered as success.
.TP
.B failed
The number of requests failed, including HTTP level failures
(non\-successful HTTP status code).
.TP
.B errored
The number of requests failed, except for HTTP level failures.
status code. This is the subset of the number reported in
\fBfailed\fP and most likely the network level failures or stream
was reset by RST_STREAM.
.UNINDENT
.TP
.B status codes
The number of status code h2load received.
.TP
.B traffic
.INDENT 7.0
.TP
.B total
The number of bytes received from the server "on the wire". If
requests were made via TLS, this value is the number of decrpyted
bytes.
.TP
.B headers
The number of response header bytes from the server without
decompression. For HTTP/2, this is the sum of the payload of
HEADERS frame. For SPDY, this is the sum of the payload of
SYN_REPLY frame.
.TP
.B data
The number of response body bytes received from the server.
.UNINDENT
.TP
.B time for request
.INDENT 7.0
.TP
.B min
The minimum time taken for request and response.
.TP
.B max
The maximum time taken for request and response.
.TP
.B mean
The mean time taken for request and response.
.TP
.B sd
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
h2load sets large flow control window by default, and effectively
disables flow control to avoid under utilization of server
performance. To set smaller flow control window, use \fI\%\-w\fP and
\fI\%\-W\fP options. For example, use \fB\-w16 \-W16\fP to set default
window size described in HTTP/2 and SPDY protocol specification.
.SH SEE ALSO
.sp
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fInghttpx(1)\fP
.SH AUTHOR
Tatsuhiro Tsujikawa
.SH COPYRIGHT
2012, 2015, Tatsuhiro Tsujikawa
.\" Generated by docutils manpage writer.
.

View File

@@ -1,113 +1,204 @@
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
.. program:: h2load
h2load(1)
=========
NAME
----
h2load - HTTP/2 benchmarking tool
SYNOPSIS
--------
**h2load** [OPTIONS]... [URI]...
DESCRIPTION
-----------
benchmarking tool for HTTP/2 and SPDY server
.. option:: URI
.. describe:: <URI>
Specify URI to access. Multiple URIs can be
specified. URIs are used in this order for each
client. All URIs are used, then first URI is
used and then 2nd URI, and so on. The scheme,
host and port in the subsequent URIs, if present,
are ignored. Those in the first URI are used
solely.
Specify URI to access. Multiple URIs can be specified.
URIs are used in this order for each client. All URIs
are used, then first URI is used and then 2nd URI, and
so on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the first URI
are used solely.
OPTIONS
-------
.. option:: -n, --requests=<N>
Number of requests. Default: 1
Number of requests.
Default: ``1``
.. option:: -c, --clients=<N>
Number of concurrent clients. Default: 1
Number of concurrent clients.
Default: ``1``
.. option:: -t, --threads=<N>
Number of native threads. Default: 1
Number of native threads.
Default: ``1``
.. option:: -i, --input-file=<FILE>
Path of a file with multiple URIs are seperated
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 are used,
then first URI is used and then 2nd URI, and so
on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the
first URI are used solely.
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
are used, then first URI is used and then 2nd URI, and
so on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the first URI
are used solely.
.. option:: -m, --max-concurrent-streams=(auto|<N>)
Max concurrent streams to issue per session. If
"auto" is given, the number of given URIs is
used. Default: auto
Max concurrent streams to issue per session. If "auto"
is given, the number of given URIs is used.
Default: ``auto``
.. option:: -w, --window-bits=<N>
Sets the stream level initial window size to
(2\*\*<N>)-1. For SPDY, 2\*\*<N> is used instead.
Sets the stream level initial window size to (2\*\*<N>)-1.
For SPDY, 2**<N> is used instead.
Default: ``30``
.. option:: -W, --connection-window-bits=<N>
Sets the connection level initial window size to
(2\*\*<N>)-1. For SPDY, if <N> is strictly less
than 16, this option is ignored. Otherwise
2\*\*<N> is used for SPDY.
Sets the connection level initial window size to
(2**<N>)-1. For SPDY, if <N> is strictly less than 16,
this option is ignored. Otherwise 2\*\*<N> is used for
SPDY.
Default: ``30``
.. option:: -H, --header=<HEADER>
Add/Override a header to the requests.
.. option:: -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
Default: h2c-14
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
Default: ``h2c``
.. option:: -d, --data=<FILE>
Post FILE to server. The request method is changed to
POST.
.. option:: -v, --verbose
Output debug information.
.. option:: --version
Display version information and exit.
.. option:: -h, --help
Display this help and exit.
OUTPUT
------
requests
total
The number of requests h2load was instructed to make.
started
The number of requests h2load has started.
done
The number of requests completed.
succeeded
The number of requests completed successfully. Only HTTP status
code 2xx or3xx are considered as success.
failed
The number of requests failed, including HTTP level failures
(non-successful HTTP status code).
errored
The number of requests failed, except for HTTP level failures.
status code. This is the subset of the number reported in
``failed`` and most likely the network level failures or stream
was reset by RST_STREAM.
status codes
The number of status code h2load received.
traffic
total
The number of bytes received from the server "on the wire". If
requests were made via TLS, this value is the number of decrpyted
bytes.
headers
The number of response header bytes from the server without
decompression. For HTTP/2, this is the sum of the payload of
HEADERS frame. For SPDY, this is the sum of the payload of
SYN_REPLY frame.
data
The number of response body bytes received from the server.
time for request
min
The minimum time taken for request and response.
max
The maximum time taken for request and response.
mean
The mean time taken for request and response.
sd
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
------------
h2load sets large flow control window by default, and effectively
disables flow control to avoid under utilization of server
performance. To set smaller flow control window, use :option:`-w` and
:option:`-W` options. For example, use ``-w16 -W16`` to set default
window size described in HTTP/2 and SPDY protocol specification.
SEE ALSO
--------
nghttp(1), nghttpd(1), nghttpx(1)
:manpage:`nghttp(1)`, :manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`

View File

@@ -1,3 +0,0 @@
[SEE ALSO]
nghttp(1), nghttpd(1), nghttpx(1)

93
doc/h2load.h2r Normal file
View File

@@ -0,0 +1,93 @@
OUTPUT
------
requests
total
The number of requests h2load was instructed to make.
started
The number of requests h2load has started.
done
The number of requests completed.
succeeded
The number of requests completed successfully. Only HTTP status
code 2xx or3xx are considered as success.
failed
The number of requests failed, including HTTP level failures
(non-successful HTTP status code).
errored
The number of requests failed, except for HTTP level failures.
status code. This is the subset of the number reported in
``failed`` and most likely the network level failures or stream
was reset by RST_STREAM.
status codes
The number of status code h2load received.
traffic
total
The number of bytes received from the server "on the wire". If
requests were made via TLS, this value is the number of decrpyted
bytes.
headers
The number of response header bytes from the server without
decompression. For HTTP/2, this is the sum of the payload of
HEADERS frame. For SPDY, this is the sum of the payload of
SYN_REPLY frame.
data
The number of response body bytes received from the server.
time for request
min
The minimum time taken for request and response.
max
The maximum time taken for request and response.
mean
The mean time taken for request and response.
sd
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
------------
h2load sets large flow control window by default, and effectively
disables flow control to avoid under utilization of server
performance. To set smaller flow control window, use :option:`-w` and
:option:`-W` options. For example, use ``-w16 -W16`` to set default
window size described in HTTP/2 and SPDY protocol specification.
SEE ALSO
--------
:manpage:`nghttp(1)`, :manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2012 Tatsuhiro Tsujikawa
@@ -23,20 +24,24 @@
# 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
import re, sys, argparse, os.path
class FunctionDoc:
def __init__(self, name, content, domain):
self.name = name
self.content = content
self.domain = domain
if self.domain == 'function':
self.funcname = re.search(r'(nghttp2_[^ )]+)\(', self.name).group(1)
def write(self, out):
print('''.. {}:: {}'''.format(self.domain, self.name))
print('')
out.write('.. {}:: {}\n'.format(self.domain, self.name))
out.write('\n')
for line in self.content:
print(' {}'.format(line))
out.write(' {}\n'.format(line))
class StructDoc:
def __init__(self, name, content, members, member_domain):
@@ -47,17 +52,17 @@ class StructDoc:
def write(self, out):
if self.name:
print('''.. type:: {}'''.format(self.name))
print('')
out.write('.. type:: {}\n'.format(self.name))
out.write('\n')
for line in self.content:
print(' {}'.format(line))
print('')
out.write(' {}\n'.format(line))
out.write('\n')
for name, content in self.members:
print(''' .. {}:: {}'''.format(self.member_domain, name))
print('')
out.write(' .. {}:: {}\n'.format(self.member_domain, name))
out.write('\n')
for line in content:
print(''' {}'''.format(line))
print('')
out.write(' {}\n'.format(line))
out.write('\n')
class MacroDoc:
def __init__(self, name, content):
@@ -65,10 +70,10 @@ class MacroDoc:
self.content = content
def write(self, out):
print('''.. macro:: {}'''.format(self.name))
print('')
out.write('''.. macro:: {}\n'''.format(self.name))
out.write('\n')
for line in self.content:
print(' {}'.format(line))
out.write(' {}\n'.format(line))
def make_api_ref(infiles):
macros = []
@@ -93,19 +98,65 @@ def make_api_ref(infiles):
enums.append(process_enum(infile))
elif doctype == '@macro':
macros.append(process_macro(infile))
return macros, enums, types, functions
alldocs = [('Macros', macros),
('Enums', enums),
('Types (structs, unions and typedefs)', types),
('Functions', functions)]
for title, docs in alldocs:
if not docs:
continue
print(title)
print('-'*len(title))
for doc in docs:
doc.write(sys.stdout)
print('')
print('')
def output(
indexfile, macrosfile, enumsfile, typesfile, funcsdir,
macros, enums, types, functions):
indexfile.write('''
API Reference
=============
.. toctree::
:maxdepth: 1
macros
enums
types
''')
for doc in functions:
indexfile.write(' {}\n'.format(doc.funcname))
macrosfile.write('''
Macros
======
''')
for doc in macros:
doc.write(macrosfile)
enumsfile.write('''
Enums
=====
''')
for doc in enums:
doc.write(enumsfile)
typesfile.write('''
Types (structs, unions and typedefs)
====================================
''')
for doc in types:
doc.write(typesfile)
for doc in functions:
with open(os.path.join(funcsdir, doc.funcname + '.rst'), 'w') as f:
f.write('''
{funcname}
{secul}
Synopsis
--------
*#include <nghttp2/nghttp2.h>*
'''.format(funcname=doc.funcname, secul='='*len(doc.funcname)))
doc.write(f)
def process_macro(infile):
content = read_content(infile)
@@ -174,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):
@@ -199,12 +251,30 @@ def transform_content(content):
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Generate API reference")
parser.add_argument('--header', type=argparse.FileType('r'),
help='header inserted at the top of the page')
parser.add_argument('index', type=argparse.FileType('w'),
help='index output file')
parser.add_argument('macros', type=argparse.FileType('w'),
help='macros section output file. The filename should be macros.rst')
parser.add_argument('enums', type=argparse.FileType('w'),
help='enums section output file. The filename should be enums.rst')
parser.add_argument('types', type=argparse.FileType('w'),
help='types section output file. The filename should be types.rst')
parser.add_argument('funcsdir',
help='functions doc output dir')
parser.add_argument('files', nargs='+', type=argparse.FileType('r'),
help='source file')
args = parser.parse_args()
if args.header:
print(args.header.read())
macros = []
enums = []
types = []
funcs = []
for infile in args.files:
make_api_ref(args.files)
m, e, t, f = make_api_ref(args.files)
macros.extend(m)
enums.extend(e)
types.extend(t)
funcs.extend(f)
funcs.sort(key=lambda x: x.funcname)
output(
args.index, args.macros, args.enums, args.types, args.funcsdir,
macros, enums, types, funcs)

View File

@@ -1,115 +1,289 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
.TH NGHTTP "1" "November 2014" "nghttp nghttp2/0.6.6" "User Commands"
.\" Man page generated from reStructuredText.
.
.TH "NGHTTP" "1" "June 23, 2015" "1.0.4" "nghttp2"
.SH NAME
nghttp \- HTTP/2 experimental client
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.B nghttp
[\fI\,OPTIONS\/\fR]... \fI\,<URI>\/\fR...
.sp
\fBnghttp\fP [OPTIONS]... <URI>...
.SH DESCRIPTION
.sp
HTTP/2 experimental client
.INDENT 0.0
.TP
<URI>
.B <URI>
Specify URI to access.
.UNINDENT
.SH OPTIONS
.INDENT 0.0
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Print debug information such as reception and
transmission of frames and name/value pairs.
Specifying this option multiple times increases
verbosity.
.B \-v, \-\-verbose
Print debug information such as reception and
transmission of frames and name/value pairs. Specifying
this option multiple times increases verbosity.
.UNINDENT
.INDENT 0.0
.TP
\fB\-n\fR, \fB\-\-null\-out\fR
.B \-n, \-\-null\-out
Discard downloaded data.
.UNINDENT
.INDENT 0.0
.TP
\fB\-O\fR, \fB\-\-remote\-name\fR
Save download data in the current directory. The
filename is dereived from URI. If URI ends with
\&'/', 'index.html' is used as a filename. Not
implemented yet.
.B \-O, \-\-remote\-name
Save download data in the current directory. The
filename is dereived from URI. If URI ends with \(aq\fI/\fP\(aq,
\(aqindex.html\(aq is used as a filename. Not implemented
yet.
.UNINDENT
.INDENT 0.0
.TP
\fB\-t\fR, \fB\-\-timeout=\fR<N>
Timeout each request after <N> seconds.
.B \-t, \-\-timeout=<DURATION>
Timeout each request after <DURATION>. Set 0 to disable
timeout.
.UNINDENT
.INDENT 0.0
.TP
\fB\-w\fR, \fB\-\-window\-bits=\fR<N>
Sets the stream level initial window size to
.B \-w, \-\-window\-bits=<N>
Sets the stream level initial window size to 2**<N>\-1.
.UNINDENT
.INDENT 0.0
.TP
.B \-W, \-\-connection\-window\-bits=<N>
Sets the connection level initial window size to
2**<N>\-1.
.UNINDENT
.INDENT 0.0
.TP
\fB\-W\fR, \fB\-\-connection\-window\-bits=\fR<N>
Sets the connection level initial window size to
2**<N>\-1.
.B \-a, \-\-get\-assets
Download assets such as stylesheets, images and script
files linked from the downloaded resource. Only links
whose origins are the same with the linking resource
will be downloaded. nghttp prioritizes resources using
HTTP/2 dependency based priority. The priority order,
from highest to lowest, is html itself, css, javascript
and images.
.UNINDENT
.INDENT 0.0
.TP
\fB\-a\fR, \fB\-\-get\-assets\fR
Download assets such as stylesheets, images and
script files linked from the downloaded resource.
Only links whose origins are the same with the
linking resource will be downloaded. nghttp
prioritizes resources using HTTP/2 dependency
based priority. The priority order, from highest
to lowest, is html itself, css, javascript and
images.
.TP
\fB\-s\fR, \fB\-\-stat\fR
.B \-s, \-\-stat
Print statistics.
.UNINDENT
.INDENT 0.0
.TP
\fB\-H\fR, \fB\-\-header=\fR<HEADER>
Add a header to the requests. Example:
\fB\-H\fR':method: PUT'
.B \-H, \-\-header=<HEADER>
Add a header to the requests. Example: \fI\%\-H\fP\(aq:method: PUT\(aq
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-cert=\fR<CERT>
Use the specified client certificate file. The
file must be in PEM format.
.B \-\-trailer=<HEADER>
Add a trailer header to the requests. <HEADER> must not
include pseudo header field (header field name starting
with \(aq:\(aq). To send trailer, one must use \fI\%\-d\fP option to
send request body. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-key=\fR<KEY>
Use the client private key file. The file must
be in PEM format.
.B \-\-cert=<CERT>
Use the specified client certificate file. The file
must be in PEM format.
.UNINDENT
.INDENT 0.0
.TP
\fB\-d\fR, \fB\-\-data=\fR<FILE>
Post FILE to server. If '\-' is given, data will
be read from stdin.
.B \-\-key=<KEY>
Use the client private key file. The file must be in
PEM format.
.UNINDENT
.INDENT 0.0
.TP
\fB\-m\fR, \fB\-\-multiply=\fR<N> Request each URI <N> times.
By default, same URI
is not requested twice. This option disables it
too.
.B \-d, \-\-data=<FILE>
Post FILE to server. If \(aq\-\(aq is given, data will be read
from stdin.
.UNINDENT
.INDENT 0.0
.TP
\fB\-u\fR, \fB\-\-upgrade\fR
Perform HTTP Upgrade for HTTP/2. This option is
ignored if the request URI has https scheme. If
\fB\-d\fR is used, the HTTP upgrade request is performed
with OPTIONS method.
.B \-m, \-\-multiply=<N>
Request each URI <N> times. By default, same URI is not
requested twice. This option disables it too.
.UNINDENT
.INDENT 0.0
.TP
\fB\-p\fR, \fB\-\-weight=\fR<WEIGHT>
Sets priority group weight. The valid value
range is [1, 256], inclusive.
Default: 16
.B \-u, \-\-upgrade
Perform HTTP Upgrade for HTTP/2. This option is ignored
if the request URI has https scheme. If \fI\%\-d\fP is used, the
HTTP upgrade request is performed with OPTIONS method.
.UNINDENT
.INDENT 0.0
.TP
\fB\-M\fR, \fB\-\-peer\-max\-concurrent\-streams=\fR<N>
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value
of remote endpoint as if it is received in
SETTINGS frame. The default is large enough as
it is seen as unlimited.
.B \-p, \-\-weight=<WEIGHT>
Sets priority group weight. The valid value range is
[1, 256], inclusive.
.sp
Default: \fB16\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-c\fR, \fB\-\-header\-table\-size=\fR<N>
.B \-M, \-\-peer\-max\-concurrent\-streams=<N>
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value of
remote endpoint as if it is received in SETTINGS frame.
The default is large enough as it is seen as unlimited.
.UNINDENT
.INDENT 0.0
.TP
.B \-c, \-\-header\-table\-size=<SIZE>
Specify decoder header table size.
.UNINDENT
.INDENT 0.0
.TP
\fB\-b\fR, \fB\-\-padding=\fR<N>
Add at most <N> bytes to a frame payload as
padding. Specify 0 to disable padding.
.B \-b, \-\-padding=<N>
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-color\fR
.B \-r, \-\-har=<FILE>
Output HTTP transactions <FILE> in HAR format. If \(aq\-\(aq
is given, data is written to stdout.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-color
Force colored log output.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-continuation\fR
.B \-\-continuation
Send large header to test CONTINUATION.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-no\-content\-length\fR
Don't send content\-length header field.
.B \-\-no\-content\-length
Don\(aqt send content\-length header field.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-version\fR
.B \-\-no\-dep
Don\(aqt send dependency based priority hint to server.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-hexdump
Display the incoming traffic in hexadecimal (Canonical
hex+ASCII display). If SSL/TLS is used, decrypted data
are used.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-no\-push
Disable server push.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-version
Display version information and exit.
.UNINDENT
.INDENT 0.0
.TP
\fB\-h\fR, \fB\-\-help\fR
.B \-h, \-\-help
Display this help and exit.
.SH "SEE ALSO"
nghttpd(1), nghttpx(1), h2load(1)
.UNINDENT
.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
\fI\%\-\-no\-dep\fP is used. nghttp mimics the way Firefox employs to
manages dependency using idle streams. We follows the behaviour of
Firefox Nightly as of April, 2015, and nghttp\(aqs behaviour is very
static and could be different from Firefox in detail. But reproducing
the same behaviour of Firefox is not our goal. The goal is provide
the easy way to test out the dependency priority in server
implementation.
.sp
When connection is established, nghttp sends 5 PRIORITY frames to idle
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
tree:
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
+\-\-\-\-\-+
|id=0 |
+\-\-\-\-\-+
^ ^ ^
w=201 / | \e w=1
/ | \e
/ w=101| \e
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
|id=3 | |id=5 | |id=7 |
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
^ ^
w=1 | w=1 |
| |
+\-\-\-\-\-+ +\-\-\-\-\-+
|id=11| |id=9 |
+\-\-\-\-\-+ +\-\-\-\-\-+
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
In the above figure, \fBid\fP means stream ID, and \fBw\fP means weight.
The stream 0 is non\-existence stream, and forms the root of the tree.
The stream 7 and 9 are not used for now.
.sp
The URIs given in the command\-line depend on stream 11 with the weight
given in \fI\%\-p\fP option, which defaults to 16.
.sp
If \fI\%\-a\fP option is used, nghttp parses the resource pointed by
URI given in command\-line as html, and extracts resource links from
it. When requesting those resources, nghttp uses dependency according
to its resource type.
.sp
For CSS, and Javascript files inside "head" element, they depend on
stream 3 with the weight 2. The Javascript files outside "head"
element depend on stream 5 with the weight 2. The mages depend on
stream 11 with the weight 12. The other resources (e.g., icon) depend
on stream 11 with the weight 2.
.SH SEE ALSO
.sp
\fInghttpd(1)\fP, \fInghttpx(1)\fP, \fIh2load(1)\fP
.SH AUTHOR
Tatsuhiro Tsujikawa
.SH COPYRIGHT
2012, 2015, Tatsuhiro Tsujikawa
.\" Generated by docutils manpage writer.
.

View File

@@ -1,23 +1,22 @@
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
.. program:: nghttp
nghttp(1)
=========
NAME
----
nghttp - HTTP/2 experimental client
SYNOPSIS
--------
**nghttp** [OPTIONS]... <URI>...
DESCRIPTION
-----------
HTTP/2 experimental client
.. option:: URI
.. describe:: <URI>
Specify URI to access.
@@ -26,150 +25,209 @@ OPTIONS
.. option:: -v, --verbose
Print debug information such as reception and
transmission of frames and name/value pairs.
Specifying this option multiple times increases
verbosity.
Print debug information such as reception and
transmission of frames and name/value pairs. Specifying
this option multiple times increases verbosity.
.. option:: -n, --null-out
Discard downloaded data.
.. option:: -O, --remote-name
Save download data in the current directory. The
filename is dereived from URI. If URI ends with
'/', 'index.html' is used as a filename. Not
implemented yet.
Save download data in the current directory. The
filename is dereived from URI. If URI ends with '*/*',
'index.html' is used as a filename. Not implemented
yet.
.. option:: -t, --timeout=<N>
.. option:: -t, --timeout=<DURATION>
Timeout each request after <N> seconds.
Timeout each request after <DURATION>. Set 0 to disable
timeout.
.. option:: -w, --window-bits=<N>
Sets the stream level initial window size to
2\*\*<N>-1.
Sets the stream level initial window size to 2\*\*<N>-1.
.. option:: -W, --connection-window-bits=<N>
Sets the connection level initial window size to
Sets the connection level initial window size to
2\*\*<N>-1.
.. option:: -a, --get-assets
Download assets such as stylesheets, images and
script files linked from the downloaded resource.
Only links whose origins are the same with the
linking resource will be downloaded. nghttp
prioritizes resources using HTTP/2 dependency
based priority. The priority order, from highest
to lowest, is html itself, css, javascript and
images.
Download assets such as stylesheets, images and script
files linked from the downloaded resource. Only links
whose origins are the same with the linking resource
will be downloaded. nghttp prioritizes resources using
HTTP/2 dependency based priority. The priority order,
from highest to lowest, is html itself, css, javascript
and images.
.. option:: -s, --stat
Print statistics.
.. option:: -H, --header=<HEADER>
Add a header to the requests. Example:
-H':method: PUT'
Add a header to the requests. Example: :option:`-H`\':method: PUT'
.. option:: --trailer=<HEADER>
Add a trailer header to the requests. <HEADER> must not
include pseudo header field (header field name starting
with ':'). To send trailer, one must use :option:`-d` option to
send request body. Example: :option:`--trailer` 'foo: bar'.
.. option:: --cert=<CERT>
Use the specified client certificate file. The
file must be in PEM format.
Use the specified client certificate file. The file
must be in PEM format.
.. option:: --key=<KEY>
Use the client private key file. The file must
be in PEM format.
Use the client private key file. The file must be in
PEM format.
.. option:: -d, --data=<FILE>
Post FILE to server. If '-' is given, data will
be read from stdin.
Post FILE to server. If '-' is given, data will be read
from stdin.
.. option:: -m, --multiply=<N>
Request each URI <N> times.
By default, same URI
is not requested twice. This option disables it
too.
Request each URI <N> times. By default, same URI is not
requested twice. This option disables it too.
.. option:: -u, --upgrade
Perform HTTP Upgrade for HTTP/2. This option is
ignored if the request URI has https scheme. If
:option:`-d` is used, the HTTP upgrade request is performed
with OPTIONS method.
Perform HTTP Upgrade for HTTP/2. This option is ignored
if the request URI has https scheme. If :option:`-d` is used, the
HTTP upgrade request is performed with OPTIONS method.
.. option:: -p, --weight=<WEIGHT>
Sets priority group weight. The valid value
range is [1, 256], inclusive.
Default: 16
Sets priority group weight. The valid value range is
[1, 256], inclusive.
Default: ``16``
.. option:: -M, --peer-max-concurrent-streams=<N>
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value
of remote endpoint as if it is received in
SETTINGS frame. The default is large enough as
it is seen as unlimited.
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value of
remote endpoint as if it is received in SETTINGS frame.
The default is large enough as it is seen as unlimited.
.. option:: -c, --header-table-size=<N>
.. option:: -c, --header-table-size=<SIZE>
Specify decoder header table size.
.. option:: -b, --padding=<N>
Add at most <N> bytes to a frame payload as
padding. Specify 0 to disable padding.
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
.. option:: -r, --har=<FILE>
Output HTTP transactions <FILE> in HAR format. If '-'
is given, data is written to stdout.
.. option:: --color
Force colored log output.
.. option:: --continuation
Send large header to test CONTINUATION.
.. option:: --no-content-length
Don't send content-length header field.
.. option:: --no-dep
Don't send dependency based priority hint to server.
.. option:: --hexdump
Display the incoming traffic in hexadecimal (Canonical
hex+ASCII display). If SSL/TLS is used, decrypted data
are used.
.. option:: --no-push
Disable server push.
.. option:: --version
Display version information and exit.
.. option:: -h, --help
Display this help and exit.
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
-------------------------
nghttp sends priority hints to server by default unless
:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
manages dependency using idle streams. We follows the behaviour of
Firefox Nightly as of April, 2015, and nghttp's behaviour is very
static and could be different from Firefox in detail. But reproducing
the same behaviour of Firefox is not our goal. The goal is provide
the easy way to test out the dependency priority in server
implementation.
When connection is established, nghttp sends 5 PRIORITY frames to idle
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
tree::
+-----+
|id=0 |
+-----+
^ ^ ^
w=201 / | \ w=1
/ | \
/ w=101| \
+-----+ +-----+ +-----+
|id=3 | |id=5 | |id=7 |
+-----+ +-----+ +-----+
^ ^
w=1 | w=1 |
| |
+-----+ +-----+
|id=11| |id=9 |
+-----+ +-----+
In the above figure, ``id`` means stream ID, and ``w`` means weight.
The stream 0 is non-existence stream, and forms the root of the tree.
The stream 7 and 9 are not used for now.
The URIs given in the command-line depend on stream 11 with the weight
given in :option:`-p` option, which defaults to 16.
If :option:`-a` option is used, nghttp parses the resource pointed by
URI given in command-line as html, and extracts resource links from
it. When requesting those resources, nghttp uses dependency according
to its resource type.
For CSS, and Javascript files inside "head" element, they depend on
stream 3 with the weight 2. The Javascript files outside "head"
element depend on stream 5 with the weight 2. The mages depend on
stream 11 with the weight 12. The other resources (e.g., icon) depend
on stream 11 with the weight 2.
SEE ALSO
--------
nghttpd(1), nghttpx(1), h2load(1)
:manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`

View File

@@ -1,3 +0,0 @@
[SEE ALSO]
nghttpd(1), nghttpx(1), h2load(1)

55
doc/nghttp.h2r Normal file
View File

@@ -0,0 +1,55 @@
DEPENDENCY BASED PRIORITY
-------------------------
nghttp sends priority hints to server by default unless
:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
manages dependency using idle streams. We follows the behaviour of
Firefox Nightly as of April, 2015, and nghttp's behaviour is very
static and could be different from Firefox in detail. But reproducing
the same behaviour of Firefox is not our goal. The goal is provide
the easy way to test out the dependency priority in server
implementation.
When connection is established, nghttp sends 5 PRIORITY frames to idle
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
tree::
+-----+
|id=0 |
+-----+
^ ^ ^
w=201 / | \ w=1
/ | \
/ w=101| \
+-----+ +-----+ +-----+
|id=3 | |id=5 | |id=7 |
+-----+ +-----+ +-----+
^ ^
w=1 | w=1 |
| |
+-----+ +-----+
|id=11| |id=9 |
+-----+ +-----+
In the above figure, ``id`` means stream ID, and ``w`` means weight.
The stream 0 is non-existence stream, and forms the root of the tree.
The stream 7 and 9 are not used for now.
The URIs given in the command-line depend on stream 11 with the weight
given in :option:`-p` option, which defaults to 16.
If :option:`-a` option is used, nghttp parses the resource pointed by
URI given in command-line as html, and extracts resource links from
it. When requesting those resources, nghttp uses dependency according
to its resource type.
For CSS, and Javascript files inside "head" element, they depend on
stream 3 with the weight 2. The Javascript files outside "head"
element depend on stream 5 with the weight 2. The mages depend on
stream 11 with the weight 12. The other resources (e.g., icon) depend
on stream 11 with the weight 2.
SEE ALSO
--------
:manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`

View File

@@ -1,93 +1,194 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
.TH NGHTTPD "1" "November 2014" "nghttpd nghttp2/0.6.6" "User Commands"
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPD" "1" "June 23, 2015" "1.0.4" "nghttp2"
.SH NAME
nghttpd \- HTTP/2 experimental server
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.B nghttpd
[\fI\,OPTION\/\fR]... \fI\,<PORT> <PRIVATE_KEY> <CERT>\/\fR
.br
.B nghttpd
\fI\,--no-tls \/\fR[\fI\,OPTION\/\fR]... \fI\,<PORT>\/\fR
.sp
\fBnghttpd\fP [OPTION]... <PORT> [<PRIVATE_KEY> <CERT>]
.SH DESCRIPTION
.sp
HTTP/2 experimental server
.INDENT 0.0
.TP
<PORT>
.B <PORT>
Specify listening port number.
.UNINDENT
.INDENT 0.0
.TP
<PRIVATE_KEY>
Set path to server's private key. Required
unless \fB\-\-no\-tls\fR is specified.
.B <PRIVATE_KEY>
Set path to server\(aqs private key. Required unless
\fI\%\-\-no\-tls\fP is specified.
.UNINDENT
.INDENT 0.0
.TP
<CERT>
Set path to server's certificate. Required
unless \fB\-\-no\-tls\fR is specified.
.B <CERT>
Set path to server\(aqs certificate. Required unless
\fI\%\-\-no\-tls\fP is specified.
.UNINDENT
.SH OPTIONS
.INDENT 0.0
.TP
\fB\-D\fR, \fB\-\-daemon\fR
Run in a background. If \fB\-D\fR is used, the current
working directory is changed to '/'. Therefore
if this option is used, \fB\-d\fR option must be
specified.
.B \-a, \-\-address=<ADDR>
The address to bind to. If not specified the default IP
address determined by getaddrinfo is used.
.UNINDENT
.INDENT 0.0
.TP
\fB\-V\fR, \fB\-\-verify\-client\fR
The server sends a client certificate request.
If the client did not return a certificate, the
handshake is terminated. Currently, this option
just requests a client certificate and does not
verify it.
.B \-D, \-\-daemon
Run in a background. If \fI\%\-D\fP is used, the current working
directory is changed to \(aq\fI/\fP\(aq. Therefore if this option
is used, \fI\%\-d\fP option must be specified.
.UNINDENT
.INDENT 0.0
.TP
\fB\-d\fR, \fB\-\-htdocs=\fR<PATH>
Specify document root. If this option is not
specified, the document root is the current
working directory.
.B \-V, \-\-verify\-client
The server sends a client certificate request. If the
client did not return a certificate, the handshake is
terminated. Currently, this option just requests a
client certificate and does not verify it.
.UNINDENT
.INDENT 0.0
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Print debug information such as reception/
transmission of frames and name/value pairs.
.B \-d, \-\-htdocs=<PATH>
Specify document root. If this option is not specified,
the document root is the current working directory.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-no\-tls\fR
.B \-v, \-\-verbose
Print debug information such as reception/ transmission
of frames and name/value pairs.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-no\-tls
Disable SSL/TLS.
.UNINDENT
.INDENT 0.0
.TP
\fB\-c\fR, \fB\-\-header\-table\-size=\fR<N>
.B \-c, \-\-header\-table\-size=<SIZE>
Specify decoder header table size.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-color\fR
.B \-\-color
Force colored log output.
.UNINDENT
.INDENT 0.0
.TP
\fB\-p\fR, \fB\-\-push=\fR<PATH>=<PUSH_PATH,...>
Push resources <PUSH_PATH>s when <PATH> is
requested. This option can be used repeatedly to
specify multiple push configurations. <PATH> and
<PUSH_PATH>s are relative to document root. See
\fB\-\-htdocs\fR option. Example: \fB\-p\fR/=/foo.png
\fB\-p\fR/doc=/bar.css
.B \-p, \-\-push=<PATH>=<PUSH_PATH,...>
Push resources <PUSH_PATH>s when <PATH> is requested.
This option can be used repeatedly to specify multiple
push configurations. <PATH> and <PUSH_PATH>s are
relative to document root. See \fI\%\-\-htdocs\fP option.
Example: \fI\%\-p\fP/=/foo.png \fI\%\-p\fP/doc=/bar.css
.UNINDENT
.INDENT 0.0
.TP
\fB\-b\fR, \fB\-\-padding=\fR<N>
Add at most <N> bytes to a frame payload as
padding. Specify 0 to disable padding.
.B \-b, \-\-padding=<N>
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
.UNINDENT
.INDENT 0.0
.TP
\fB\-n\fR, \fB\-\-workers=\fR<CORE>
.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.
Default: 1
.sp
Default: \fB1\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-e\fR, \fB\-\-error\-gzip\fR
.B \-e, \-\-error\-gzip
Make error response gzipped.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-dh\-param\-file=\fR<PATH>
Path to file that contains DH parameters in PEM
format. Without this option, DHE cipher suites
are not available.
.B \-\-dh\-param\-file=<PATH>
Path to file that contains DH parameters in PEM format.
Without this option, DHE cipher suites are not
available.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-early\-response\fR
Start sending response when request HEADERS is
received, rather than complete request is
received.
.B \-\-early\-response
Start sending response when request HEADERS is received,
rather than complete request is received.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-version\fR
.B \-\-trailer=<HEADER>
Add a trailer header to a response. <HEADER> must not
include pseudo header field (header field name starting
with \(aq:\(aq). The trailer is sent only if a response has
body part. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-hexdump
Display the incoming traffic in hexadecimal (Canonical
hex+ASCII display). If SSL/TLS is used, decrypted data
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
.INDENT 0.0
.TP
\fB\-h\fR, \fB\-\-help\fR
.B \-h, \-\-help
Display this help and exit.
.SH "SEE ALSO"
nghttp(1), nghttpx(1), h2load(1)
.UNINDENT
.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).
.SH SEE ALSO
.sp
\fInghttp(1)\fP, \fInghttpx(1)\fP, \fIh2load(1)\fP
.SH AUTHOR
Tatsuhiro Tsujikawa
.SH COPYRIGHT
2012, 2015, Tatsuhiro Tsujikawa
.\" Generated by docutils manpage writer.
.

View File

@@ -1,138 +1,151 @@
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
.. program:: nghttpd
nghttpd(1)
==========
NAME
----
nghttpd - HTTP/2 experimental server
SYNOPSIS
--------
**nghttpd** [OPTION]... <PORT> <PRIVATE_KEY> <CERT>
**nghttpd** --no-tls [OPTION]... <PORT>
**nghttpd** [OPTION]... <PORT> [<PRIVATE_KEY> <CERT>]
DESCRIPTION
-----------
HTTP/2 experimental server
.. option:: PORT
.. describe:: <PORT>
Specify listening port number.
.. option:: PRIVATE_KEY
.. describe:: <PRIVATE_KEY>
Set path to server's private key. Required
unless :option:`--no-tls` is specified.
Set path to server's private key. Required unless
:option:`--no-tls` is specified.
.. option:: CERT
.. describe:: <CERT>
Set path to server's certificate. Required
unless :option:`--no-tls` is specified.
Set path to server's certificate. Required unless
:option:`--no-tls` is specified.
OPTIONS
-------
.. option:: -a, --address=<ADDR>
The address to bind to. If not specified the default IP
address determined by getaddrinfo is used.
.. option:: -D, --daemon
Run in a background. If :option:`-D` is used, the current
working directory is changed to '/'. Therefore
if this option is used, :option:`-d` option must be
specified.
Run in a background. If :option:`-D` is used, the current working
directory is changed to '*/*'. Therefore if this option
is used, :option:`-d` option must be specified.
.. option:: -V, --verify-client
The server sends a client certificate request.
If the client did not return a certificate, the
handshake is terminated. Currently, this option
just requests a client certificate and does not
verify it.
The server sends a client certificate request. If the
client did not return a certificate, the handshake is
terminated. Currently, this option just requests a
client certificate and does not verify it.
.. option:: -d, --htdocs=<PATH>
Specify document root. If this option is not
specified, the document root is the current
working directory.
Specify document root. If this option is not specified,
the document root is the current working directory.
.. option:: -v, --verbose
Print debug information such as reception/
transmission of frames and name/value pairs.
Print debug information such as reception/ transmission
of frames and name/value pairs.
.. option:: --no-tls
Disable SSL/TLS.
.. option:: -c, --header-table-size=<N>
.. option:: -c, --header-table-size=<SIZE>
Specify decoder header table size.
.. option:: --color
Force colored log output.
.. option:: -p, --push=<PATH>=<PUSH_PATH,...>
Push resources <PUSH_PATH>s when <PATH> is
requested. This option can be used repeatedly to
specify multiple push configurations. <PATH> and
<PUSH_PATH>s are relative to document root. See
:option:`--htdocs` option. Example: -p/=/foo.png
-p/doc=/bar.css
Push resources <PUSH_PATH>s when <PATH> is requested.
This option can be used repeatedly to specify multiple
push configurations. <PATH> and <PUSH_PATH>s are
relative to document root. See :option:`--htdocs` option.
Example: :option:`-p`\/=/foo.png :option:`-p`\/doc=/bar.css
.. option:: -b, --padding=<N>
Add at most <N> bytes to a frame payload as
padding. Specify 0 to disable padding.
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
.. option:: -n, --workers=<CORE>
.. 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.
Default: 1
Default: ``1``
.. option:: -e, --error-gzip
Make error response gzipped.
.. option:: --dh-param-file=<PATH>
Path to file that contains DH parameters in PEM
format. Without this option, DHE cipher suites
are not available.
Path to file that contains DH parameters in PEM format.
Without this option, DHE cipher suites are not
available.
.. option:: --early-response
Start sending response when request HEADERS is
received, rather than complete request is
received.
Start sending response when request HEADERS is received,
rather than complete request is received.
.. option:: --trailer=<HEADER>
Add a trailer header to a response. <HEADER> must not
include pseudo header field (header field name starting
with ':'). The trailer is sent only if a response has
body part. Example: :option:`--trailer` 'foo: bar'.
.. option:: --hexdump
Display the incoming traffic in hexadecimal (Canonical
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.
.. option:: -h, --help
Display this help and exit.
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).
SEE ALSO
--------
nghttp(1), nghttpx(1), h2load(1)
:manpage:`nghttp(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`

View File

@@ -1,3 +0,0 @@
[SEE ALSO]
nghttp(1), nghttpx(1), h2load(1)

4
doc/nghttpd.h2r Normal file
View File

@@ -0,0 +1,4 @@
SEE ALSO
--------
:manpage:`nghttp(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +0,0 @@
[SEE ALSO]
nghttp(1), nghttpd(1), h2load(1)

102
doc/nghttpx.h2r Normal file
View File

@@ -0,0 +1,102 @@
FILES
-----
*/etc/nghttpx/nghttpx.conf*
The default configuration file path nghttpx searches at startup.
The configuration file path can be changed using :option:`--conf`
option.
Those lines which are staring ``#`` are treated as comment.
The option name in the configuration file is the long command-line
option name with leading ``--`` stripped (e.g., ``frontend``). Put
``=`` between option name and value. Don't put extra leading or
trailing spaces.
The options which do not take argument in the command-line *take*
argument in the configuration file. Specify ``yes`` as an argument
(e.g., ``http2-proxy=yes``). If other string is given, it is
ignored.
To specify private key and certificate file which are given as
positional arguments in command-line, use ``private-key-file`` and
``certificate-file``.
:option:`--conf` option cannot be used in the configuration file and
will be ignored if specified.
SIGNALS
-------
SIGQUIT
Shutdown gracefully. First accept pending connections and stop
accepting connection. After all connections are handled, nghttpx
exits.
SIGUSR1
Reopen log files.
SIGUSR2
Fork and execute nghttpx. It will execute the binary in the same
path with same command-line arguments and environment variables.
After new process comes up, sending SIGQUIT to the original process
to perform hot swapping.
SERVER PUSH
-----------
nghttpx supports HTTP/2 server push in default mode. nghttpx looks
for Link header field (`RFC 5988
<http://tools.ietf.org/html/rfc5988>`_) in response headers from
backend server and extracts URI-reference with parameter
``rel=preload`` (see `preload
<http://w3c.github.io/preload/#interoperability-with-http-link-header>`_)
and pushes those URIs to the frontend client. Here is a sample Link
header field to initiate server push:
.. code-block:: http
Link: </fonts/font.woff>; rel=preload
Link: </css/theme.css>; rel=preload
Currently, the following restrictions are applied for server push:
1. URI-reference must not contain authority. If it exists, it is not
pushed. ``/fonts/font.woff`` and ``css/theme.css`` are eligible to
be pushed. ``https://example.org/fonts/font.woff`` and
``//example.org/css/theme.css`` are not.
2. The associated stream must have method "GET" or "POST". The
associated stream's status code must be 200.
These limitations may be loosened in the future release.
UNIX DOMAIN SOCKET
------------------
nghttpx supports UNIX domain socket with a filename for both frontend
and backend connections.
Please note that current nghttpx implementation does not delete a
socket with a filename. And on start up, if nghttpx detects that the
specified socket already exists in the file system, nghttpx first
deletes it. However, if SIGUSR2 is used to execute new binary and
both old and new configurations use same filename, new binary does not
delete the socket and continues to use it.
OCSP STAPLING
-------------
OCSP query is done using external Python script
``fetch-ocsp-response``, which has been originally developed in Perl
as part of h2o project (https://github.com/h2o/h2o), and was
translated into Python.
The script file is usually installed under
``$(prefix)/share/nghttp2/`` directory. The actual path to script can
be customized using :option:`--fetch-ocsp-response-file` option.
SEE ALSO
--------
:manpage:`nghttp(1)`, :manpage:`nghttpd(1)`, :manpage:`h2load(1)`

105
doc/programmers-guide.rst Normal file
View File

@@ -0,0 +1,105 @@
Programmers' Guide
==================
Includes
--------
To use the public APIs, include ``nghttp2/nghttp2.h``::
#include <nghttp2/nghttp2.h>
The header files are also available online: :doc:`nghttp2.h` and
:doc:`nghttp2ver.h`.
Remarks
-------
Do not call `nghttp2_session_send()`, `nghttp2_session_mem_send()`,
`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` from the
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.
`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:
HTTP Messaging
--------------
By default, nghttp2 library checks HTTP messaging rules described in
`HTTP/2 specification, section 8
<https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-8>`_.
Everything described in that section is not validated however. We
briefly describe what the library does in this area. In the following
description, without loss of generality we omit CONTINUATION frame
since they must follow HEADERS frame and are processed atomically. In
other words, they are just one big HEADERS frame. To disable these
validations, use `nghttp2_option_set_no_http_messaging()`.
For HTTP request, including those carried by PUSH_PROMISE, HTTP
message starts with one HEADERS frame containing request headers. It
is followed by zero or more DATA frames containing request body, which
is followed by zero or one HEADERS containing trailer headers. The
request headers must include ":scheme", ":method" and ":path" pseudo
header fields unless ":method" is not "CONNECT". ":authority" is
optional, but nghttp2 requires either ":authority" or "Host" header
field must be present. If ":method" is "CONNECT", the request headers
must include ":method" and ":authority" and must omit ":scheme" and
":path".
For HTTP response, HTTP message starts with zero or more HEADERS
frames containing non-final response (status code 1xx). They are
followed by one HEADERS frame containing final response headers
(non-1xx). It is followed by zero or more DATA frames containing
response body, which is followed by zero or one HEADERS containing
trailer headers. The non-final and final response headers must
contain ":status" pseudo header field containing 3 digits only.
All request and response headers must include exactly one valid value
for each pseudo header field. Additionally nghttp2 requires all
request headers must not include more than one "Host" header field.
HTTP/2 prohibits connection-specific header fields. The following
header fields must not appear: "Connection", "Keep-Alive",
"Proxy-Connection", "Transfer-Encoding" and "Upgrade". Additionally,
"TE" header field must not include any value other than "trailers".
Each header field name and value must obey the field-name and
field-value production rules described in `RFC 7230, section
3.2. <https://tools.ietf.org/html/rfc7230#section-3.2>`_.
Additionally, all field name must be lower cased. While the pseudo
header fields must satisfy these rules, we just ignore illegal regular
headers (this means that these header fields are not passed to
application callback). This is because these illegal header fields
are floating around in existing internet and resetting stream just
because of this may break many web sites. This is especially true if
we forward to or translate from HTTP/1 traffic.
For "http" or "https" URIs, ":path" pseudo header fields must start
with "/". The only exception is OPTIONS request, in that case, "*" is
allowed in ":path" pseudo header field to represent system-wide
OPTIONS request.
With the above validations, nghttp2 library guarantees that header
field name passed to `nghttp2_on_header_callback()` is not empty.
Also required pseudo headers are all present and not empty.
nghttp2 enforces "Content-Length" validation as well. All request or
response headers must not contain more than one "Content-Length"
header field. If "Content-Length" header field is present, it must be
parsed as 64 bit signed integer. The sum of data length in the
following DATA frames must match with the number in "Content-Length"
header field if it is present (this does not include padding bytes).
Any deviation results in stream error of type PROTOCOL_ERROR. If
error is found in PUSH_PROMISE frame, stream error is raised against
promised stream.

View File

@@ -21,7 +21,9 @@ unpacked::
$ build/tools/make-standalone-toolchain.sh \
--install-dir=$ANDROID_HOME/toolchain \
--toolchain=arm-linux-androideabi-4.8
--toolchain=arm-linux-androideabi-4.9 \
--llvm-version=3.5 \
--platform=android-16
The additional flag ``--system=linux-x86_64`` may be required if you
are using x86_64 system.
@@ -29,13 +31,14 @@ are using x86_64 system.
The platform level is not important here because we don't use Android
specific C/C++ API.
The dependent libraries, such as OpenSSL and libevent should be built
The dependent libraries, such as OpenSSL and libev should be built
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.
@@ -46,7 +49,9 @@ correct path. Also add ``$ANDROID_HOME/toolchain/bin`` to ``PATH``::
$ export PATH=$PATH:$ANDROID_HOME/toolchain/bin
To configure OpenSSL, use the following script::
To configure OpenSSL, use the following script:
.. code-block:: sh
#!/bin/sh
@@ -63,7 +68,12 @@ To configure OpenSSL, use the following script::
And run ``make install`` to build and install.
To configure libevent, use the following script::
We cannot compile libev without modification. Apply `this patch
<https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed>`_ before
configuring libev. This patch is for libev-4.19. After applying the
patch, to configure libev, use the following script:
.. code-block:: sh
#!/bin/sh
@@ -86,7 +96,40 @@ To configure libevent, use the following script::
And run ``make install`` to build and install.
To configure spdylay, use the following script::
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.'
@@ -108,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

@@ -0,0 +1,57 @@
Contribution Guidelines
=======================
[This text was composed based on 1.2. License section of curl/libcurl
project.]
When contributing with code, you agree to put your changes and new
code under the same license nghttp2 is already using unless stated and
agreed otherwise.
When changing existing source code, you do not alter the copyright of
the original file(s). The copyright will still be owned by the
original creator(s) or those who have been assigned copyright by the
original author(s).
By submitting a patch to the nghttp2 project, you are assumed to have
the right to the code and to be allowed by your employer or whatever
to hand over that patch/code to us. We will credit you for your
changes as far as possible, to give credit but also to keep a trace
back to who made what changes. Please always provide us with your
full real name when contributing!
Coding style
------------
We use clang-format to format source code consistently. The
clang-format configuration file .clang-format is located at the root
directory. Since clang-format produces slightly different results
between versions, we currently use clang-format which comes with
clang-3.5.
To detect any violation to the coding style, we recommend to setup git
pre-commit hook to check coding style of the changes you introduced.
The pre-commit file is located at the root directory. Copy it under
.git/hooks and make sure that it is executable. The pre-commit script
uses clang-format-diff.py to detect any style errors. If it is not in
your PATH or it exists under different name (e.g.,
clang-format-diff-3.5 in debian), either add it to PATH variable or
add git option ``clangformatdiff.binary`` to point to the script.
For emacs users, integrating clang-format to emacs is very easy.
clang-format.el should come with clang distribution. If it is not
found, download it from `here
<https://llvm.org/svn/llvm-project/cfe/trunk/tools/clang-format/clang-format.el>`_.
And add these lines to your .emacs file:
.. code-block:: lisp
;; From
;; https://code.google.com/p/chromium/wiki/Emacs#Use_Google's_C++_style!
(load "/<path/to>/clang-format.el")
(add-hook 'c-mode-common-hook
(function (lambda () (local-set-key (kbd "TAB")
'clang-format-region))))
You can find other editor integration in
http://clang.llvm.org/docs/ClangFormat.html.

View File

@@ -50,8 +50,9 @@ Flow Control
------------
HTTP/2 and SPDY/3 or later employ flow control and it may affect
benchmarking results. To adjust receiver flow control window size,
there is following options:
benchmarking results. By default, h2load uses large enough flow
control window, which effectively disables flow control. To adjust
receiver flow control window size, there are following options:
``-w``
Sets the stream level initial window size to
@@ -86,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

@@ -17,6 +17,7 @@ Contents:
:maxdepth: 2
package_README
contribute
building-android-binary
tutorial-client
tutorial-server
@@ -27,14 +28,18 @@ Contents:
h2load.1
nghttpx-howto
h2load-howto
programmers-guide
apiref
libnghttp2_asio
python-apiref
nghttp2.h
nghttp2ver.h
asio_http2_server.h
asio_http2_client.h
asio_http2.h
Source <https://github.com/tatsuhiro-t/nghttp2>
Issues <https://github.com/tatsuhiro-t/nghttp2/issues>
nghttp2.org <https://nghttp2.org/>
Released Versions
=================
@@ -44,6 +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://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-04
* HTTP/2 https://tools.ietf.org/html/rfc7540
* HPACK https://tools.ietf.org/html/rfc7541

View File

@@ -4,7 +4,7 @@ libnghttp2_asio: High level HTTP/2 C++ library
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
high level abstraction API to build HTTP/2 applications. It depends
on Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
provides server side API.
provides server and client side API.
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
configure flag to build libnghttp2_asio. The required Boost libraries
@@ -14,46 +14,64 @@ are:
* Boost::System
* Boost::Thread
To use libnghttp2_asio, first include following header file:
We have 3 header files for this library:
.. code-block:: cpp
* :doc:`asio_http2_server.h`
* :doc:`asio_http2_client.h`
* :doc:`asio_http2.h`
#include <nghttp2/asio_http2.h>
asio_http2.h is included from the other two files.
Also take a look at that header file :doc:`asio_http2.h`.
To build a program with libnghttp2_asio, link to the following
libraries::
-lnghttp2_asio -lboost_system
If ``boost::asio::ssl`` is used in application code, OpenSSL is also
required in link line::
-lnghttp2_asio -lboost_system -lssl -lcrypto
Server API
----------
To use server API, first include following header file:
.. code-block:: cpp
#include <nghttp2/asio_http2_server.h>
Also take a look at that header file :doc:`asio_http2_server.h`.
Server API is designed to build HTTP/2 server very easily to utilize
C++11 anonymous function and closure. The bare minimum example of
HTTP/2 server looks like this:
.. code-block:: cpp
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char* argv[])
{
int main(int argc, char *argv[]) {
boost::system::error_code ec;
http2 server;
server.listen
("*", 3000,
[](const std::shared_ptr<request>& req,
const std::shared_ptr<response>& res)
{
res->write_head(200);
res->end("hello, world");
});
server.handle("/", [](const request &req, const response &res) {
res.write_head(200);
res.end("hello, world\n");
});
if (server.listen_and_serve(ec, "localhost", "3000")) {
std::cerr << "error: " << ec.message() << std::endl;
}
}
First we instantiate ``nghttp2::asio_http2::server::http2`` object.
Then call ``nghttp2::asio_http2::server::http2::listen`` function with
address and port to listen to and callback function, namely "request
callback", invoked when request arrives.
``nghttp2::asio_http2::server::http2::handle`` function registers
pattern and its handler function. In this example, we register "/" as
pattern, which matches all requests. Then call
``nghttp2::asio_http2::server::http2::listen_and_serve`` function with
address and port to listen to.
The ``req`` and ``res`` represent HTTP request and response
respectively. ``nghttp2::asio_http2_::server::response::write_head``
@@ -62,9 +80,13 @@ 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
``nghttp2::asio_http2::server::response::on_close`` function.
Application must not use those objects after this call.
Serving static files and enabling SSL/TLS
+++++++++++++++++++++++++++++++++++++++++
@@ -73,44 +95,47 @@ SSL/TLS.
.. code-block:: cpp
#include <nghttp2/asio_http2.h>
#include <nghttp2/asio_http2_server.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char* argv[])
{
int main(int argc, char *argv[]) {
boost::system::error_code ec;
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
tls.use_private_key_file("server.key", boost::asio::ssl::context::pem);
tls.use_certificate_chain_file("server.crt");
configure_tls_context_easy(ec, tls);
http2 server;
server.tls("server.key", "server.crt");
server.handle("/index.html", [](const request &req, const response &res) {
res.write_head(200);
res.end(file_generator("index.html"));
});
server.listen
("*", 3000,
[](const std::shared_ptr<request>& req,
const std::shared_ptr<response>& res)
{
if(req->path() == "/" || req->path() == "/index.html") {
res->write_head(200);
res->end(file_reader("index.html"));
} else {
res->write_head(404);
res->end("<html><head><title>404</title></head>"
"<body>404 Not Found</body></html>");
}
});
if (server.listen_and_serve(ec, tls, "localhost", "3000")) {
std::cerr << "error: " << ec.message() << std::endl;
}
}
Specifying path to private key file and certificate file in
``nghttp2::asio_http2::server::http2::tls`` will enable SSL/TLS. Both
files must be in PEM format.
We first create ``boost::asio::ssl::context`` object and set path to
private key file and certificate file.
``nghttp2::asio_http2::server::configure_tls_context_easy`` function
configures SSL/TLS context object for HTTP/2 server use, including NPN
callbacks.
In the above example, if request path is either "/" or "/index.html",
we serve index.html file in the current working directory.
In the above example, if request path is "/index.html", we serve
index.html file in the current working directory.
``nghttp2::asio_http2::server::response::end`` has overload to take
function of type ``nghttp2::asio_http2::read_cb`` and application pass
its implementation to generate response body. For the convenience,
libnghttp2_asio library provides ``nghttp2::asio_http2::file_reader``
function to generate function to server static file.
function of type ``nghttp2::asio_http2::generator_cb`` and application
pass its implementation to generate response body. For the
convenience, libnghttp2_asio library provides
``nghttp2::asio_http2::file_generator`` function to generate function
to server static file. If other resource is requested, server
automatically responds with 404 status code.
Server push
+++++++++++
@@ -119,48 +144,56 @@ Server push is also supported.
.. code-block:: cpp
#include <nghttp2/asio_http2.h>
#include <nghttp2/asio_http2_server.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char* argv[])
{
int main(int argc, char *argv[]) {
boost::system::error_code ec;
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
tls.use_private_key_file("server.key", boost::asio::ssl::context::pem);
tls.use_certificate_chain_file("server.crt");
configure_tls_context_easy(ec, tls);
http2 server;
server.tls("server.key", "server.crt");
std::string style_css = "h1 { color: green; }";
server.listen
("*", 3000,
[](const std::shared_ptr<request>& req,
const std::shared_ptr<response>& res)
{
if(req->path() == "/") {
req->push("GET", "/my.css");
server.handle("/", [&style_css](const request &req, const response &res) {
boost::system::error_code ec;
auto push = res.push(ec, "GET", "/style.css");
push->write_head(200);
push->end(style_css);
res->write_head(200);
res->end(file_reader("index.html"));
res.write_head(200);
res.end(R"(
<!DOCTYPE html><html lang="en">
<title>HTTP/2 FTW</title><body>
<link href="/style.css" rel="stylesheet" type="text/css">
<h1>This should be green</h1>
</body></html>
)");
});
return;
}
server.handle("/style.css",
[&style_css](const request &req, const response &res) {
res.write_head(200);
res.end(style_css);
});
if(req->path() == "/my.css") {
res->write_head(200);
res->end(file_reader("my.css"));
return;
}
res->write_head(404);
res->end("<html><head><title>404</title></head>"
"<body>404 Not Found</body></html>");
});
if (server.listen_and_serve(ec, tls, "localhost", "3000")) {
std::cerr << "error: " << ec.message() << std::endl;
}
}
When client requested "/", we push "/my.css". To push resource, call
``nghttp2::asio_http2::server::request::push`` function with desired
method and path. Later, the callback will be called with the pushed
resource "/my.css".
When client requested any resource other than "/style.css", we push
"/style.css". To push resource, call
``nghttp2::asio_http2::server::response::push`` function with desired
method and path. It returns another response object and use its
functions to send push response.
Enable multi-threading
++++++++++++++++++++++
@@ -176,73 +209,225 @@ desired number of threads:
// Use 4 native threads
server.num_threads(4);
Run blocking tasks in background thread
+++++++++++++++++++++++++++++++++++++++
Client API
----------
The request callback is called in the same thread where HTTP request
is handled. And many connections shares the same thread, we cannot
directly run blocking tasks in request callback.
To run blocking tasks, use
``nghttp2::asio_http2::server::request::run_task``. The passed
callback will be executed in the different thread from the thread
where request callback was executed. So application can perform
blocking task there. The example follows:
To use client API, first include following header file:
.. code-block:: cpp
#include <unistd.h>
#include <nghttp2/asio_http2.h>
#include <nghttp2/asio_http2_client.h>
Also take a look at that header file :doc:`asio_http2_client.h`.
Here is the sample client code to access HTTP/2 server and print out
response header fields and response body to the console screen:
.. code-block:: cpp
#include <iostream>
#include <nghttp2/asio_http2_client.h>
using boost::asio::ip::tcp;
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
using namespace nghttp2::asio_http2::client;
int main(int argc, char* argv[])
{
http2 server;
int main(int argc, char *argv[]) {
boost::system::error_code ec;
boost::asio::io_service io_service;
server.num_concurrent_tasks(16);
// connect to localhost:3000
session sess(io_service, "localhost", "3000");
server.listen
("*", 3000,
[](const std::shared_ptr<request>& req,
const std::shared_ptr<response>& res)
{
req->run_task
([res](channel& channel)
{
// executed in different thread than the thread where
// request callback was executed.
sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
boost::system::error_code ec;
// using res directly here is not safe. Capturing it by
// value is safe because it is std::shared_ptr.
auto req = sess.submit(ec, "GET", "http://localhost:3000/");
sleep(1);
req->on_response([](const response &res) {
// print status code and response header fields.
std::cerr << "HTTP/2 " << res.status_code() << std::endl;
for (auto &kv : res.header()) {
std::cerr << kv.first << ": " << kv.second.value << "\n";
}
std::cerr << std::endl;
channel.post
([res]()
{
// executed in the same thread where request callback
// was executed.
res->write_head(200);
res->end("hello, world");
});
});
});
res.on_data([](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
});
req->on_close([&sess](uint32_t error_code) {
// shutdown session after first request was done.
sess.shutdown();
});
});
sess.on_error([](const boost::system::error_code &ec) {
std::cerr << "error: " << ec.message() << std::endl;
});
io_service.run();
}
First we set the number of background threads which run tasks. By
default it is set to 1. In this example, we set it to 16, so at most
16 tasks can be executed concurrently without blocking handling new
requests.
``nghttp2::asio_http2::client::session`` object takes
``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 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.
We call ``req->run_task()`` to execute task in background thread. In
the passed callback, we just simply sleeps 1 second. After sleep is
over, we schedule another callback to send response to the client.
Since the callback passed to ``req->run_task()`` is executed in the
different thread from the thread where request callback is called,
using ``req`` or ``res`` object directly there may cause undefined
behaviour. To avoid this issue, we can use
``nghttp2::asio_http2::channel::post`` by supplying a callback which
in turn get called in the same thread where request callback was
called.
The life time of req and res object ends after the callback set by
``nghttp2::asio_http2::server::request::on_close`` function.
Application must not use those objects after this call.
Normally, client does not stop even after all requests are done unless
connection is lost. To stop client, call
``nghttp2::asio_http2::server::session::shutdown()``.
Recieve server push and enable SSL/TLS
++++++++++++++++++++++++++++++++++++++
.. code-block:: cpp
#include <iostream>
#include <nghttp2/asio_http2_client.h>
using boost::asio::ip::tcp;
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::client;
int main(int argc, char *argv[]) {
boost::system::error_code ec;
boost::asio::io_service io_service;
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
tls.set_default_verify_paths();
// disabled to make development easier...
// tls_ctx.set_verify_mode(boost::asio::ssl::verify_peer);
configure_tls_context(ec, tls);
// connect to localhost:3000
session sess(io_service, tls, "localhost", "3000");
sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
boost::system::error_code ec;
auto req = sess.submit(ec, "GET", "http://localhost:3000/");
req->on_response([&sess](const response &res) {
std::cerr << "response received!" << std::endl;
res.on_data([&sess](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
});
req->on_push([](const request &push) {
std::cerr << "push request received!" << std::endl;
push.on_response([](const response &res) {
std::cerr << "push response received!" << std::endl;
res.on_data([](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
});
});
});
sess.on_error([](const boost::system::error_code &ec) {
std::cerr << "error: " << ec.message() << std::endl;
});
io_service.run();
}
The above sample code demonstrates how to enable SSL/TLS and receive
server push. Currently,
``nghttp2::asio_http2::client::configure_tls_context`` function setups
NPN callbacks for SSL/TLS context for HTTP/2 use.
To receive server push, use
``nghttp2::asio_http2::client::request::on_push`` function to set
callback function which is invoked when server push request is
arrived. The callback function takes
``nghttp2::asio_http2::client::request`` object, which contains the
pushed request. To get server push response, set callback using
``nghttp2::asio_http2::client::request::on_response``.
As stated in the previous section, client does not stop automatically
as long as HTTP/2 session is fine and connection is alive. We don't
call ``nghttp2::asio_http2::client::session::shutdown`` in this
example, so the program does not terminate after all responses are
received. Hit Ctrl-C to terminate the program.
Multiple concurrent requests
++++++++++++++++++++++++++++
.. code-block:: cpp
#include <iostream>
#include <nghttp2/asio_http2_client.h>
using boost::asio::ip::tcp;
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::client;
int main(int argc, char *argv[]) {
boost::system::error_code ec;
boost::asio::io_service io_service;
// connect to localhost:3000
session sess(io_service, "localhost", "3000");
sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
boost::system::error_code ec;
auto printer = [](const response &res) {
res.on_data([](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
};
std::size_t num = 3;
auto count = std::make_shared<int>(num);
for (std::size_t i = 0; i < num; ++i) {
auto req = sess.submit(ec, "GET",
"http://localhost:3000/" + std::to_string(i + 1));
req->on_response(printer);
req->on_close([&sess, count](uint32_t error_code) {
if (--*count == 0) {
// shutdown session after |num| requests were done.
sess.shutdown();
}
});
}
});
sess.on_error([](const boost::system::error_code &ec) {
std::cerr << "error: " << ec.message() << std::endl;
});
io_service.run();
}
Here is the sample to send 3 requests at once. Depending on the
server settings, these requests are processed out-of-order. In this
example, we have a trick to shutdown session after all requests were
done. We made ``count`` object which is shared pointer to int and is
initialized to 3. On each request closure (the invocation of the
callback set by ``nghttp2::asio_http2::client::request::on_close``),
we decrement the count. If count becomes 0, we are sure that all
requests have been done and initiate shutdown.

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
@@ -52,15 +52,15 @@ like forward proxy and assumes the backend is HTTP/1 proxy server
(e.g., squid, traffic server). So HTTP/1 request must include
absolute URI in request line.
By default, frontend connection is encrypted, this mode is also called
secure proxy. If nghttpx is linked with spdylay, it supports SPDY
protocols and it works as so called SPDY proxy.
By default, frontend connection is encrypted. So this mode is also
called secure proxy. If nghttpx is linked with spdylay, it supports
SPDY protocols and it works as so called SPDY proxy.
With ``--frontend-no-tls`` option, SSL/TLS is turned off in frontend
connection, so the connection gets insecure.
The backend must be HTTP/1 proxy server. nghttpx only supports 1
backend server address. It translates incoming requests to HTTP/1
The backend must be HTTP/1 proxy server. nghttpx supports multiple
backend server addresses. It translates incoming requests to HTTP/1
request to backend server. The backend server performs real proxy
work for each request, for example, dispatching requests to the origin
server and caching contents.
@@ -87,7 +87,7 @@ proxy, user has to create proxy.pac script file like this:
``SERVERADDR`` and ``PORT`` is the hostname/address and port of the
machine nghttpx is running. Please note that both Firefox nightly and
Chromium requires valid certificate for secure proxy.
Chromium require valid certificate for secure proxy.
For Firefox nightly, open Preference window and select Advanced then
click Network tab. Clicking Connection Settings button will show the
@@ -100,9 +100,9 @@ For Chromium, use following command-line::
$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
Squid may work as out-of-box. Traffic server requires to be
configured as forward proxy. Here is the minimum configuration items
to edit::
As HTTP/1 proxy server, Squid may work as out-of-box. Traffic server
requires to be configured as forward proxy. Here is the minimum
configuration items to edit::
CONFIG proxy.config.reverse_proxy.enabled INT 0
CONFIG proxy.config.url_remap.remap_required INT 0
@@ -124,7 +124,9 @@ HTTP/1 frontend connection can be upgraded to HTTP/2 using HTTP
Upgrade. To disable SSL/TLS in backend connection, use
``--backend-no-tls`` option.
The backend connection is created one per worker (thread).
By default, the number of backend HTTP/2 connections per worker
(thread) is determined by number of ``-b`` option. To adjust this
value, use ``--backend-http2-connections-per-worker`` option.
The backend server is supporsed to be a HTTP/2 web server (e.g.,
nghttpd). The one use-case of this mode is utilize existing HTTP/1
@@ -156,7 +158,9 @@ HTTP/1 frontend connection can be upgraded to HTTP/2 using HTTP
Upgrade. To disable SSL/TLS in backend connection, use
``--backend-no-tls`` option.
The backend connection is created one per worker (thread).
By default, the number of backend HTTP/2 connections per worker
(thread) is determined by number of ``-b`` option. To adjust this
value, use ``--backend-http2-connections-per-worker`` option.
The backend server must be a HTTP/2 proxy. You can use nghttpx in
`HTTP/2 proxy mode`_ as backend server. The one use-case of this mode
@@ -196,10 +200,14 @@ With ``--frontend-no-tls`` option, SSL/TLS is turned off in frontend
connection, so the connection gets insecure. To disable SSL/TLS in
backend connection, use ``--backend-no-tls`` option.
By default, the number of backend HTTP/2 connections per worker
(thread) is determined by number of ``-b`` option. To adjust this
value, use ``--backend-http2-connections-per-worker`` option.
The backend server is supporsed to be a HTTP/2 web server or HTTP/2
proxy. If backend server is HTTP/2 proxy, use
``--no-location-rewrite`` option to disable rewriting location header
field.
``--no-location-rewrite`` and ``--no-host-rewrite`` options to disable
rewriting location, host and :authority header field.
The use-case of this mode is aggregate the incoming connections to one
HTTP/2 connection. One backend HTTP/2 connection is created per
@@ -235,12 +243,12 @@ Read/write rate limit
---------------------
nghttpx supports transfer rate limiting on frontend connections. You
can do rate limit per worker (thread) for reading and writeing
can do rate limit per frontend connection for reading and writing
individually.
To rate limit per worker (thread), use ``--worker-read-rate`` and
``--worker-read-burst`` options. For writing, use
``--worker-write-rate`` and ``--worker-write-burst``.
To perform rate limit for reading, use ``--read-rate`` and
``--read-burst`` options. For writing, use ``--write-rate`` and
``--write-burst``.
Please note that rate limit is performed on top of TCP and nothing to
do with HTTP/2 flow control.
@@ -263,10 +271,10 @@ precedence. If the above conditions are not met with the host value
in :authority header field, rewrite is retried with the value in host
header field.
Hot deploy
----------
Hot swapping
------------
nghttpx supports hot deploy feature using signals. The hot deploy in
nghttpx supports hot swapping using signals. The hot swapping in
nghttpx is multi step process. First send USR2 signal to nghttpx
process. It will do fork and execute new executable, using same
command-line arguments and environment variables. At this point, both
@@ -284,3 +292,12 @@ log rotation daemon renamed existing log files. To tell nghttpx to
re-open log files, send USR1 signal to nghttpx process. It will
re-open files specified by ``--accesslog-file`` and
``--errorlog-file`` options.
Multiple backend addresses
--------------------------
nghttpx supports multiple backend addresses. To specify them, just
use ``-b`` option repeatedly. For example, to use backend1:8080 and
backend2:8080, use command-line like this: ``-bbackend1,8080
-bbackend2,8080``. For HTTP/2 backend, see also
``--backend-http2-connections-per-worker`` option.

View File

@@ -220,6 +220,10 @@ HTTP/2 servers
This is a value of ``:path`` header field.
.. py:attribute:: headers
Request header fields.
A :py:class:`BaseRequestHandler` has the following methods:
.. py:method:: on_headers()
@@ -249,10 +253,28 @@ HTTP/2 servers
Send response. The *status* is HTTP status code. The *headers*
is additional response headers. The *:status* header field will
be appended by the library. The *body* is the response body.
It could be ``None`` if response body is empty. Or it must be
instance of either ``str``, ``bytes`` or :py:class:`io.IOBase`.
If instance of ``str`` is specified, it will be encoded using
UTF-8.
It could be ``None`` if response body is empty. Or it must be
instance of either ``str``, ``bytes``, :py:class:`io.IOBase` or
callable, called body generator, which takes one parameter,
size. The body generator generates response body. It can pause
generation of response so that it can wait for slow backend data
generation. When invoked, it should return tuple, byte string
at most size length and flag. The flag is either
:py:data:`DATA_OK`, :py:data:`DATA_EOF` or
:py:data:`DATA_DEFERRED`. For non-empty byte string and it is
not the last chunk of response, :py:data:`DATA_OK` must be
returned as flag. If this is the last chunk of the response
(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_DEFERRED`). When data arrived, call
:py:meth:`resume()` and restart response body transmission.
Only the body generator can pause response body generation;
instance of :py:class:`io.IOBase` must not block.
If instance of ``str`` is specified as *body*, it will be
encoded using UTF-8.
The *headers* is a list of tuple of the form ``(name,
value)``. The ``name`` and ``value`` can be either byte string
@@ -273,10 +295,8 @@ HTTP/2 servers
The *status* is HTTP status code. The *headers* is additional
response headers. The ``:status`` header field is appended by
the library. The *body* is the response body. It could be
``None`` if response body is empty. Or it must be instance of
either ``str``, ``bytes`` or ``io.IOBase``. If instance of
``str`` is specified, it is encoded using UTF-8.
the library. The *body* is the response body. It has the same
semantics of *body* parameter of :py:meth:`send_response()`.
The headers and request_headers are a list of tuple of the form
``(name, value)``. The ``name`` and ``value`` can be either byte
@@ -288,6 +308,27 @@ HTTP/2 servers
Raises the exception if any error occurs.
.. py:method:: resume()
Signals the restarting of response body transmission paused by
``DATA_DEFERRED`` from the body generator (see
:py:meth:`send_response()` about the body generator). It is not
an error calling this method while response body transmission is
not paused.
.. py:data:: DATA_OK
``DATA_OK`` indicates non empty data is generated from body generator.
.. py:data:: DATA_EOF
``DATA_EOF`` indicates the end of response body.
.. py:data:: DATA_DEFERRED
``DATA_DEFERRED`` indicates that data are not available right now
and response should be paused.
The following example illustrates :py:class:`HTTP2Server` and
:py:class:`BaseRequestHandler` usage:
@@ -296,6 +337,7 @@ The following example illustrates :py:class:`HTTP2Server` and
#!/usr/bin/env python
import io, ssl
import nghttp2
class Handler(nghttp2.BaseRequestHandler):
@@ -311,9 +353,85 @@ The following example illustrates :py:class:`HTTP2Server` and
body=io.BytesIO(b'nghttp2-python FTW'))
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
ctx.load_cert_chain('server.crt', 'server.key')
# give None to ssl to make the server non-SSL/TLS
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
server.serve_forever()
The following example illustrates HTTP/2 server using asynchronous
response body generation. This is simplified reverse proxy:
.. code-block:: python
#!/usr/bin/env python
import ssl
import os
import urllib
import asyncio
import io
import nghttp2
@asyncio.coroutine
def get_http_header(handler, url):
url = urllib.parse.urlsplit(url)
ssl = url.scheme == 'https'
if url.port == None:
if url.scheme == 'https':
port = 443
else:
port = 80
else:
port = url.port
connect = asyncio.open_connection(url.hostname, port, ssl=ssl)
reader, writer = yield from connect
req = 'GET {path} HTTP/1.0\r\n\r\n'.format(path=url.path or '/')
writer.write(req.encode('utf-8'))
# skip response header fields
while True:
line = yield from reader.readline()
line = line.rstrip()
if not line:
break
# read body
while True:
b = yield from reader.read(4096)
if not b:
break
handler.buf.write(b)
writer.close()
handler.buf.seek(0)
handler.eof = True
handler.resume()
class Body:
def __init__(self, handler):
self.handler = handler
self.handler.eof = False
self.handler.buf = io.BytesIO()
def generate(self, n):
buf = self.handler.buf
data = buf.read1(n)
if not data and not self.handler.eof:
return None, nghttp2.DATA_DEFERRED
return data, nghttp2.DATA_EOF if self.handler.eof else nghttp2.DATA_OK
class Handler(nghttp2.BaseRequestHandler):
def on_headers(self):
body = Body(self)
asyncio.async(get_http_header(
self, 'http://localhost' + self.path.decode('utf-8')))
self.send_response(status=200, body=body.generate)
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
ctx.load_cert_chain('server.crt', 'server.key')
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
server.serve_forever()

View File

@@ -22,12 +22,10 @@ protocol over the SSL/TLS transport. In this tutorial, we use
`nghttp2_select_next_protocol()` function to select the HTTP/2
protocol the library supports::
static int select_next_proto_cb(SSL* ssl,
unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen,
void *arg)
{
if(nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg _U_) {
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
}
return SSL_TLSEXT_ERR_OK;
@@ -36,17 +34,17 @@ protocol the library supports::
The callback is set to the SSL_CTX object using
``SSL_CTX_set_next_proto_select_cb()`` function::
static SSL_CTX* create_ssl_ctx(void)
{
static SSL_CTX *create_ssl_ctx(void) {
SSL_CTX *ssl_ctx;
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if(!ssl_ctx) {
if (!ssl_ctx) {
errx(1, "Could not create SSL/TLS context: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
return ssl_ctx;
}
@@ -67,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 */
@@ -91,25 +89,22 @@ respectively.
Then we call function ``initiate_connection()`` to start connecting to
the remote server::
static void initiate_connection(struct event_base *evbase,
SSL_CTX *ssl_ctx,
static void initiate_connection(struct event_base *evbase, SSL_CTX *ssl_ctx,
const char *host, uint16_t port,
http2_session_data *session_data)
{
http2_session_data *session_data) {
int rv;
struct bufferevent *bev;
SSL *ssl;
ssl = create_ssl(ssl_ctx);
bev = bufferevent_openssl_socket_new(evbase, -1, ssl,
BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_DEFER_CALLBACKS |
BEV_OPT_CLOSE_ON_FREE);
bev = bufferevent_openssl_socket_new(
evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
AF_UNSPEC, host, port);
if(rv != 0) {
if (rv != 0) {
errx(1, "Could not connect to the remote host %s", host);
}
session_data->bev = bev;
@@ -122,10 +117,9 @@ The ``eventcb()`` is invoked by libevent event loop when an event
(e.g., connection has been established, timeout, etc) happens on the
underlying network socket::
static void eventcb(struct bufferevent *bev, short events, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(events & BEV_EVENT_CONNECTED) {
static void eventcb(struct bufferevent *bev, short events, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (events & BEV_EVENT_CONNECTED) {
int fd = bufferevent_getfd(bev);
int val = 1;
fprintf(stderr, "Connected\n");
@@ -133,16 +127,16 @@ underlying network socket::
initialize_nghttp2_session(session_data);
send_client_connection_header(session_data);
submit_request(session_data);
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
}
return;
}
if(events & BEV_EVENT_EOF) {
if (events & BEV_EVENT_EOF) {
warnx("Disconnected from the remote host");
} else if(events & BEV_EVENT_ERROR) {
} else if (events & BEV_EVENT_ERROR) {
warnx("Network error");
} else if(events & BEV_EVENT_TIMEOUT) {
} else if (events & BEV_EVENT_TIMEOUT) {
warnx("Timeout");
}
delete_http2_session_data(session_data);
@@ -154,28 +148,27 @@ event, we just simply tear down the connection. The
finished successfully. We first initialize nghttp2 session object in
``initialize_nghttp2_session()`` function::
static void initialize_nghttp2_session(http2_session_data *session_data)
{
static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_session_callbacks *callbacks;
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback
(callbacks, on_frame_recv_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
(callbacks, on_data_chunk_recv_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
callbacks, on_data_chunk_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback
(callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback
(callbacks, on_header_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback
(callbacks, on_begin_headers_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
nghttp2_session_client_new(&session_data->session, callbacks, session_data);
@@ -191,30 +184,26 @@ 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)
{
static void send_client_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = {
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
};
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
bufferevent_write(session_data->bev,
NGHTTP2_CLIENT_CONNECTION_PREFACE,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE,
iv, ARRLEN(iv));
if(rv != 0) {
/* 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) {
errx(1, "Could not submit SETTINGS: %s", nghttp2_strerror(rv));
}
}
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
@@ -225,24 +214,22 @@ used, which is described about later.
After the transmission of client connection header, we enqueue HTTP
request in ``submit_request()`` function::
static void submit_request(http2_session_data *session_data)
{
static void submit_request(http2_session_data *session_data) {
int32_t stream_id;
http2_stream_data *stream_data = session_data->stream_data;
const char *uri = stream_data->uri;
const struct http_parser_url *u = stream_data->u;
nghttp2_nv hdrs[] = {
MAKE_NV2(":method", "GET"),
MAKE_NV(":scheme",
&uri[u->field_data[UF_SCHEMA].off], u->field_data[UF_SCHEMA].len),
MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
MAKE_NV(":path", stream_data->path, stream_data->pathlen)
};
MAKE_NV2(":method", "GET"),
MAKE_NV(":scheme", &uri[u->field_data[UF_SCHEMA].off],
u->field_data[UF_SCHEMA].len),
MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
MAKE_NV(":path", stream_data->path, stream_data->pathlen)};
fprintf(stderr, "Request headers:\n");
print_headers(stderr, hdrs, ARRLEN(hdrs));
stream_id = nghttp2_submit_request(session_data->session, NULL,
hdrs, ARRLEN(hdrs), NULL, stream_data);
if(stream_id < 0) {
stream_id = nghttp2_submit_request(session_data->session, NULL, hdrs,
ARRLEN(hdrs), NULL, stream_data);
if (stream_id < 0) {
errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id));
}
@@ -261,26 +248,25 @@ this request.
The next bufferevent callback is ``readcb()``, which is invoked when
data is available to read in the bufferevent input buffer::
static void readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
static void readcb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
ssize_t readlen;
struct evbuffer *input = bufferevent_get_input(bev);
size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
if(readlen < 0) {
if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
delete_http2_session_data(session_data);
return;
}
if(evbuffer_drain(input, readlen) != 0) {
if (evbuffer_drain(input, readlen) != 0) {
warnx("Fatal error: evbuffer_drain failed");
delete_http2_session_data(session_data);
return;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
@@ -293,12 +279,11 @@ invoke nghttp2 callbacks and also queue frames. Since there may be
pending frames, we call ``session_send()`` function to send those
frames. The ``session_send()`` function is defined as follows::
static int session_send(http2_session_data *session_data)
{
static int session_send(http2_session_data *session_data) {
int rv;
rv = nghttp2_session_send(session_data->session);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -310,11 +295,9 @@ format and call ``send_callback()`` function of type
:type:`nghttp2_send_callback`. The ``send_callback()`` is defined as
follows::
static ssize_t send_callback(nghttp2_session *session,
const uint8_t *data, size_t length,
int flags, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
size_t length, int flags _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev;
bufferevent_write(bev, data, length);
return length;
@@ -336,12 +319,11 @@ buffered data, see the ``send_callback()`` in the server tutorial.
The third bufferevent callback is ``writecb()``, which is invoked when
all data written in the bufferevent output buffer have been sent::
static void writecb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0 &&
evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
static void writecb(struct bufferevent *bev _U_, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0 &&
evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
delete_http2_session_data(session_data);
}
}
@@ -367,18 +349,16 @@ Let's describe remaining nghttp2 callbacks we setup in
Each request header name/value pair is emitted via
``on_header_callback`` function::
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
uint8_t flags,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
switch(frame->hd.type) {
static int on_header_callback(nghttp2_session *session _U_,
const nghttp2_frame *frame, const uint8_t *name,
size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags _U_,
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
/* Print response headers for the initiated request. */
print_header(stderr, name, namelen, value, valuelen);
break;
@@ -387,19 +367,18 @@ Each request header name/value pair is emitted via
return 0;
}
In this turotial, we just print the name/value pair.
In this tutorial, we just print the name/value pair.
After all name/value pairs are emitted for a frame,
``on_frame_recv_callback`` function is called::
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
switch(frame->hd.type) {
static int on_frame_recv_callback(nghttp2_session *session _U_,
const nghttp2_frame *frame, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
fprintf(stderr, "All headers received\n");
}
break;
@@ -408,46 +387,43 @@ 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.
The ``on_data_chunk_recv_callback()`` function is invoked when a chunk
of data is received from the remote peer::
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
uint8_t flags _U_, int32_t stream_id,
const uint8_t *data, size_t len,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
if(session_data->stream_data->stream_id == stream_id) {
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
if (session_data->stream_data->stream_id == stream_id) {
fwrite(data, len, 1, stdout);
}
return 0;
}
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.
The ``on_stream_close_callback()`` function is invoked when the stream
is about to close::
static int on_stream_close_callback(nghttp2_session *session,
int32_t stream_id,
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
nghttp2_error_code error_code,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
int rv;
if(session_data->stream_data->stream_id == stream_id) {
fprintf(stderr, "Stream %d closed with error_code=%d\n",
stream_id, error_code);
if (session_data->stream_data->stream_id == stream_id) {
fprintf(stderr, "Stream %d closed with error_code=%d\n", stream_id,
error_code);
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
if(rv != 0) {
if (rv != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
}

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

@@ -29,17 +29,17 @@ time::
static unsigned char next_proto_list[256];
static size_t next_proto_list_len;
static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
void *arg)
{
static int next_proto_cb(SSL *s _U_, const unsigned char **data,
unsigned int *len, void *arg _U_) {
*data = next_proto_list;
*len = (unsigned int)next_proto_list_len;
return SSL_TLSEXT_ERR_OK;
}
static SSL_CTX* create_ssl_ctx(const char *key_file, const char *cert_file)
{
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
SSL_CTX *ssl_ctx;
EC_KEY *ecdh;
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
...
@@ -104,8 +104,7 @@ We first create a listener object to accept incoming connections. We use
libevent's ``struct evconnlistener`` for this purpose::
static void start_listen(struct event_base *evbase, const char *service,
app_context *app_ctx)
{
app_context *app_ctx) {
int rv;
struct addrinfo hints;
struct addrinfo *res, *rp;
@@ -116,19 +115,20 @@ libevent's ``struct evconnlistener`` for this purpose::
hints.ai_flags = AI_PASSIVE;
#ifdef AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG;
#endif // AI_ADDRCONFIG
#endif /* AI_ADDRCONFIG */
rv = getaddrinfo(NULL, service, &hints, &res);
if(rv != 0) {
if (rv != 0) {
errx(1, NULL);
}
for(rp = res; rp; rp = rp->ai_next) {
for (rp = res; rp; rp = rp->ai_next) {
struct evconnlistener *listener;
listener = evconnlistener_new_bind(evbase, acceptcb, app_ctx,
LEV_OPT_CLOSE_ON_FREE |
LEV_OPT_REUSEABLE, -1,
rp->ai_addr, rp->ai_addrlen);
if(listener) {
listener = evconnlistener_new_bind(
evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
16, rp->ai_addr, rp->ai_addrlen);
if (listener) {
freeaddrinfo(res);
return;
}
}
@@ -138,10 +138,9 @@ libevent's ``struct evconnlistener`` for this purpose::
We specify the ``acceptcb`` callback which is called when a new connection is
accepted::
static void acceptcb(struct evconnlistener *listener, int fd,
struct sockaddr *addr, int addrlen, void *arg)
{
app_context *app_ctx = (app_context*)arg;
static void acceptcb(struct evconnlistener *listener _U_, int fd,
struct sockaddr *addr, int addrlen, void *arg) {
app_context *app_ctx = (app_context *)arg;
http2_session_data *session_data;
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
@@ -158,26 +157,25 @@ The ``eventcb()`` callback is invoked by the libevent event loop when an event
(e.g., connection has been established, timeout, etc) happens on the
underlying network socket::
static void eventcb(struct bufferevent *bev, short events, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(events & BEV_EVENT_CONNECTED) {
static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (events & BEV_EVENT_CONNECTED) {
fprintf(stderr, "%s connected\n", session_data->client_addr);
initialize_nghttp2_session(session_data);
if(send_server_connection_header(session_data) != 0) {
if (send_server_connection_header(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
return;
}
if(events & BEV_EVENT_EOF) {
if (events & BEV_EVENT_EOF) {
fprintf(stderr, "%s EOF\n", session_data->client_addr);
} else if(events & BEV_EVENT_ERROR) {
} else if (events & BEV_EVENT_ERROR) {
fprintf(stderr, "%s network error\n", session_data->client_addr);
} else if(events & BEV_EVENT_TIMEOUT) {
} else if (events & BEV_EVENT_TIMEOUT) {
fprintf(stderr, "%s timeout\n", session_data->client_addr);
}
delete_http2_session_data(session_data);
@@ -195,63 +193,46 @@ communication.
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;
static void initialize_nghttp2_session(http2_session_data *session_data) {
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);
nghttp2_session_callbacks_set_on_frame_recv_callback
(callbacks, on_frame_recv_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback
(callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback
(callbacks, on_header_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback
(callbacks, on_begin_headers_callback);
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()``::
static int send_server_connection_header(http2_session_data *session_data)
{
static int send_server_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = {
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
};
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE,
iv, ARRLEN(iv));
if(rv != 0) {
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv));
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -272,23 +253,22 @@ have to process them here since libevent won't invoke callback functions for
this pending data. To process the received data, we call the
``session_recv()`` function::
static int session_recv(http2_session_data *session_data)
{
static int session_recv(http2_session_data *session_data) {
ssize_t readlen;
struct evbuffer *input = bufferevent_get_input(session_data->bev);
size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
if(readlen < 0) {
if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
return -1;
}
if(evbuffer_drain(input, readlen) != 0) {
if (evbuffer_drain(input, readlen) != 0) {
warnx("Fatal error: evbuffer_drain failed");
return -1;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
return -1;
}
return 0;
@@ -301,11 +281,10 @@ nghttp2 callbacks and also queue outgoing frames. Since there may be pending
outgoing frames, we call ``session_send()`` function to send off those
frames. The ``session_send()`` function is defined as follows::
static int session_send(http2_session_data *session_data)
{
static int session_send(http2_session_data *session_data) {
int rv;
rv = nghttp2_session_send(session_data->session);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -317,15 +296,13 @@ format and calls ``send_callback()`` of type
:type:`nghttp2_send_callback`. The ``send_callback()`` is defined as
follows::
static ssize_t send_callback(nghttp2_session *session,
const uint8_t *data, size_t length,
int flags, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
size_t length, int flags _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev;
/* Avoid excessive buffering in server side. */
if(evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
OUTPUT_WOULDBLOCK_THRESHOLD) {
if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
OUTPUT_WOULDBLOCK_THRESHOLD) {
return NGHTTP2_ERR_WOULDBLOCK;
}
bufferevent_write(bev, data, length);
@@ -350,10 +327,9 @@ calling send_callback.
The next bufferevent callback is ``readcb()``, which is invoked when
data is available to read in the bufferevent input buffer::
static void readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(session_recv(session_data) != 0) {
static void readcb(struct bufferevent *bev _U_, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (session_recv(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
@@ -365,18 +341,17 @@ data.
The third bufferevent callback is ``writecb()``, which is invoked when all
data in the bufferevent output buffer has been sent::
static void writecb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
static void writecb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
return;
}
if(nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0) {
if (nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0) {
delete_http2_session_data(session_data);
return;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
@@ -407,13 +382,12 @@ a header block in HEADERS or PUSH_PROMISE frame is started::
static int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
if(frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
if (frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
stream_data = create_http2_stream_data(session_data, frame->hd.stream_id);
@@ -436,26 +410,26 @@ emitted via ``on_header_callback`` function, which is called after
``on_begin_headers_callback()``::
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
void *user_data)
{
const nghttp2_frame *frame, const uint8_t *name,
size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags _U_,
void *user_data _U_) {
http2_stream_data *stream_data;
const char PATH[] = ":path";
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
break;
}
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if(!stream_data || stream_data->request_path) {
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (!stream_data || stream_data->request_path) {
break;
}
if(namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
size_t j;
for(j = 0; j < valuelen && value[j] != '?'; ++j);
for (j = 0; j < valuelen && value[j] != '?'; ++j)
;
stream_data->request_path = percent_decode(value, j);
}
break;
@@ -472,20 +446,19 @@ The ``on_frame_recv_callback()`` function is invoked when a frame is
fully received::
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
const nghttp2_frame *frame, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_DATA:
case NGHTTP2_HEADERS:
/* Check that the client request has finished */
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
/* For DATA and HEADERS frame, this callback may be called after
on_stream_close_callback. Check that stream still alive. */
if(!stream_data) {
if (!stream_data) {
return 0;
}
return on_request_recv(session, session_data, stream_data);
@@ -508,15 +481,14 @@ header.
Sending the content of the file is done in ``send_response()`` function::
static int send_response(nghttp2_session *session, int32_t stream_id,
nghttp2_nv *nva, size_t nvlen, int fd)
{
nghttp2_nv *nva, size_t nvlen, int fd) {
int rv;
nghttp2_data_provider data_prd;
data_prd.source.fd = fd;
data_prd.read_callback = file_read_callback;
rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -530,18 +502,19 @@ intended to be used as file descriptor. In this example server, we use
the file descriptor. We also set the ``file_read_callback()`` callback
function to read the contents of the file::
static ssize_t file_read_callback
(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length, uint32_t *data_flags,
nghttp2_data_source *source, void *user_data)
{
static ssize_t file_read_callback(nghttp2_session *session _U_,
int32_t stream_id _U_, uint8_t *buf,
size_t length, uint32_t *data_flags,
nghttp2_data_source *source,
void *user_data _U_) {
int fd = source->fd;
ssize_t r;
while((r = read(fd, buf, length)) == -1 && errno == EINTR);
if(r == -1) {
while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
;
if (r == -1) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if(r == 0) {
if (r == 0) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
}
return r;
@@ -559,16 +532,13 @@ remote peer.
The ``on_stream_close_callback()`` function is invoked when the stream
is about to close::
static int on_stream_close_callback(nghttp2_session *session,
int32_t stream_id,
nghttp2_error_code error_code,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
if(!stream_data) {
if (!stream_data) {
return 0;
}
remove_stream(session_data, stream_data);

5
examples/.gitignore vendored
View File

@@ -2,7 +2,8 @@ client
libevent-client
libevent-server
deflate
asio-sv
tiny-nghttpd
asio-sv
asio-sv2
asio-sv3
asio-cl
asio-cl2

View File

@@ -23,6 +23,7 @@
if ENABLE_EXAMPLES
AM_CFLAGS = $(WARNCFLAGS)
AM_CPPFLAGS = \
-Wall \
-I$(top_srcdir)/lib/includes \
@@ -32,12 +33,10 @@ AM_CPPFLAGS = \
@LIBEVENT_OPENSSL_CFLAGS@ \
@OPENSSL_CFLAGS@ \
@DEFS@
AM_LDFLAGS = \
LDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/libhttp-parser.la \
@LIBEVENT_OPENSSL_LIBS@ \
@OPENSSL_LIBS@
LDADD = \
$(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/libhttp-parser.la
noinst_PROGRAMS = client libevent-client libevent-server deflate
@@ -59,26 +58,37 @@ endif # ENABLE_TINY_NGHTTPD
if ENABLE_ASIO_LIB
noinst_PROGRAMS += asio-sv asio-sv2 asio-sv3
noinst_PROGRAMS += asio-sv asio-sv2 asio-cl asio-cl2
ASIOCPPFLAGS = ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
ASIOLDFLAGS = @JEMALLOC_LIBS@
ASIOLDADD = $(top_builddir)/src/libnghttp2_asio.la
# AM_CPPFLAGS must be placed first, so that header file (e.g.,
# nghttp2/nghttp2.h) in this package is used rather than installed
# one.
ASIOCPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
$(top_builddir)/third-party/libhttp-parser.la \
${BOOST_LDFLAGS} \
${BOOST_ASIO_LIB} \
${BOOST_THREAD_LIB} \
${BOOST_SYSTEM_LIB} \
@OPENSSL_LIBS@ \
@APPLDFLAGS@
asio_sv_SOURCES = asio-sv.cc
asio_sv_CPPFLAGS = ${ASIOCPPFLAGS}
asio_sv_LDFLAGS = ${ASIOLDFLAGS}
asio_sv_LDADD = ${ASIOLDADD}
asio_sv2_SOURCES = asio-sv2.cc
asio_sv2_CPPFLAGS = ${ASIOCPPFLAGS}
asio_sv2_LDFLAGS = ${ASIOLDFLAGS}
asio_sv2_LDADD = ${ASIOLDADD}
asio_sv3_SOURCES = asio-sv3.cc
asio_sv3_CPPFLAGS = ${ASIOCPPFLAGS}
asio_sv3_LDFLAGS = ${ASIOLDFLAGS}
asio_sv3_LDADD = ${ASIOLDADD}
asio_cl_SOURCES = asio-cl.cc
asio_cl_CPPFLAGS = ${ASIOCPPFLAGS}
asio_cl_LDADD = ${ASIOLDADD}
asio_cl2_SOURCES = asio-cl2.cc
asio_cl2_CPPFLAGS = ${ASIOCPPFLAGS}
asio_cl2_LDADD = ${ASIOLDADD}
endif # ENABLE_ASIO_LIB

96
examples/asio-cl.cc Normal file
View File

@@ -0,0 +1,96 @@
/*
* 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.
*/
#include <iostream>
#include <nghttp2/asio_http2_client.h>
using boost::asio::ip::tcp;
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::client;
int main(int argc, char *argv[]) {
try {
if (argc < 2) {
std::cerr << "Usage: asio-cl URI" << std::endl;
return 1;
}
boost::system::error_code ec;
boost::asio::io_service io_service;
std::string uri = argv[1];
std::string scheme, host, service;
if (host_service_from_uri(ec, scheme, host, service, uri)) {
std::cerr << "error: bad URI: " << ec.message() << std::endl;
return 1;
}
boost::asio::ssl::context tls_ctx(boost::asio::ssl::context::sslv23);
tls_ctx.set_default_verify_paths();
// disabled to make development easier...
// tls_ctx.set_verify_mode(boost::asio::ssl::verify_peer);
configure_tls_context(ec, tls_ctx);
auto sess = scheme == "https" ? session(io_service, tls_ctx, host, service)
: session(io_service, host, service);
sess.on_connect([&sess, &uri](tcp::resolver::iterator endpoint_it) {
boost::system::error_code ec;
auto req = sess.submit(ec, "GET", uri);
if (ec) {
std::cerr << "error: " << ec.message() << std::endl;
return;
}
req->on_response([&sess](const response &res) {
std::cerr << "HTTP/2 " << res.status_code() << std::endl;
for (auto &kv : res.header()) {
std::cerr << kv.first << ": " << kv.second.value << "\n";
}
std::cerr << std::endl;
res.on_data([&sess](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
});
req->on_close([&sess](uint32_t error_code) { sess.shutdown(); });
});
sess.on_error([](const boost::system::error_code &ec) {
std::cerr << "error: " << ec.message() << std::endl;
});
io_service.run();
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}

134
examples/asio-cl2.cc Normal file
View File

@@ -0,0 +1,134 @@
/*
* 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.
*/
#include <iostream>
#include <string>
#include <nghttp2/asio_http2_client.h>
using boost::asio::ip::tcp;
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::client;
void print_header(const header_map &h) {
for (auto &kv : h) {
std::cerr << kv.first << ": " << kv.second.value << "\n";
}
std::cerr << std::endl;
}
void print_header(const response &res) {
std::cerr << "HTTP/2 " << res.status_code() << "\n";
print_header(res.header());
}
void print_header(const request &req) {
auto &uri = req.uri();
std::cerr << req.method() << " " << uri.scheme << "://" << uri.host
<< uri.path;
if (!uri.raw_query.empty()) {
std::cerr << "?" << uri.raw_query;
}
std::cerr << " HTTP/2\n";
print_header(req.header());
}
int main(int argc, char *argv[]) {
try {
if (argc < 2) {
std::cerr << "Usage: asio-cl URI" << std::endl;
return 1;
}
boost::system::error_code ec;
boost::asio::io_service io_service;
std::string uri = argv[1];
std::string scheme, host, service;
if (host_service_from_uri(ec, scheme, host, service, uri)) {
std::cerr << "error: bad URI: " << ec.message() << std::endl;
return 1;
}
boost::asio::ssl::context tls_ctx(boost::asio::ssl::context::sslv23);
tls_ctx.set_default_verify_paths();
// disabled to make development easier...
// tls_ctx.set_verify_mode(boost::asio::ssl::verify_peer);
configure_tls_context(ec, tls_ctx);
auto sess = scheme == "https" ? session(io_service, tls_ctx, host, service)
: session(io_service, host, service);
sess.on_connect([&sess, &uri](tcp::resolver::iterator endpoint_it) {
std::cerr << "connected to " << (*endpoint_it).endpoint() << std::endl;
boost::system::error_code ec;
auto req = sess.submit(ec, "GET", uri, {{"cookie", {"foo=bar", true}}});
if (ec) {
std::cerr << "error: " << ec.message() << std::endl;
return;
}
req->on_response([&sess, req](const response &res) {
std::cerr << "response header was received" << std::endl;
print_header(res);
res.on_data([&sess](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
});
req->on_close([&sess](uint32_t error_code) {
std::cerr << "request done with error_code=" << error_code << std::endl;
});
req->on_push([](const request &push_req) {
std::cerr << "push request was received" << std::endl;
print_header(push_req);
push_req.on_response([](const response &res) {
std::cerr << "push response header was received" << std::endl;
res.on_data([](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
});
});
});
sess.on_error([](const boost::system::error_code &ec) {
std::cerr << "error: " << ec.message() << std::endl;
});
io_service.run();
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}

View File

@@ -37,41 +37,111 @@
#include <iostream>
#include <string>
#include <nghttp2/asio_http2.h>
#include <nghttp2/asio_http2_server.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char* argv[])
{
int main(int argc, char *argv[]) {
try {
// Check command line arguments.
if (argc < 3) {
std::cerr << "Usage: asio-sv <port> <threads> <private-key-file> "
<< "<cert-file>\n";
if (argc < 4) {
std::cerr
<< "Usage: asio-sv <address> <port> <threads> [<private-key-file> "
<< "<cert-file>]\n";
return 1;
}
uint16_t port = std::stoi(argv[1]);
std::size_t num_threads = std::stoi(argv[2]);
boost::system::error_code ec;
std::string addr = argv[1];
std::string port = argv[2];
std::size_t num_threads = std::stoi(argv[3]);
http2 server;
server.num_threads(num_threads);
if(argc >= 5) {
server.tls(argv[3], argv[4]);
}
server.handle("/", [](const request &req, const response &res) {
res.write_head(200, {{"foo", {"bar"}}});
res.end("hello, world\n");
});
server.handle("/secret/", [](const request &req, const response &res) {
res.write_head(200);
res.end("under construction!\n");
});
server.handle("/push", [](const request &req, const response &res) {
boost::system::error_code ec;
auto push = res.push(ec, "GET", "/push/1");
if (!ec) {
push->write_head(200);
push->end("server push FTW!\n");
}
server.listen
("*", port,
[](const std::shared_ptr<request>& req,
const std::shared_ptr<response>& res)
{
res->write_head(200, { header{ "foo", "bar" } });
res->end("hello, world");
});
} catch (std::exception& e) {
res.write_head(200);
res.end("you'll receive server push!\n");
});
server.handle("/delay", [](const request &req, const response &res) {
res.write_head(200);
auto timer = std::make_shared<boost::asio::deadline_timer>(
res.io_service(), boost::posix_time::seconds(3));
auto closed = std::make_shared<bool>();
res.on_close([timer, closed](uint32_t error_code) {
timer->cancel();
*closed = true;
});
timer->async_wait([&res, closed](const boost::system::error_code &ec) {
if (ec || *closed) {
return;
}
res.end("finally!\n");
});
});
server.handle("/trailer", [](const request &req, const response &res) {
// send trailer part.
res.write_head(200, {{"trailers", {"digest"}}});
std::string body = "nghttp2 FTW!\n";
auto left = std::make_shared<size_t>(body.size());
res.end([&res, body, left](uint8_t *dst, std::size_t len,
uint32_t *data_flags) {
auto n = std::min(len, *left);
std::copy_n(body.c_str() + (body.size() - *left), n, dst);
*left -= n;
if (*left == 0) {
*data_flags |=
NGHTTP2_DATA_FLAG_EOF | NGHTTP2_DATA_FLAG_NO_END_STREAM;
// RFC 3230 Instance Digests in HTTP. The digest value is
// SHA-256 message digest of body.
res.write_trailer(
{{"digest",
{"SHA-256=qqXqskW7F3ueBSvmZRCiSwl2ym4HRO0M/pvQCBlSDis="}}});
}
return n;
});
});
if (argc >= 6) {
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
tls.use_private_key_file(argv[4], boost::asio::ssl::context::pem);
tls.use_certificate_chain_file(argv[5]);
configure_tls_context_easy(ec, tls);
if (server.listen_and_serve(ec, tls, addr, port)) {
std::cerr << "error: " << ec.message() << std::endl;
}
} else {
if (server.listen_and_serve(ec, addr, port)) {
std::cerr << "error: " << ec.message() << std::endl;
}
}
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}

View File

@@ -35,75 +35,89 @@
//
#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>
#include <nghttp2/asio_http2.h>
#include <nghttp2/asio_http2_server.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char* argv[])
{
int main(int argc, char *argv[]) {
try {
// Check command line arguments.
if (argc < 4) {
std::cerr << "Usage: asio-sv2 <port> <threads> <doc-root> "
<< "<private-key-file> <cert-file>\n";
if (argc < 5) {
std::cerr << "Usage: asio-sv2 <address> <port> <threads> <doc-root> "
<< "[<private-key-file> <cert-file>]\n";
return 1;
}
uint16_t port = std::stoi(argv[1]);
std::size_t num_threads = std::stoi(argv[2]);
std::string docroot = argv[3];
boost::system::error_code ec;
std::string addr = argv[1];
std::string port = argv[2];
std::size_t num_threads = std::stoi(argv[3]);
std::string docroot = argv[4];
http2 server;
server.num_threads(num_threads);
if(argc >= 6) {
server.tls(argv[4], argv[5]);
server.handle("/", [&docroot](const request &req, const response &res) {
auto path = percent_decode(req.uri().path);
if (!check_path(path)) {
res.write_head(404);
res.end();
return;
}
if (path == "/") {
path = "/index.html";
}
path = docroot + path;
auto fd = open(path.c_str(), O_RDONLY);
if (fd == -1) {
res.write_head(404);
res.end();
return;
}
auto header = header_map();
struct stat stbuf;
if (stat(path.c_str(), &stbuf) == 0) {
header.emplace("content-length",
header_value{std::to_string(stbuf.st_size)});
header.emplace("last-modified",
header_value{http_date(stbuf.st_mtime)});
}
res.write_head(200, std::move(header));
res.end(file_generator_from_fd(fd));
});
if (argc >= 7) {
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
tls.use_private_key_file(argv[5], boost::asio::ssl::context::pem);
tls.use_certificate_chain_file(argv[6]);
configure_tls_context_easy(ec, tls);
if (server.listen_and_serve(ec, tls, addr, port)) {
std::cerr << "error: " << ec.message() << std::endl;
}
} else {
if (server.listen_and_serve(ec, addr, port)) {
std::cerr << "error: " << ec.message() << std::endl;
}
}
server.listen
("*", port,
[&docroot](const std::shared_ptr<request>& req,
const std::shared_ptr<response>& res)
{
auto path = percent_decode(req->path());
if(!check_path(path)) {
res->write_head(404);
res->end();
return;
}
if(path == "/") {
path = "/index.html";
}
path = docroot + path;
auto fd = open(path.c_str(), O_RDONLY);
if(fd == -1) {
res->write_head(404);
res->end();
return;
}
auto headers = std::vector<header>();
struct stat stbuf;
if(stat(path.c_str(), &stbuf) == 0) {
headers.push_back
(header{"content-length", std::to_string(stbuf.st_size)});
headers.push_back
(header{"last-modified", http_date(stbuf.st_mtim.tv_sec)});
}
res->write_head(200, std::move(headers));
res->end(file_reader_from_fd(fd));
});
} catch (std::exception& e) {
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}

View File

@@ -1,151 +0,0 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 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.
*/
// We wrote this code based on the original code which has the
// following license:
//
// main.cpp
// ~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <unistd.h>
#include <iostream>
#include <string>
#include <deque>
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char* argv[])
{
try {
// Check command line arguments.
if (argc < 4) {
std::cerr << "Usage: asio-sv3 <port> <threads> <tasks> "
<< " <private-key-file> <cert-file>\n";
return 1;
}
uint16_t port = std::stoi(argv[1]);
std::size_t num_threads = std::stoi(argv[2]);
std::size_t num_concurrent_tasks = std::stoi(argv[3]);
http2 server;
server.num_threads(num_threads);
if(argc >= 5) {
server.tls(argv[4], argv[5]);
}
server.num_concurrent_tasks(num_concurrent_tasks);
server.listen
("*", port,
[](const std::shared_ptr<request>& req,
const std::shared_ptr<response>& res)
{
res->write_head(200);
auto msgq = std::make_shared<std::deque<std::string>>();
res->end
([msgq](uint8_t *buf, std::size_t len) -> std::pair<ssize_t, bool>
{
if(msgq->empty()) {
// if msgq is empty, tells the library that don't call
// this callback until we call res->resume(). This is
// done by returing std::make_pair(0, false).
return std::make_pair(0, false);
}
auto msg = std::move(msgq->front());
msgq->pop_front();
if(msg.empty()) {
// The empty message signals the end of response in
// this simple protocol.
return std::make_pair(0, true);
}
auto nwrite = std::min(len, msg.size());
std::copy(std::begin(msg), std::begin(msg) + nwrite, buf);
if(msg.size() > nwrite) {
msgq->push_front(msg.substr(nwrite));
}
return std::make_pair(nwrite, false);
});
req->run_task
([res, msgq](channel& channel)
{
// executed in different thread from request callback
// was called.
// Using res and msgq is not safe inside this callback.
// But using them in callback passed to channel::post is
// safe.
// We just emit simple message "message N\n" in every 1
// second and 3 times in total.
for(std::size_t i = 0; i < 3; ++i) {
msgq->push_back("message " + std::to_string(i + 1) + "\n");
channel.post([res]()
{
// executed in same thread where
// request callback was called.
// Tells library we have new message.
res->resume();
});
sleep(1);
}
// Send empty message to signal the end of response
// body.
msgq->push_back("");
channel.post([res]()
{
// executed in same thread where request
// callback was called.
res->resume();
});
});
});
} catch (std::exception& e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}

View File

@@ -26,14 +26,28 @@
* This program is written to show how to use nghttp2 API in C and
* intentionally made simple.
*/
#include <stdint.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_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>
@@ -46,19 +60,19 @@
#include <openssl/err.h>
#include <openssl/conf.h>
enum {
IO_NONE,
WANT_READ,
WANT_WRITE
};
enum { IO_NONE, WANT_READ, WANT_WRITE };
#define MAKE_NV(NAME, VALUE) \
{(uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE}
#define MAKE_NV(NAME, VALUE) \
{ \
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
#define MAKE_NV_CS(NAME, VALUE) \
{(uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, strlen(VALUE), \
NGHTTP2_NV_FLAG_NONE}
#define MAKE_NV_CS(NAME, VALUE) \
{ \
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, strlen(VALUE), \
NGHTTP2_NV_FLAG_NONE \
}
struct Connection {
SSL *ssl;
@@ -99,10 +113,9 @@ struct URI {
* Returns copy of string |s| with the length |len|. The returned
* string is NULL-terminated.
*/
static char* strcopy(const char *s, size_t len)
{
static char *strcopy(const char *s, size_t len) {
char *dst;
dst = malloc(len+1);
dst = malloc(len + 1);
memcpy(dst, s, len);
dst[len] = '\0';
return dst;
@@ -111,8 +124,7 @@ static char* strcopy(const char *s, size_t len)
/*
* Prints error message |msg| and exit.
*/
static void die(const char *msg)
{
static void die(const char *msg) {
fprintf(stderr, "FATAL: %s\n", msg);
exit(EXIT_FAILURE);
}
@@ -121,8 +133,7 @@ static void die(const char *msg)
* Prints error containing the function name |func| and message |msg|
* and exit.
*/
static void dief(const char *func, const char *msg)
{
static void dief(const char *func, const char *msg) {
fprintf(stderr, "FATAL: %s: %s\n", func, msg);
exit(EXIT_FAILURE);
}
@@ -131,8 +142,7 @@ static void dief(const char *func, const char *msg)
* Prints error containing the function name |func| and error code
* |error_code| and exit.
*/
static void diec(const char *func, int error_code)
{
static void diec(const char *func, int error_code) {
fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,
nghttp2_strerror(error_code));
exit(EXIT_FAILURE);
@@ -144,21 +154,19 @@ static void diec(const char *func, int error_code)
* bytes actually written. See the documentation of
* nghttp2_send_callback for the details.
*/
static ssize_t send_callback(nghttp2_session *session,
const uint8_t *data, size_t length, int flags,
void *user_data)
{
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
size_t length, int flags _U_, void *user_data) {
struct Connection *connection;
int rv;
connection = (struct Connection*)user_data;
connection = (struct Connection *)user_data;
connection->want_io = IO_NONE;
ERR_clear_error();
rv = SSL_write(connection->ssl, data, (int)length);
if(rv < 0) {
if (rv <= 0) {
int err = SSL_get_error(connection->ssl, rv);
if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
connection->want_io = (err == SSL_ERROR_WANT_READ ?
WANT_READ : WANT_WRITE);
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
connection->want_io =
(err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);
rv = NGHTTP2_ERR_WOULDBLOCK;
} else {
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -173,41 +181,39 @@ static ssize_t send_callback(nghttp2_session *session,
* |length| bytes. Returns the number of bytes stored in |buf|. See
* the documentation of nghttp2_recv_callback for the details.
*/
static ssize_t recv_callback(nghttp2_session *session,
uint8_t *buf, size_t length, int flags,
void *user_data)
{
static ssize_t recv_callback(nghttp2_session *session _U_, uint8_t *buf,
size_t length, int flags _U_, void *user_data) {
struct Connection *connection;
int rv;
connection = (struct Connection*)user_data;
connection = (struct Connection *)user_data;
connection->want_io = IO_NONE;
ERR_clear_error();
rv = SSL_read(connection->ssl, buf, (int)length);
if(rv < 0) {
if (rv < 0) {
int err = SSL_get_error(connection->ssl, rv);
if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
connection->want_io = (err == SSL_ERROR_WANT_READ ?
WANT_READ : WANT_WRITE);
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
connection->want_io =
(err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);
rv = NGHTTP2_ERR_WOULDBLOCK;
} else {
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
}
} else if(rv == 0) {
} else if (rv == 0) {
rv = NGHTTP2_ERR_EOF;
}
return rv;
}
static int on_frame_send_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
const nghttp2_frame *frame,
void *user_data _U_) {
size_t i;
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
if (nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
const nghttp2_nv *nva = frame->headers.nva;
printf("[INFO] C ----------------------------> S (HEADERS)\n");
for(i = 0; i < frame->headers.nvlen; ++i) {
for (i = 0; i < frame->headers.nvlen; ++i) {
fwrite(nva[i].name, nva[i].namelen, 1, stdout);
printf(": ");
fwrite(nva[i].value, nva[i].valuelen, 1, stdout);
@@ -226,18 +232,18 @@ static int on_frame_send_callback(nghttp2_session *session,
}
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
const nghttp2_frame *frame,
void *user_data _U_) {
size_t i;
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
const nghttp2_nv *nva = frame->headers.nva;
struct Request *req;
req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if(req) {
if (req) {
printf("[INFO] C <---------------------------- S (HEADERS)\n");
for(i = 0; i < frame->headers.nvlen; ++i) {
for (i = 0; i < frame->headers.nvlen; ++i) {
fwrite(nva[i].name, nva[i].namelen, 1, stdout);
printf(": ");
fwrite(nva[i].value, nva[i].valuelen, 1, stdout);
@@ -262,18 +268,16 @@ static int on_frame_recv_callback(nghttp2_session *session,
* fetch 1 resource in this program, after reception of the response,
* we submit GOAWAY and close the session.
*/
static int on_stream_close_callback(nghttp2_session *session,
int32_t stream_id,
nghttp2_error_code error_code,
void *user_data)
{
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code _U_,
void *user_data _U_) {
struct Request *req;
req = nghttp2_session_get_stream_user_data(session, stream_id);
if(req) {
if (req) {
int rv;
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
if(rv != 0) {
if (rv != 0) {
diec("nghttp2_session_terminate_session", rv);
}
}
@@ -286,16 +290,16 @@ static int on_stream_close_callback(nghttp2_session *session,
* The implementation of nghttp2_on_data_chunk_recv_callback type. We
* use this function to print the received response body.
*/
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
static int on_data_chunk_recv_callback(nghttp2_session *session,
uint8_t flags _U_, int32_t stream_id,
const uint8_t *data, size_t len,
void *user_data)
{
void *user_data _U_) {
struct Request *req;
req = nghttp2_session_get_stream_user_data(session, stream_id);
if(req) {
if (req) {
printf("[INFO] C <---------------------------- S (DATA chunk)\n"
"%lu bytes\n", (unsigned long int)len);
"%lu bytes\n",
(unsigned long int)len);
fwrite(data, 1, len, stdout);
printf("\n");
}
@@ -308,23 +312,22 @@ static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
* always required. Since we use nghttp2_session_recv(), the
* recv_callback is also required.
*/
static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks)
{
static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback);
nghttp2_session_callbacks_set_on_frame_send_callback
(callbacks, on_frame_send_callback);
nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
on_frame_send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback
(callbacks, on_frame_recv_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback
(callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
(callbacks, on_data_chunk_recv_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
callbacks, on_data_chunk_recv_callback);
}
/*
@@ -332,16 +335,14 @@ static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks)
* HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2
* library supports, we terminate program.
*/
static int select_next_proto_cb(SSL* ssl,
unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen,
void *arg)
{
static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg _U_) {
int rv;
/* nghttp2_select_next_protocol() selects HTTP/2 protocol the
nghttp2 library supports. */
rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
if(rv <= 0) {
if (rv <= 0) {
die("Server did not advertise HTTP/2 protocol");
}
return SSL_TLSEXT_ERR_OK;
@@ -350,25 +351,23 @@ static int select_next_proto_cb(SSL* ssl,
/*
* Setup SSL/TLS context.
*/
static void init_ssl_ctx(SSL_CTX *ssl_ctx)
{
static void init_ssl_ctx(SSL_CTX *ssl_ctx) {
/* Disable SSLv2 and enable all workarounds for buggy servers */
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
/* Set NPN callback */
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
}
static void ssl_handshake(SSL *ssl, int fd)
{
static void ssl_handshake(SSL *ssl, int fd) {
int rv;
if(SSL_set_fd(ssl, fd) == 0) {
if (SSL_set_fd(ssl, fd) == 0) {
dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));
}
ERR_clear_error();
rv = SSL_connect(ssl);
if(rv <= 0) {
if (rv <= 0) {
dief("SSL_connect", ERR_error_string(ERR_get_error(), NULL));
}
}
@@ -377,8 +376,7 @@ static void ssl_handshake(SSL *ssl, int fd)
* Connects to the host |host| and port |port|. This function returns
* the file descriptor of the client socket.
*/
static int connect_to(const char *host, uint16_t port)
{
static int connect_to(const char *host, uint16_t port) {
struct addrinfo hints;
int fd = -1;
int rv;
@@ -389,17 +387,18 @@ static int connect_to(const char *host, uint16_t port)
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
rv = getaddrinfo(host, service, &hints, &res);
if(rv != 0) {
if (rv != 0) {
dief("getaddrinfo", gai_strerror(rv));
}
for(rp = res; rp; rp = rp->ai_next) {
for (rp = res; rp; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(fd == -1) {
if (fd == -1) {
continue;
}
while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
errno == EINTR);
if(rv == 0) {
while ((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
errno == EINTR)
;
if (rv == 0) {
break;
}
close(fd);
@@ -409,25 +408,25 @@ static int connect_to(const char *host, uint16_t port)
return fd;
}
static void make_non_block(int fd)
{
static void make_non_block(int fd) {
int flags, rv;
while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
if(flags == -1) {
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
;
if (flags == -1) {
dief("fcntl", strerror(errno));
}
while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
if(rv == -1) {
while ((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
;
if (rv == -1) {
dief("fcntl", strerror(errno));
}
}
static void set_tcp_nodelay(int fd)
{
static void set_tcp_nodelay(int fd) {
int val = 1;
int rv;
rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
if(rv == -1) {
if (rv == -1) {
dief("setsockopt", strerror(errno));
}
}
@@ -435,15 +434,14 @@ static void set_tcp_nodelay(int fd)
/*
* Update |pollfd| based on the state of |connection|.
*/
static void ctl_poll(struct pollfd *pollfd, struct Connection *connection)
{
static void ctl_poll(struct pollfd *pollfd, struct Connection *connection) {
pollfd->events = 0;
if(nghttp2_session_want_read(connection->session) ||
connection->want_io == WANT_READ) {
if (nghttp2_session_want_read(connection->session) ||
connection->want_io == WANT_READ) {
pollfd->events |= POLLIN;
}
if(nghttp2_session_want_write(connection->session) ||
connection->want_io == WANT_WRITE) {
if (nghttp2_session_want_write(connection->session) ||
connection->want_io == WANT_WRITE) {
pollfd->events |= POLLOUT;
}
}
@@ -453,24 +451,20 @@ static void ctl_poll(struct pollfd *pollfd, struct Connection *connection)
* function does not send packets; just append the request to the
* internal queue in |connection->session|.
*/
static void submit_request(struct Connection *connection, struct Request *req)
{
static void submit_request(struct Connection *connection, struct Request *req) {
int32_t stream_id;
const nghttp2_nv nva[] = {
/* Make sure that the last item is NULL */
MAKE_NV(":method", "GET"),
MAKE_NV_CS(":path", req->path),
MAKE_NV(":scheme", "https"),
MAKE_NV_CS(":authority", req->hostport),
MAKE_NV("accept", "*/*"),
MAKE_NV("user-agent", "nghttp2/"NGHTTP2_VERSION)
};
/* Make sure that the last item is NULL */
const nghttp2_nv nva[] = {MAKE_NV(":method", "GET"),
MAKE_NV_CS(":path", req->path),
MAKE_NV(":scheme", "https"),
MAKE_NV_CS(":authority", req->hostport),
MAKE_NV("accept", "*/*"),
MAKE_NV("user-agent", "nghttp2/" NGHTTP2_VERSION)};
stream_id = nghttp2_submit_request(connection->session, NULL,
nva, sizeof(nva)/sizeof(nva[0]),
NULL, req);
stream_id = nghttp2_submit_request(connection->session, NULL, nva,
sizeof(nva) / sizeof(nva[0]), NULL, req);
if(stream_id < 0) {
if (stream_id < 0) {
diec("nghttp2_submit_request", stream_id);
}
@@ -481,21 +475,19 @@ static void submit_request(struct Connection *connection, struct Request *req)
/*
* Performs the network I/O.
*/
static void exec_io(struct Connection *connection)
{
static void exec_io(struct Connection *connection) {
int rv;
rv = nghttp2_session_recv(connection->session);
if(rv != 0) {
if (rv != 0) {
diec("nghttp2_session_recv", rv);
}
rv = nghttp2_session_send(connection->session);
if(rv != 0) {
if (rv != 0) {
diec("nghttp2_session_send", rv);
}
}
static void request_init(struct Request *req, const struct URI *uri)
{
static void request_init(struct Request *req, const struct URI *uri) {
req->host = strcopy(uri->host, uri->hostlen);
req->port = uri->port;
req->path = strcopy(uri->path, uri->pathlen);
@@ -503,8 +495,7 @@ static void request_init(struct Request *req, const struct URI *uri)
req->stream_id = -1;
}
static void request_free(struct Request *req)
{
static void request_free(struct Request *req) {
free(req->host);
free(req->path);
free(req->hostport);
@@ -513,8 +504,7 @@ static void request_free(struct Request *req)
/*
* Fetches the resource denoted by |uri|.
*/
static void fetch_uri(const struct URI *uri)
{
static void fetch_uri(const struct URI *uri) {
nghttp2_session_callbacks *callbacks;
int fd;
SSL_CTX *ssl_ctx;
@@ -529,16 +519,16 @@ static void fetch_uri(const struct URI *uri)
/* Establish connection and setup SSL */
fd = connect_to(req.host, req.port);
if(fd == -1) {
if (fd == -1) {
die("Could not open file descriptor");
}
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if(ssl_ctx == NULL) {
if (ssl_ctx == NULL) {
dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
}
init_ssl_ctx(ssl_ctx);
ssl = SSL_new(ssl_ctx);
if(ssl == NULL) {
if (ssl == NULL) {
dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
}
/* To simplify the program, we perform SSL/TLS handshake in blocking
@@ -548,10 +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 */
SSL_write(ssl, NGHTTP2_CLIENT_CONNECTION_PREFACE,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
/* Here make file descriptor non-block */
make_non_block(fd);
set_tcp_nodelay(fd);
@@ -560,21 +546,22 @@ static void fetch_uri(const struct URI *uri)
rv = nghttp2_session_callbacks_new(&callbacks);
if(rv != 0) {
if (rv != 0) {
diec("nghttp2_session_callbacks_new", rv);
}
setup_nghttp2_callbacks(callbacks);
rv = nghttp2_session_client_new(&connection.session, callbacks,
&connection);
rv = nghttp2_session_client_new(&connection.session, callbacks, &connection);
nghttp2_session_callbacks_del(callbacks);
if(rv != 0) {
if (rv != 0) {
diec("nghttp2_session_client_new", rv);
}
nghttp2_submit_settings(connection.session, NGHTTP2_FLAG_NONE, NULL, 0);
/* Submit the HTTP request to the outbound queue. */
submit_request(&connection, &req);
@@ -582,16 +569,16 @@ static void fetch_uri(const struct URI *uri)
ctl_poll(pollfds, &connection);
/* Event loop */
while(nghttp2_session_want_read(connection.session) ||
nghttp2_session_want_write(connection.session)) {
while (nghttp2_session_want_read(connection.session) ||
nghttp2_session_want_write(connection.session)) {
int nfds = poll(pollfds, npollfds, -1);
if(nfds == -1) {
if (nfds == -1) {
dief("poll", strerror(errno));
}
if(pollfds[0].revents & (POLLIN | POLLOUT)) {
if (pollfds[0].revents & (POLLIN | POLLOUT)) {
exec_io(&connection);
}
if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
if ((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
die("Connection error");
}
ctl_poll(pollfds, &connection);
@@ -607,96 +594,94 @@ static void fetch_uri(const struct URI *uri)
request_free(&req);
}
static int parse_uri(struct URI *res, const char *uri)
{
static int parse_uri(struct URI *res, const char *uri) {
/* We only interested in https */
size_t len, i, offset;
int ipv6addr = 0;
memset(res, 0, sizeof(struct URI));
len = strlen(uri);
if(len < 9 || memcmp("https://", uri, 8) != 0) {
if (len < 9 || memcmp("https://", uri, 8) != 0) {
return -1;
}
offset = 8;
res->host = res->hostport = &uri[offset];
res->hostlen = 0;
if(uri[offset] == '[') {
if (uri[offset] == '[') {
/* IPv6 literal address */
++offset;
++res->host;
ipv6addr = 1;
for(i = offset; i < len; ++i) {
if(uri[i] == ']') {
res->hostlen = i-offset;
offset = i+1;
for (i = offset; i < len; ++i) {
if (uri[i] == ']') {
res->hostlen = i - offset;
offset = i + 1;
break;
}
}
} else {
const char delims[] = ":/?#";
for(i = offset; i < len; ++i) {
if(strchr(delims, uri[i]) != NULL) {
for (i = offset; i < len; ++i) {
if (strchr(delims, uri[i]) != NULL) {
break;
}
}
res->hostlen = i-offset;
res->hostlen = i - offset;
offset = i;
}
if(res->hostlen == 0) {
if (res->hostlen == 0) {
return -1;
}
/* Assuming https */
res->port = 443;
if(offset < len) {
if(uri[offset] == ':') {
if (offset < len) {
if (uri[offset] == ':') {
/* port */
const char delims[] = "/?#";
int port = 0;
++offset;
for(i = offset; i < len; ++i) {
if(strchr(delims, uri[i]) != NULL) {
for (i = offset; i < len; ++i) {
if (strchr(delims, uri[i]) != NULL) {
break;
}
if('0' <= uri[i] && uri[i] <= '9') {
if ('0' <= uri[i] && uri[i] <= '9') {
port *= 10;
port += uri[i]-'0';
if(port > 65535) {
port += uri[i] - '0';
if (port > 65535) {
return -1;
}
} else {
return -1;
}
}
if(port == 0) {
if (port == 0) {
return -1;
}
offset = i;
res->port = port;
}
}
res->hostportlen = uri+offset+ipv6addr-res->host;
for(i = offset; i < len; ++i) {
if(uri[i] == '#') {
res->hostportlen = uri + offset + ipv6addr - res->host;
for (i = offset; i < len; ++i) {
if (uri[i] == '#') {
break;
}
}
if(i-offset == 0) {
if (i - offset == 0) {
res->path = "/";
res->pathlen = 1;
} else {
res->path = &uri[offset];
res->pathlen = i-offset;
res->pathlen = i - offset;
}
return 0;
}
int main(int argc, char **argv)
{
int main(int argc, char **argv) {
struct URI uri;
struct sigaction act;
int rv;
if(argc < 2) {
if (argc < 2) {
die("Specify a https URI");
}
@@ -704,13 +689,13 @@ 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) {
if (rv != 0) {
die("parse_uri failed");
}
fetch_uri(&uri);

View File

@@ -22,48 +22,48 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* !HAVE_CONFIG_H */
#include <stdio.h>
#include <string.h>
#include <nghttp2/nghttp2.h>
#define MAKE_NV(K, V) \
{ (uint8_t*)K, (uint8_t*)V, sizeof(K) - 1, sizeof(V) - 1, \
NGHTTP2_NV_FLAG_NONE }
#define MAKE_NV(K, V) \
{ \
(uint8_t *) K, (uint8_t *)V, sizeof(K) - 1, sizeof(V) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
static void deflate(nghttp2_hd_deflater *deflater,
nghttp2_hd_inflater *inflater,
const nghttp2_nv * const nva, size_t nvlen);
nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva,
size_t nvlen);
static int inflate_header_block(nghttp2_hd_inflater *inflater,
uint8_t *in, size_t inlen, int final);
static int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
size_t inlen, int final);
int main(int argc, char **argv)
{
int main(int argc _U_, char **argv _U_) {
int rv;
nghttp2_hd_deflater *deflater;
nghttp2_hd_inflater *inflater;
/* Define 1st header set. This is looks like a HTTP request. */
nghttp2_nv nva1[] = {
MAKE_NV(":scheme", "https"),
MAKE_NV(":authority", "example.org"),
MAKE_NV(":path", "/"),
MAKE_NV("user-agent", "libnghttp2"),
MAKE_NV("accept-encoding", "gzip, deflate")
};
MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "example.org"),
MAKE_NV(":path", "/"), MAKE_NV("user-agent", "libnghttp2"),
MAKE_NV("accept-encoding", "gzip, deflate")};
/* Define 2nd header set */
nghttp2_nv nva2[] = {
MAKE_NV(":scheme", "https"),
MAKE_NV(":authority", "example.org"),
MAKE_NV(":path", "/stylesheet/style.css"),
MAKE_NV("user-agent", "libnghttp2"),
MAKE_NV("accept-encoding", "gzip, deflate"),
MAKE_NV("referer", "https://example.org")
};
nghttp2_nv nva2[] = {MAKE_NV(":scheme", "https"),
MAKE_NV(":authority", "example.org"),
MAKE_NV(":path", "/stylesheet/style.css"),
MAKE_NV("user-agent", "libnghttp2"),
MAKE_NV("accept-encoding", "gzip, deflate"),
MAKE_NV("referer", "https://example.org")};
rv = nghttp2_hd_deflate_new(&deflater, 4096);
if(rv != 0) {
if (rv != 0) {
fprintf(stderr, "nghttp2_hd_deflate_init failed with error: %s\n",
nghttp2_strerror(rv));
exit(EXIT_FAILURE);
@@ -71,7 +71,7 @@ int main(int argc, char **argv)
rv = nghttp2_hd_inflate_new(&inflater);
if(rv != 0) {
if (rv != 0) {
fprintf(stderr, "nghttp2_hd_inflate_init failed with error: %s\n",
nghttp2_strerror(rv));
exit(EXIT_FAILURE);
@@ -91,9 +91,8 @@ int main(int argc, char **argv)
}
static void deflate(nghttp2_hd_deflater *deflater,
nghttp2_hd_inflater *inflater,
const nghttp2_nv * const nva, size_t nvlen)
{
nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva,
size_t nvlen) {
ssize_t rv;
uint8_t *buf;
size_t buflen;
@@ -103,13 +102,13 @@ static void deflate(nghttp2_hd_deflater *deflater,
sum = 0;
for(i = 0; i < nvlen; ++i) {
for (i = 0; i < nvlen; ++i) {
sum += nva[i].namelen + nva[i].valuelen;
}
printf("Input (%zu byte(s)):\n\n", sum);
for(i = 0; i < nvlen; ++i) {
for (i = 0; i < nvlen; ++i) {
fwrite(nva[i].name, nva[i].namelen, 1, stdout);
printf(": ");
fwrite(nva[i].value, nva[i].valuelen, 1, stdout);
@@ -121,7 +120,7 @@ static void deflate(nghttp2_hd_deflater *deflater,
rv = nghttp2_hd_deflate_hd(deflater, buf, buflen, nva, nvlen);
if(rv < 0) {
if (rv < 0) {
fprintf(stderr, "nghttp2_hd_deflate_hd() failed with error: %s\n",
nghttp2_strerror((int)rv));
@@ -132,17 +131,17 @@ static void deflate(nghttp2_hd_deflater *deflater,
outlen = rv;
printf("\nDeflate (%zu byte(s), ratio %.02f):\n\n",
outlen, sum == 0 ? 0 : (double)outlen / sum);
printf("\nDeflate (%zu byte(s), ratio %.02f):\n\n", outlen,
sum == 0 ? 0 : (double)outlen / sum);
for(i = 0; i < outlen; ++i) {
if((i & 0x0fu) == 0) {
for (i = 0; i < outlen; ++i) {
if ((i & 0x0fu) == 0) {
printf("%08zX: ", i);
}
printf("%02X ", buf[i]);
if(((i + 1) & 0x0fu) == 0) {
if (((i + 1) & 0x0fu) == 0) {
printf("\n");
}
}
@@ -153,7 +152,7 @@ static void deflate(nghttp2_hd_deflater *deflater,
header data. */
rv = inflate_header_block(inflater, buf, outlen, 1);
if(rv != 0) {
if (rv != 0) {
free(buf);
exit(EXIT_FAILURE);
@@ -165,20 +164,18 @@ static void deflate(nghttp2_hd_deflater *deflater,
free(buf);
}
int inflate_header_block(nghttp2_hd_inflater *inflater,
uint8_t *in, size_t inlen, int final)
{
int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
size_t inlen, int final) {
ssize_t rv;
for(;;) {
for (;;) {
nghttp2_nv nv;
int inflate_flags = 0;
size_t proclen;
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags,
in, inlen, final);
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, in, inlen, final);
if(rv < 0) {
if (rv < 0) {
fprintf(stderr, "inflate failed with error code %zd", rv);
return -1;
}
@@ -188,20 +185,19 @@ int inflate_header_block(nghttp2_hd_inflater *inflater,
in += proclen;
inlen -= proclen;
if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
if (inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
fwrite(nv.name, nv.namelen, 1, stderr);
fprintf(stderr, ": ");
fwrite(nv.value, nv.valuelen, 1, stderr);
fprintf(stderr, "\n");
}
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
nghttp2_hd_inflate_end_headers(inflater);
break;
}
if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 &&
inlen == 0) {
if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
break;
}
}

View File

@@ -22,10 +22,20 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <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>
@@ -43,14 +53,14 @@
#include "http-parser/http_parser.h"
#define ARRLEN(x) (sizeof(x)/sizeof(x[0]))
#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 */
@@ -70,9 +80,8 @@ typedef struct {
http2_stream_data *stream_data;
} http2_session_data;
static http2_stream_data* create_http2_stream_data(const char *uri,
struct http_parser_url *u)
{
static http2_stream_data *create_http2_stream_data(const char *uri,
struct http_parser_url *u) {
/* MAX 5 digits (max 65535) + 1 ':' + 1 NULL (because of snprintf) */
size_t extra = 7;
http2_stream_data *stream_data = malloc(sizeof(http2_stream_data));
@@ -83,48 +92,51 @@ static http2_stream_data* create_http2_stream_data(const char *uri,
stream_data->authoritylen = u->field_data[UF_HOST].len;
stream_data->authority = malloc(stream_data->authoritylen + extra);
memcpy(stream_data->authority,
&uri[u->field_data[UF_HOST].off], u->field_data[UF_HOST].len);
if(u->field_set & (1 << UF_PORT)) {
memcpy(stream_data->authority, &uri[u->field_data[UF_HOST].off],
u->field_data[UF_HOST].len);
if (u->field_set & (1 << UF_PORT)) {
stream_data->authoritylen +=
snprintf(stream_data->authority + u->field_data[UF_HOST].len, extra,
":%u", u->port);
snprintf(stream_data->authority + u->field_data[UF_HOST].len, extra,
":%u", u->port);
}
stream_data->pathlen = 0;
if(u->field_set & (1 << UF_PATH)) {
/* 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;
}
if(u->field_set & (1 << UF_QUERY)) {
if (u->field_set & (1 << UF_QUERY)) {
/* +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);
}
if(u->field_set & (1 << UF_QUERY)) {
memcpy(stream_data->path + u->field_data[UF_PATH].len + 1,
&uri[u->field_data[UF_QUERY].off], u->field_data[UF_QUERY].len);
}
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 = NULL;
stream_data->path[0] = '/';
}
if (u->field_set & (1 << UF_QUERY)) {
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);
}
return stream_data;
}
static void delete_http2_stream_data(http2_stream_data *stream_data)
{
static void delete_http2_stream_data(http2_stream_data *stream_data) {
free(stream_data->path);
free(stream_data->authority);
free(stream_data);
}
/* Initializes |session_data| */
static http2_session_data *create_http2_session_data(struct event_base *evbase)
{
static http2_session_data *
create_http2_session_data(struct event_base *evbase) {
http2_session_data *session_data = malloc(sizeof(http2_session_data));
memset(session_data, 0, sizeof(http2_session_data));
@@ -132,11 +144,10 @@ static http2_session_data *create_http2_session_data(struct event_base *evbase)
return session_data;
}
static void delete_http2_session_data(http2_session_data *session_data)
{
static void delete_http2_session_data(http2_session_data *session_data) {
SSL *ssl = bufferevent_openssl_get_ssl(session_data->bev);
if(ssl) {
if (ssl) {
SSL_shutdown(ssl);
}
bufferevent_free(session_data->bev);
@@ -145,17 +156,15 @@ static void delete_http2_session_data(http2_session_data *session_data)
session_data->dnsbase = NULL;
nghttp2_session_del(session_data->session);
session_data->session = NULL;
if(session_data->stream_data) {
if (session_data->stream_data) {
delete_http2_stream_data(session_data->stream_data);
session_data->stream_data = NULL;
}
free(session_data);
}
static void print_header(FILE *f,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen)
{
static void print_header(FILE *f, const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen) {
fwrite(name, namelen, 1, f);
fprintf(f, ": ");
fwrite(value, valuelen, 1, f);
@@ -165,13 +174,10 @@ static void print_header(FILE *f,
/* Print HTTP headers to |f|. Please note that this function does not
take into account that header name and value are sequence of
octets, therefore they may contain non-printable characters. */
static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen)
{
static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen) {
size_t i;
for(i = 0; i < nvlen; ++i) {
print_header(f,
nva[i].name, nva[i].namelen,
nva[i].value, nva[i].valuelen);
for (i = 0; i < nvlen; ++i) {
print_header(f, nva[i].name, nva[i].namelen, nva[i].value, nva[i].valuelen);
}
fprintf(f, "\n");
}
@@ -179,11 +185,9 @@ static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen)
/* nghttp2_send_callback. Here we transmit the |data|, |length| bytes,
to the network. Because we are using libevent bufferevent, we just
write those bytes into bufferevent buffer. */
static ssize_t send_callback(nghttp2_session *session,
const uint8_t *data, size_t length,
int flags, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
size_t length, int flags _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev;
bufferevent_write(bev, data, length);
return length;
@@ -191,18 +195,16 @@ static ssize_t send_callback(nghttp2_session *session,
/* nghttp2_on_header_callback: Called when nghttp2 library emits
single header name/value pair. */
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
uint8_t flags,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
switch(frame->hd.type) {
static int on_header_callback(nghttp2_session *session _U_,
const nghttp2_frame *frame, const uint8_t *name,
size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags _U_,
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
/* Print response headers for the initiated request. */
print_header(stderr, name, namelen, value, valuelen);
break;
@@ -213,15 +215,14 @@ static int on_header_callback(nghttp2_session *session,
/* nghttp2_on_begin_headers_callback: Called when nghttp2 library gets
started to receive header block. */
static int on_begin_headers_callback(nghttp2_session *session,
static int on_begin_headers_callback(nghttp2_session *session _U_,
const nghttp2_frame *frame,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
switch(frame->hd.type) {
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
fprintf(stderr, "Response headers for stream ID=%d:\n",
frame->hd.stream_id);
}
@@ -232,14 +233,13 @@ static int on_begin_headers_callback(nghttp2_session *session,
/* nghttp2_on_frame_recv_callback: Called when nghttp2 library
received a complete frame from the remote peer. */
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
switch(frame->hd.type) {
static int on_frame_recv_callback(nghttp2_session *session _U_,
const nghttp2_frame *frame, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
fprintf(stderr, "All headers received\n");
}
break;
@@ -252,13 +252,12 @@ static int on_frame_recv_callback(nghttp2_session *session,
is meant to the stream we initiated, print the received data in
stdout, so that the user can redirect its output to the file
easily. */
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
uint8_t flags _U_, int32_t stream_id,
const uint8_t *data, size_t len,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
if(session_data->stream_data->stream_id == stream_id) {
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
if (session_data->stream_data->stream_id == stream_id) {
fwrite(data, len, 1, stdout);
}
return 0;
@@ -268,19 +267,16 @@ static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
closed. This example program only deals with 1 HTTP request (1
stream), if it is closed, we send GOAWAY and tear down the
session */
static int on_stream_close_callback(nghttp2_session *session,
int32_t stream_id,
nghttp2_error_code error_code,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
int rv;
if(session_data->stream_data->stream_id == stream_id) {
fprintf(stderr, "Stream %d closed with error_code=%d\n",
stream_id, error_code);
if (session_data->stream_data->stream_id == stream_id) {
fprintf(stderr, "Stream %d closed with error_code=%d\n", stream_id,
error_code);
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
if(rv != 0) {
if (rv != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
@@ -290,117 +286,111 @@ static int on_stream_close_callback(nghttp2_session *session,
/* NPN TLS extension client callback. We check that server advertised
the HTTP/2 protocol the nghttp2 library supports. If not, exit
the program. */
static int select_next_proto_cb(SSL* ssl,
unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen,
void *arg)
{
if(nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg _U_) {
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
}
return SSL_TLSEXT_ERR_OK;
}
/* Create SSL_CTX. */
static SSL_CTX* create_ssl_ctx(void)
{
static SSL_CTX *create_ssl_ctx(void) {
SSL_CTX *ssl_ctx;
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if(!ssl_ctx) {
if (!ssl_ctx) {
errx(1, "Could not create SSL/TLS context: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
return ssl_ctx;
}
/* Create SSL object */
static SSL* create_ssl(SSL_CTX *ssl_ctx)
{
static SSL *create_ssl(SSL_CTX *ssl_ctx) {
SSL *ssl;
ssl = SSL_new(ssl_ctx);
if(!ssl) {
if (!ssl) {
errx(1, "Could not create SSL/TLS session object: %s",
ERR_error_string(ERR_get_error(), NULL));
}
return ssl;
}
static void initialize_nghttp2_session(http2_session_data *session_data)
{
static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_session_callbacks *callbacks;
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback
(callbacks, on_frame_recv_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
(callbacks, on_data_chunk_recv_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
callbacks, on_data_chunk_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback
(callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback
(callbacks, on_header_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback
(callbacks, on_begin_headers_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
nghttp2_session_client_new(&session_data->session, callbacks, session_data);
nghttp2_session_callbacks_del(callbacks);
}
static void send_client_connection_header(http2_session_data *session_data)
{
static void send_client_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = {
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
};
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
bufferevent_write(session_data->bev,
NGHTTP2_CLIENT_CONNECTION_PREFACE,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE,
iv, ARRLEN(iv));
if(rv != 0) {
/* 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) {
errx(1, "Could not submit SETTINGS: %s", nghttp2_strerror(rv));
}
}
#define MAKE_NV(NAME, VALUE, VALUELEN) \
{ (uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, VALUELEN, \
NGHTTP2_NV_FLAG_NONE }
#define MAKE_NV(NAME, VALUE, VALUELEN) \
{ \
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, VALUELEN, \
NGHTTP2_NV_FLAG_NONE \
}
#define MAKE_NV2(NAME, VALUE) \
{ (uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE }
#define MAKE_NV2(NAME, VALUE) \
{ \
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
/* Send HTTP request to the remote peer */
static void submit_request(http2_session_data *session_data)
{
static void submit_request(http2_session_data *session_data) {
int32_t stream_id;
http2_stream_data *stream_data = session_data->stream_data;
const char *uri = stream_data->uri;
const struct http_parser_url *u = stream_data->u;
nghttp2_nv hdrs[] = {
MAKE_NV2(":method", "GET"),
MAKE_NV(":scheme",
&uri[u->field_data[UF_SCHEMA].off], u->field_data[UF_SCHEMA].len),
MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
MAKE_NV(":path", stream_data->path, stream_data->pathlen)
};
MAKE_NV2(":method", "GET"),
MAKE_NV(":scheme", &uri[u->field_data[UF_SCHEMA].off],
u->field_data[UF_SCHEMA].len),
MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
MAKE_NV(":path", stream_data->path, stream_data->pathlen)};
fprintf(stderr, "Request headers:\n");
print_headers(stderr, hdrs, ARRLEN(hdrs));
stream_id = nghttp2_submit_request(session_data->session, NULL,
hdrs, ARRLEN(hdrs), NULL, stream_data);
if(stream_id < 0) {
stream_id = nghttp2_submit_request(session_data->session, NULL, hdrs,
ARRLEN(hdrs), NULL, stream_data);
if (stream_id < 0) {
errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id));
}
@@ -409,12 +399,11 @@ static void submit_request(http2_session_data *session_data)
/* Serialize the frame and send (or buffer) the data to
bufferevent. */
static int session_send(http2_session_data *session_data)
{
static int session_send(http2_session_data *session_data) {
int rv;
rv = nghttp2_session_send(session_data->session);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -425,26 +414,25 @@ static int session_send(http2_session_data *session_data)
of bufferevent and feed them to nghttp2 library. This may invoke
nghttp2 callbacks. It may also queues the frame in nghttp2 session
context. To send them, we call session_send() in the end. */
static void readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
static void readcb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
ssize_t readlen;
struct evbuffer *input = bufferevent_get_input(bev);
size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
if(readlen < 0) {
if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
delete_http2_session_data(session_data);
return;
}
if(evbuffer_drain(input, readlen) != 0) {
if (evbuffer_drain(input, readlen) != 0) {
warnx("Fatal error: evbuffer_drain failed");
delete_http2_session_data(session_data);
return;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
@@ -454,12 +442,11 @@ static void readcb(struct bufferevent *bev, void *ptr)
receiving GOAWAY, we check the some conditions on the nghttp2
library and output buffer of bufferevent. If it indicates we have
no business to this session, tear down the connection. */
static void writecb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0 &&
evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
static void writecb(struct bufferevent *bev _U_, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0 &&
evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
delete_http2_session_data(session_data);
}
}
@@ -469,10 +456,9 @@ static void writecb(struct bufferevent *bev, void *ptr)
peer verification. After SSL/TLS handshake is over, initialize
nghttp2 library session, and send client connection header. Then
send HTTP request. */
static void eventcb(struct bufferevent *bev, short events, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(events & BEV_EVENT_CONNECTED) {
static void eventcb(struct bufferevent *bev, short events, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (events & BEV_EVENT_CONNECTED) {
int fd = bufferevent_getfd(bev);
int val = 1;
fprintf(stderr, "Connected\n");
@@ -480,41 +466,38 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr)
initialize_nghttp2_session(session_data);
send_client_connection_header(session_data);
submit_request(session_data);
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
}
return;
}
if(events & BEV_EVENT_EOF) {
if (events & BEV_EVENT_EOF) {
warnx("Disconnected from the remote host");
} else if(events & BEV_EVENT_ERROR) {
} else if (events & BEV_EVENT_ERROR) {
warnx("Network error");
} else if(events & BEV_EVENT_TIMEOUT) {
} else if (events & BEV_EVENT_TIMEOUT) {
warnx("Timeout");
}
delete_http2_session_data(session_data);
}
/* Start connecting to the remote peer |host:port| */
static void initiate_connection(struct event_base *evbase,
SSL_CTX *ssl_ctx,
static void initiate_connection(struct event_base *evbase, SSL_CTX *ssl_ctx,
const char *host, uint16_t port,
http2_session_data *session_data)
{
http2_session_data *session_data) {
int rv;
struct bufferevent *bev;
SSL *ssl;
ssl = create_ssl(ssl_ctx);
bev = bufferevent_openssl_socket_new(evbase, -1, ssl,
BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_DEFER_CALLBACKS |
BEV_OPT_CLOSE_ON_FREE);
bev = bufferevent_openssl_socket_new(
evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
AF_UNSPEC, host, port);
if(rv != 0) {
if (rv != 0) {
errx(1, "Could not connect to the remote host %s", host);
}
session_data->bev = bev;
@@ -522,8 +505,7 @@ static void initiate_connection(struct event_base *evbase,
/* Get resource denoted by the |uri|. The debug and error messages are
printed in stderr, while the response body is printed in stdout. */
static void run(const char *uri)
{
static void run(const char *uri) {
struct http_parser_url u;
char *host;
uint16_t port;
@@ -534,11 +516,11 @@ static void run(const char *uri)
/* Parse the |uri| and stores its components in |u| */
rv = http_parser_parse_url(uri, strlen(uri), 0, &u);
if(rv != 0) {
if (rv != 0) {
errx(1, "Could not parse URI %s", uri);
}
host = strndup(&uri[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len);
if(!(u.field_set & (1 << UF_PORT))) {
if (!(u.field_set & (1 << UF_PORT))) {
port = 443;
} else {
port = u.port;
@@ -561,11 +543,10 @@ static void run(const char *uri)
SSL_CTX_free(ssl_ctx);
}
int main(int argc, char **argv)
{
int main(int argc, char **argv) {
struct sigaction act;
if(argc < 2) {
if (argc < 2) {
fprintf(stderr, "Usage: libevent-client HTTPS_URI\n");
exit(EXIT_FAILURE);
}
@@ -574,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

@@ -22,15 +22,29 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */
#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>
@@ -47,11 +61,13 @@
#define OUTPUT_WOULDBLOCK_THRESHOLD (1 << 16)
#define ARRLEN(x) (sizeof(x)/sizeof(x[0]))
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
#define MAKE_NV(NAME, VALUE) \
{ (uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE }
#define MAKE_NV(NAME, VALUE) \
{ \
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
struct app_context;
typedef struct app_context app_context;
@@ -79,32 +95,40 @@ struct app_context {
static unsigned char next_proto_list[256];
static size_t next_proto_list_len;
static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
void *arg)
{
static int next_proto_cb(SSL *s _U_, const unsigned char **data,
unsigned int *len, void *arg _U_) {
*data = next_proto_list;
*len = (unsigned int)next_proto_list_len;
return SSL_TLSEXT_ERR_OK;
}
/* Create SSL_CTX. */
static SSL_CTX* create_ssl_ctx(const char *key_file, const char *cert_file)
{
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
SSL_CTX *ssl_ctx;
EC_KEY *ecdh;
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if(!ssl_ctx) {
if (!ssl_ctx) {
errx(1, "Could not create SSL/TLS context: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
if(SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file,
SSL_FILETYPE_PEM) != 1) {
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (!ecdh) {
errx(1, "EC_KEY_new_by_curv_name failed: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
EC_KEY_free(ecdh);
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
errx(1, "Could not read private key file %s", key_file);
}
if(SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
errx(1, "Could not read certificate file %s", cert_file);
}
@@ -118,11 +142,10 @@ static SSL_CTX* create_ssl_ctx(const char *key_file, const char *cert_file)
}
/* Create SSL object */
static SSL* create_ssl(SSL_CTX *ssl_ctx)
{
static SSL *create_ssl(SSL_CTX *ssl_ctx) {
SSL *ssl;
ssl = SSL_new(ssl_ctx);
if(!ssl) {
if (!ssl) {
errx(1, "Could not create SSL/TLS session object: %s",
ERR_error_string(ERR_get_error(), NULL));
}
@@ -130,28 +153,25 @@ static SSL* create_ssl(SSL_CTX *ssl_ctx)
}
static void add_stream(http2_session_data *session_data,
http2_stream_data *stream_data)
{
http2_stream_data *stream_data) {
stream_data->next = session_data->root.next;
session_data->root.next = stream_data;
stream_data->prev = &session_data->root;
if(stream_data->next) {
if (stream_data->next) {
stream_data->next->prev = stream_data;
}
}
static void remove_stream(http2_session_data *session_data,
http2_stream_data *stream_data)
{
static void remove_stream(http2_session_data *session_data _U_,
http2_stream_data *stream_data) {
stream_data->prev->next = stream_data->next;
if(stream_data->next) {
if (stream_data->next) {
stream_data->next->prev = stream_data->prev;
}
}
static http2_stream_data* create_http2_stream_data
(http2_session_data *session_data, int32_t stream_id)
{
static http2_stream_data *
create_http2_stream_data(http2_session_data *session_data, int32_t stream_id) {
http2_stream_data *stream_data;
stream_data = malloc(sizeof(http2_stream_data));
memset(stream_data, 0, sizeof(http2_stream_data));
@@ -162,20 +182,18 @@ static http2_stream_data* create_http2_stream_data
return stream_data;
}
static void delete_http2_stream_data(http2_stream_data *stream_data)
{
if(stream_data->fd != -1) {
static void delete_http2_stream_data(http2_stream_data *stream_data) {
if (stream_data->fd != -1) {
close(stream_data->fd);
}
free(stream_data->request_path);
free(stream_data);
}
static http2_session_data* create_http2_session_data(app_context *app_ctx,
static http2_session_data *create_http2_session_data(app_context *app_ctx,
int fd,
struct sockaddr *addr,
int addrlen)
{
int addrlen) {
int rv;
http2_session_data *session_data;
SSL *ssl;
@@ -187,12 +205,11 @@ static http2_session_data* create_http2_session_data(app_context *app_ctx,
memset(session_data, 0, sizeof(http2_session_data));
session_data->app_ctx = app_ctx;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
session_data->bev = bufferevent_openssl_socket_new
(app_ctx->evbase, fd, ssl,
BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
session_data->bev = bufferevent_openssl_socket_new(
app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
rv = getnameinfo(addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
if(rv != 0) {
if (rv != 0) {
session_data->client_addr = strdup("(unknown)");
} else {
session_data->client_addr = strdup(host);
@@ -201,17 +218,16 @@ static http2_session_data* create_http2_session_data(app_context *app_ctx,
return session_data;
}
static void delete_http2_session_data(http2_session_data *session_data)
{
static void delete_http2_session_data(http2_session_data *session_data) {
http2_stream_data *stream_data;
SSL *ssl = bufferevent_openssl_get_ssl(session_data->bev);
fprintf(stderr, "%s disconnected\n", session_data->client_addr);
if(ssl) {
if (ssl) {
SSL_shutdown(ssl);
}
bufferevent_free(session_data->bev);
nghttp2_session_del(session_data->session);
for(stream_data = session_data->root.next; stream_data;) {
for (stream_data = session_data->root.next; stream_data;) {
http2_stream_data *next = stream_data->next;
delete_http2_stream_data(stream_data);
stream_data = next;
@@ -222,11 +238,10 @@ static void delete_http2_session_data(http2_session_data *session_data)
/* Serialize the frame and send (or buffer) the data to
bufferevent. */
static int session_send(http2_session_data *session_data)
{
static int session_send(http2_session_data *session_data) {
int rv;
rv = nghttp2_session_send(session_data->session);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -237,37 +252,34 @@ static int session_send(http2_session_data *session_data)
function. Invocation of nghttp2_session_mem_recv() may make
additional pending frames, so call session_send() at the end of the
function. */
static int session_recv(http2_session_data *session_data)
{
static int session_recv(http2_session_data *session_data) {
ssize_t readlen;
struct evbuffer *input = bufferevent_get_input(session_data->bev);
size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
if(readlen < 0) {
if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
return -1;
}
if(evbuffer_drain(input, readlen) != 0) {
if (evbuffer_drain(input, readlen) != 0) {
warnx("Fatal error: evbuffer_drain failed");
return -1;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
return -1;
}
return 0;
}
static ssize_t send_callback(nghttp2_session *session,
const uint8_t *data, size_t length,
int flags, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
size_t length, int flags _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev;
/* Avoid excessive buffering in server side. */
if(evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
OUTPUT_WOULDBLOCK_THRESHOLD) {
if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
OUTPUT_WOULDBLOCK_THRESHOLD) {
return NGHTTP2_ERR_WOULDBLOCK;
}
bufferevent_write(bev, data, length);
@@ -275,26 +287,24 @@ static ssize_t send_callback(nghttp2_session *session,
}
/* Returns nonzero if the string |s| ends with the substring |sub| */
static int ends_with(const char *s, const char *sub)
{
static int ends_with(const char *s, const char *sub) {
size_t slen = strlen(s);
size_t sublen = strlen(sub);
if(slen < sublen) {
if (slen < sublen) {
return 0;
}
return memcmp(s + slen - sublen, sub, sublen) == 0;
}
/* Returns int value of hex string character |c| */
static uint8_t hex_to_uint(uint8_t c)
{
if('0' <= c && c <= '9') {
static uint8_t hex_to_uint(uint8_t c) {
if ('0' <= c && c <= '9') {
return c - '0';
}
if('A' <= c && c <= 'F') {
if ('A' <= c && c <= 'F') {
return c - 'A' + 10;
}
if('a' <= c && c <= 'f') {
if ('a' <= c && c <= 'f') {
return c - 'a' + 10;
}
return 0;
@@ -304,16 +314,15 @@ static uint8_t hex_to_uint(uint8_t c)
and returns the decoded byte string in allocated buffer. The return
value is NULL terminated. The caller must free the returned
string. */
static char* percent_decode(const uint8_t *value, size_t valuelen)
{
static char *percent_decode(const uint8_t *value, size_t valuelen) {
char *res;
res = malloc(valuelen + 1);
if(valuelen > 3) {
if (valuelen > 3) {
size_t i, j;
for(i = 0, j = 0; i < valuelen - 2;) {
if(value[i] != '%' ||
!isxdigit(value[i + 1]) || !isxdigit(value[i + 2])) {
for (i = 0, j = 0; i < valuelen - 2;) {
if (value[i] != '%' || !isxdigit(value[i + 1]) ||
!isxdigit(value[i + 2])) {
res[j++] = value[i++];
continue;
}
@@ -329,33 +338,33 @@ static char* percent_decode(const uint8_t *value, size_t valuelen)
return res;
}
static ssize_t file_read_callback
(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length, uint32_t *data_flags,
nghttp2_data_source *source, void *user_data)
{
static ssize_t file_read_callback(nghttp2_session *session _U_,
int32_t stream_id _U_, uint8_t *buf,
size_t length, uint32_t *data_flags,
nghttp2_data_source *source,
void *user_data _U_) {
int fd = source->fd;
ssize_t r;
while((r = read(fd, buf, length)) == -1 && errno == EINTR);
if(r == -1) {
while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
;
if (r == -1) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if(r == 0) {
if (r == 0) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
}
return r;
}
static int send_response(nghttp2_session *session, int32_t stream_id,
nghttp2_nv *nva, size_t nvlen, int fd)
{
nghttp2_nv *nva, size_t nvlen, int fd) {
int rv;
nghttp2_data_provider data_prd;
data_prd.source.fd = fd;
data_prd.read_callback = file_read_callback;
rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -363,25 +372,22 @@ static int send_response(nghttp2_session *session, int32_t stream_id,
}
const char ERROR_HTML[] = "<html><head><title>404</title></head>"
"<body><h1>404 Not Found</h1></body></html>";
"<body><h1>404 Not Found</h1></body></html>";
static int error_reply(nghttp2_session *session,
http2_stream_data *stream_data)
{
http2_stream_data *stream_data) {
int rv;
ssize_t writelen;
int pipefd[2];
nghttp2_nv hdrs[] = {
MAKE_NV(":status", "404")
};
nghttp2_nv hdrs[] = {MAKE_NV(":status", "404")};
rv = pipe(pipefd);
if(rv != 0) {
if (rv != 0) {
warn("Could not create pipe");
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
stream_data->stream_id,
NGHTTP2_INTERNAL_ERROR);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -391,15 +397,15 @@ static int error_reply(nghttp2_session *session,
writelen = write(pipefd[1], ERROR_HTML, sizeof(ERROR_HTML) - 1);
close(pipefd[1]);
if(writelen != sizeof(ERROR_HTML) - 1) {
if (writelen != sizeof(ERROR_HTML) - 1) {
close(pipefd[0]);
return -1;
}
stream_data->fd = pipefd[0];
if(send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs),
pipefd[0]) != 0) {
if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs),
pipefd[0]) != 0) {
close(pipefd[0]);
return -1;
}
@@ -409,27 +415,26 @@ static int error_reply(nghttp2_session *session,
/* nghttp2_on_header_callback: Called when nghttp2 library emits
single header name/value pair. */
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
uint8_t flags,
void *user_data)
{
const nghttp2_frame *frame, const uint8_t *name,
size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags _U_,
void *user_data _U_) {
http2_stream_data *stream_data;
const char PATH[] = ":path";
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
break;
}
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if(!stream_data || stream_data->request_path) {
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (!stream_data || stream_data->request_path) {
break;
}
if(namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
size_t j;
for(j = 0; j < valuelen && value[j] != '?'; ++j);
for (j = 0; j < valuelen && value[j] != '?'; ++j)
;
stream_data->request_path = percent_decode(value, j);
}
break;
@@ -439,13 +444,12 @@ static int on_header_callback(nghttp2_session *session,
static int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
if(frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
if (frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
stream_data = create_http2_stream_data(session_data, frame->hd.stream_id);
@@ -456,52 +460,47 @@ static int on_begin_headers_callback(nghttp2_session *session,
/* Minimum check for directory traversal. Returns nonzero if it is
safe. */
static int check_path(const char *path)
{
static int check_path(const char *path) {
/* We don't like '\' in url. */
return path[0] && path[0] == '/' &&
strchr(path, '\\') == NULL &&
strstr(path, "/../") == NULL &&
strstr(path, "/./") == NULL &&
!ends_with(path, "/..") && !ends_with(path, "/.");
return path[0] && path[0] == '/' && strchr(path, '\\') == NULL &&
strstr(path, "/../") == NULL && strstr(path, "/./") == NULL &&
!ends_with(path, "/..") && !ends_with(path, "/.");
}
static int on_request_recv(nghttp2_session *session,
http2_session_data *session_data,
http2_stream_data *stream_data)
{
http2_stream_data *stream_data) {
int fd;
nghttp2_nv hdrs[] = {
MAKE_NV(":status", "200")
};
nghttp2_nv hdrs[] = {MAKE_NV(":status", "200")};
char *rel_path;
if(!stream_data->request_path) {
if(error_reply(session, stream_data) != 0) {
if (!stream_data->request_path) {
if (error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
fprintf(stderr, "%s GET %s\n", session_data->client_addr,
stream_data->request_path);
if(!check_path(stream_data->request_path)) {
if(error_reply(session, stream_data) != 0) {
if (!check_path(stream_data->request_path)) {
if (error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
for(rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path);
for (rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path)
;
fd = open(rel_path, O_RDONLY);
if(fd == -1) {
if(error_reply(session, stream_data) != 0) {
if (fd == -1) {
if (error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
stream_data->fd = fd;
if(send_response(session, stream_data->stream_id, hdrs,
ARRLEN(hdrs), fd) != 0) {
if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs), fd) !=
0) {
close(fd);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
@@ -509,20 +508,19 @@ static int on_request_recv(nghttp2_session *session,
}
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
const nghttp2_frame *frame, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_DATA:
case NGHTTP2_HEADERS:
/* Check that the client request has finished */
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
/* For DATA and HEADERS frame, this callback may be called after
on_stream_close_callback. Check that stream still alive. */
if(!stream_data) {
if (!stream_data) {
return 0;
}
return on_request_recv(session, session_data, stream_data);
@@ -534,16 +532,13 @@ static int on_frame_recv_callback(nghttp2_session *session,
return 0;
}
static int on_stream_close_callback(nghttp2_session *session,
int32_t stream_id,
nghttp2_error_code error_code,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
if(!stream_data) {
if (!stream_data) {
return 0;
}
remove_stream(session_data, stream_data);
@@ -551,54 +546,40 @@ static int on_stream_close_callback(nghttp2_session *session,
return 0;
}
static void initialize_nghttp2_session(http2_session_data *session_data)
{
nghttp2_option *option;
static void initialize_nghttp2_session(http2_session_data *session_data) {
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);
nghttp2_session_callbacks_set_on_frame_recv_callback
(callbacks, on_frame_recv_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback
(callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback
(callbacks, on_header_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback
(callbacks, on_begin_headers_callback);
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
magic octets and SETTINGS frame */
static int send_server_connection_header(http2_session_data *session_data)
{
static int send_server_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = {
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
};
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE,
iv, ARRLEN(iv));
if(rv != 0) {
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv));
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -607,10 +588,9 @@ static int send_server_connection_header(http2_session_data *session_data)
/* readcb for bufferevent after client connection header was
checked. */
static void readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(session_recv(session_data) != 0) {
static void readcb(struct bufferevent *bev _U_, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (session_recv(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
@@ -624,54 +604,51 @@ static void readcb(struct bufferevent *bev, void *ptr)
process pending data in the output buffer. This is necessary
because we have a threshold on the buffer size to avoid too much
buffering. See send_callback(). */
static void writecb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
static void writecb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
return;
}
if(nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0) {
if (nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0) {
delete_http2_session_data(session_data);
return;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
}
/* eventcb for bufferevent */
static void eventcb(struct bufferevent *bev, short events, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(events & BEV_EVENT_CONNECTED) {
static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (events & BEV_EVENT_CONNECTED) {
fprintf(stderr, "%s connected\n", session_data->client_addr);
initialize_nghttp2_session(session_data);
if(send_server_connection_header(session_data) != 0) {
if (send_server_connection_header(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
return;
}
if(events & BEV_EVENT_EOF) {
if (events & BEV_EVENT_EOF) {
fprintf(stderr, "%s EOF\n", session_data->client_addr);
} else if(events & BEV_EVENT_ERROR) {
} else if (events & BEV_EVENT_ERROR) {
fprintf(stderr, "%s network error\n", session_data->client_addr);
} else if(events & BEV_EVENT_TIMEOUT) {
} else if (events & BEV_EVENT_TIMEOUT) {
fprintf(stderr, "%s timeout\n", session_data->client_addr);
}
delete_http2_session_data(session_data);
}
/* callback for evconnlistener */
static void acceptcb(struct evconnlistener *listener, int fd,
struct sockaddr *addr, int addrlen, void *arg)
{
app_context *app_ctx = (app_context*)arg;
static void acceptcb(struct evconnlistener *listener _U_, int fd,
struct sockaddr *addr, int addrlen, void *arg) {
app_context *app_ctx = (app_context *)arg;
http2_session_data *session_data;
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
@@ -680,8 +657,7 @@ static void acceptcb(struct evconnlistener *listener, int fd,
}
static void start_listen(struct event_base *evbase, const char *service,
app_context *app_ctx)
{
app_context *app_ctx) {
int rv;
struct addrinfo hints;
struct addrinfo *res, *rp;
@@ -695,16 +671,15 @@ static void start_listen(struct event_base *evbase, const char *service,
#endif /* AI_ADDRCONFIG */
rv = getaddrinfo(NULL, service, &hints, &res);
if(rv != 0) {
if (rv != 0) {
errx(1, NULL);
}
for(rp = res; rp; rp = rp->ai_next) {
for (rp = res; rp; rp = rp->ai_next) {
struct evconnlistener *listener;
listener = evconnlistener_new_bind(evbase, acceptcb, app_ctx,
LEV_OPT_CLOSE_ON_FREE |
LEV_OPT_REUSEABLE, 16,
rp->ai_addr, rp->ai_addrlen);
if(listener) {
listener = evconnlistener_new_bind(
evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
16, rp->ai_addr, rp->ai_addrlen);
if (listener) {
freeaddrinfo(res);
return;
@@ -714,16 +689,14 @@ static void start_listen(struct event_base *evbase, const char *service,
}
static void initialize_app_context(app_context *app_ctx, SSL_CTX *ssl_ctx,
struct event_base *evbase)
{
struct event_base *evbase) {
memset(app_ctx, 0, sizeof(app_context));
app_ctx->ssl_ctx = ssl_ctx;
app_ctx->evbase = evbase;
}
static void run(const char *service,
const char *key_file, const char *cert_file)
{
static void run(const char *service, const char *key_file,
const char *cert_file) {
SSL_CTX *ssl_ctx;
app_context app_ctx;
struct event_base *evbase;
@@ -739,11 +712,10 @@ static void run(const char *service,
SSL_CTX_free(ssl_ctx);
}
int main(int argc, char **argv)
{
int main(int argc, char **argv) {
struct sigaction act;
if(argc < 4) {
if (argc < 4) {
fprintf(stderr, "Usage: libevent-server PORT KEY_FILE CERT_FILE\n");
exit(EXIT_FAILURE);
}
@@ -752,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;

File diff suppressed because it is too large Load Diff

40
genheaderfunc.py Executable file
View File

@@ -0,0 +1,40 @@
#!/usr/bin/env python
from gentokenlookup import gentokenlookup
HEADERS = [
':authority',
':method',
':path',
':scheme',
':status',
':host', # for spdy
'expect',
'host',
'if-modified-since',
"te",
"cookie",
"http2-settings",
"server",
"via",
"x-forwarded-for",
"x-forwarded-proto",
"alt-svc",
"content-length",
"location",
"trailer",
"link",
"accept-encoding",
"accept-language",
"cache-control",
"user-agent",
# disallowed h1 headers
'connection',
'keep-alive',
'proxy-connection',
'transfer-encoding',
'upgrade'
]
if __name__ == '__main__':
gentokenlookup(HEADERS, 'HD')

140
genlibtokenlookup.py Executable file
View File

@@ -0,0 +1,140 @@
#!/usr/bin/env python
HEADERS = [
(':authority', 0),
(':method', 1),
(':method', 2),
(':path', 3),
(':path', 4),
(':scheme', 5),
(':scheme', 6),
(':status', 7),
(':status', 8),
(':status', 9),
(':status', 10),
(':status', 11),
(':status', 12),
(':status', 13),
('accept-charset', 14),
('accept-encoding', 15),
('accept-language', 16),
('accept-ranges', 17),
('accept', 18),
('access-control-allow-origin', 19),
('age', 20),
('allow', 21),
('authorization', 22),
('cache-control', 23),
('content-disposition', 24),
('content-encoding', 25),
('content-language', 26),
('content-length', 27),
('content-location', 28),
('content-range', 29),
('content-type', 30),
('cookie', 31),
('date', 32),
('etag', 33),
('expect', 34),
('expires', 35),
('from', 36),
('host', 37),
('if-match', 38),
('if-modified-since', 39),
('if-none-match', 40),
('if-range', 41),
('if-unmodified-since', 42),
('last-modified', 43),
('link', 44),
('location', 45),
('max-forwards', 46),
('proxy-authenticate', 47),
('proxy-authorization', 48),
('range', 49),
('referer', 50),
('refresh', 51),
('retry-after', 52),
('server', 53),
('set-cookie', 54),
('strict-transport-security', 55),
('transfer-encoding', 56),
('user-agent', 57),
('vary', 58),
('via', 59),
('www-authenticate', 60),
('te', None),
('connection', None),
('keep-alive',None),
('proxy-connection', None),
('upgrade', None),
]
def to_enum_hd(k):
res = 'NGHTTP2_TOKEN_'
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():
name = ''
print 'typedef enum {'
for k, token in HEADERS:
if token is None:
print ' {},'.format(to_enum_hd(k))
else:
if name != k:
name = k
print ' {} = {},'.format(to_enum_hd(k), token)
print '} nghttp2_token;'
def gen_index_header():
print '''\
static inline 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 (lstreq("{}", 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()

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)

484
git-clang-format Executable file
View File

@@ -0,0 +1,484 @@
#!/usr/bin/env python
#
#===- git-clang-format - ClangFormat Git Integration ---------*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
r"""
clang-format git integration
============================
This file provides a clang-format integration for git. Put it somewhere in your
path and ensure that it is executable. Then, "git clang-format" will invoke
clang-format on the changes in current files or a specific commit.
For further details, run:
git clang-format -h
Requires Python 2.7
"""
import argparse
import collections
import contextlib
import errno
import os
import re
import subprocess
import sys
usage = 'git clang-format [OPTIONS] [<commit>] [--] [<file>...]'
desc = '''
Run clang-format on all lines that differ between the working directory
and <commit>, which defaults to HEAD. Changes are only applied to the working
directory.
The following git-config settings set the default of the corresponding option:
clangFormat.binary
clangFormat.commit
clangFormat.extension
clangFormat.style
'''
# Name of the temporary index file in which save the output of clang-format.
# This file is created within the .git directory.
temp_index_basename = 'clang-format-index'
Range = collections.namedtuple('Range', 'start, count')
def main():
config = load_git_config()
# In order to keep '--' yet allow options after positionals, we need to
# check for '--' ourselves. (Setting nargs='*' throws away the '--', while
# nargs=argparse.REMAINDER disallows options after positionals.)
argv = sys.argv[1:]
try:
idx = argv.index('--')
except ValueError:
dash_dash = []
else:
dash_dash = argv[idx:]
argv = argv[:idx]
default_extensions = ','.join([
# From clang/lib/Frontend/FrontendOptions.cpp, all lower case
'c', 'h', # C
'm', # ObjC
'mm', # ObjC++
'cc', 'cp', 'cpp', 'c++', 'cxx', 'hpp', # C++
# Other languages that clang-format supports
'proto', 'protodevel', # Protocol Buffers
'js', # JavaScript
])
p = argparse.ArgumentParser(
usage=usage, formatter_class=argparse.RawDescriptionHelpFormatter,
description=desc)
p.add_argument('--binary',
default=config.get('clangformat.binary', 'clang-format'),
help='path to clang-format'),
p.add_argument('--commit',
default=config.get('clangformat.commit', 'HEAD'),
help='default commit to use if none is specified'),
p.add_argument('--diff', action='store_true',
help='print a diff instead of applying the changes')
p.add_argument('--extensions',
default=config.get('clangformat.extensions',
default_extensions),
help=('comma-separated list of file extensions to format, '
'excluding the period and case-insensitive')),
p.add_argument('-f', '--force', action='store_true',
help='allow changes to unstaged files')
p.add_argument('-p', '--patch', action='store_true',
help='select hunks interactively')
p.add_argument('-q', '--quiet', action='count', default=0,
help='print less information')
p.add_argument('--style',
default=config.get('clangformat.style', None),
help='passed to clang-format'),
p.add_argument('-v', '--verbose', action='count', default=0,
help='print extra information')
# We gather all the remaining positional arguments into 'args' since we need
# to use some heuristics to determine whether or not <commit> was present.
# However, to print pretty messages, we make use of metavar and help.
p.add_argument('args', nargs='*', metavar='<commit>',
help='revision from which to compute the diff')
p.add_argument('ignored', nargs='*', metavar='<file>...',
help='if specified, only consider differences in these files')
opts = p.parse_args(argv)
opts.verbose -= opts.quiet
del opts.quiet
commit, files = interpret_args(opts.args, dash_dash, opts.commit)
changed_lines = compute_diff_and_extract_lines(commit, files)
if opts.verbose >= 1:
ignored_files = set(changed_lines)
filter_by_extension(changed_lines, opts.extensions.lower().split(','))
if opts.verbose >= 1:
ignored_files.difference_update(changed_lines)
if ignored_files:
print 'Ignoring changes in the following files (wrong extension):'
for filename in ignored_files:
print ' ', filename
if changed_lines:
print 'Running clang-format on the following files:'
for filename in changed_lines:
print ' ', filename
if not changed_lines:
print 'no modified files to format'
return
# The computed diff outputs absolute paths, so we must cd before accessing
# those files.
cd_to_toplevel()
old_tree = create_tree_from_workdir(changed_lines)
new_tree = run_clang_format_and_save_to_tree(changed_lines,
binary=opts.binary,
style=opts.style)
if opts.verbose >= 1:
print 'old tree:', old_tree
print 'new tree:', new_tree
if old_tree == new_tree:
if opts.verbose >= 0:
print 'clang-format did not modify any files'
elif opts.diff:
print_diff(old_tree, new_tree)
else:
changed_files = apply_changes(old_tree, new_tree, force=opts.force,
patch_mode=opts.patch)
if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1:
print 'changed files:'
for filename in changed_files:
print ' ', filename
def load_git_config(non_string_options=None):
"""Return the git configuration as a dictionary.
All options are assumed to be strings unless in `non_string_options`, in which
is a dictionary mapping option name (in lower case) to either "--bool" or
"--int"."""
if non_string_options is None:
non_string_options = {}
out = {}
for entry in run('git', 'config', '--list', '--null').split('\0'):
if entry:
name, value = entry.split('\n', 1)
if name in non_string_options:
value = run('git', 'config', non_string_options[name], name)
out[name] = value
return out
def interpret_args(args, dash_dash, default_commit):
"""Interpret `args` as "[commit] [--] [files...]" and return (commit, files).
It is assumed that "--" and everything that follows has been removed from
args and placed in `dash_dash`.
If "--" is present (i.e., `dash_dash` is non-empty), the argument to its
left (if present) is taken as commit. Otherwise, the first argument is
checked if it is a commit or a file. If commit is not given,
`default_commit` is used."""
if dash_dash:
if len(args) == 0:
commit = default_commit
elif len(args) > 1:
die('at most one commit allowed; %d given' % len(args))
else:
commit = args[0]
object_type = get_object_type(commit)
if object_type not in ('commit', 'tag'):
if object_type is None:
die("'%s' is not a commit" % commit)
else:
die("'%s' is a %s, but a commit was expected" % (commit, object_type))
files = dash_dash[1:]
elif args:
if disambiguate_revision(args[0]):
commit = args[0]
files = args[1:]
else:
commit = default_commit
files = args
else:
commit = default_commit
files = []
return commit, files
def disambiguate_revision(value):
"""Returns True if `value` is a revision, False if it is a file, or dies."""
# If `value` is ambiguous (neither a commit nor a file), the following
# command will die with an appropriate error message.
run('git', 'rev-parse', value, verbose=False)
object_type = get_object_type(value)
if object_type is None:
return False
if object_type in ('commit', 'tag'):
return True
die('`%s` is a %s, but a commit or filename was expected' %
(value, object_type))
def get_object_type(value):
"""Returns a string description of an object's type, or None if it is not
a valid git object."""
cmd = ['git', 'cat-file', '-t', value]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
return None
return stdout.strip()
def compute_diff_and_extract_lines(commit, files):
"""Calls compute_diff() followed by extract_lines()."""
diff_process = compute_diff(commit, files)
changed_lines = extract_lines(diff_process.stdout)
diff_process.stdout.close()
diff_process.wait()
if diff_process.returncode != 0:
# Assume error was already printed to stderr.
sys.exit(2)
return changed_lines
def compute_diff(commit, files):
"""Return a subprocess object producing the diff from `commit`.
The return value's `stdin` file object will produce a patch with the
differences between the working directory and `commit`, filtered on `files`
(if non-empty). Zero context lines are used in the patch."""
cmd = ['git', 'diff-index', '-p', '-U0', commit, '--']
cmd.extend(files)
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p.stdin.close()
return p
def extract_lines(patch_file):
"""Extract the changed lines in `patch_file`.
The return value is a dictionary mapping filename to a list of (start_line,
line_count) pairs.
The input must have been produced with ``-U0``, meaning unidiff format with
zero lines of context. The return value is a dict mapping filename to a
list of line `Range`s."""
matches = {}
for line in patch_file:
match = re.search(r'^\+\+\+\ [^/]+/(.*)', line)
if match:
filename = match.group(1).rstrip('\r\n')
match = re.search(r'^@@ -[0-9,]+ \+(\d+)(,(\d+))?', line)
if match:
start_line = int(match.group(1))
line_count = 1
if match.group(3):
line_count = int(match.group(3))
if line_count > 0:
matches.setdefault(filename, []).append(Range(start_line, line_count))
return matches
def filter_by_extension(dictionary, allowed_extensions):
"""Delete every key in `dictionary` that doesn't have an allowed extension.
`allowed_extensions` must be a collection of lowercase file extensions,
excluding the period."""
allowed_extensions = frozenset(allowed_extensions)
for filename in dictionary.keys():
base_ext = filename.rsplit('.', 1)
if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions:
del dictionary[filename]
def cd_to_toplevel():
"""Change to the top level of the git repository."""
toplevel = run('git', 'rev-parse', '--show-toplevel')
os.chdir(toplevel)
def create_tree_from_workdir(filenames):
"""Create a new git tree with the given files from the working directory.
Returns the object ID (SHA-1) of the created tree."""
return create_tree(filenames, '--stdin')
def run_clang_format_and_save_to_tree(changed_lines, binary='clang-format',
style=None):
"""Run clang-format on each file and save the result to a git tree.
Returns the object ID (SHA-1) of the created tree."""
def index_info_generator():
for filename, line_ranges in changed_lines.iteritems():
mode = oct(os.stat(filename).st_mode)
blob_id = clang_format_to_blob(filename, line_ranges, binary=binary,
style=style)
yield '%s %s\t%s' % (mode, blob_id, filename)
return create_tree(index_info_generator(), '--index-info')
def create_tree(input_lines, mode):
"""Create a tree object from the given input.
If mode is '--stdin', it must be a list of filenames. If mode is
'--index-info' is must be a list of values suitable for "git update-index
--index-info", such as "<mode> <SP> <sha1> <TAB> <filename>". Any other mode
is invalid."""
assert mode in ('--stdin', '--index-info')
cmd = ['git', 'update-index', '--add', '-z', mode]
with temporary_index_file():
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
for line in input_lines:
p.stdin.write('%s\0' % line)
p.stdin.close()
if p.wait() != 0:
die('`%s` failed' % ' '.join(cmd))
tree_id = run('git', 'write-tree')
return tree_id
def clang_format_to_blob(filename, line_ranges, binary='clang-format',
style=None):
"""Run clang-format on the given file and save the result to a git blob.
Returns the object ID (SHA-1) of the created blob."""
clang_format_cmd = [binary, filename]
if style:
clang_format_cmd.extend(['-style='+style])
clang_format_cmd.extend([
'-lines=%s:%s' % (start_line, start_line+line_count-1)
for start_line, line_count in line_ranges])
try:
clang_format = subprocess.Popen(clang_format_cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
except OSError as e:
if e.errno == errno.ENOENT:
die('cannot find executable "%s"' % binary)
else:
raise
clang_format.stdin.close()
hash_object_cmd = ['git', 'hash-object', '-w', '--path='+filename, '--stdin']
hash_object = subprocess.Popen(hash_object_cmd, stdin=clang_format.stdout,
stdout=subprocess.PIPE)
clang_format.stdout.close()
stdout = hash_object.communicate()[0]
if hash_object.returncode != 0:
die('`%s` failed' % ' '.join(hash_object_cmd))
if clang_format.wait() != 0:
die('`%s` failed' % ' '.join(clang_format_cmd))
return stdout.rstrip('\r\n')
@contextlib.contextmanager
def temporary_index_file(tree=None):
"""Context manager for setting GIT_INDEX_FILE to a temporary file and deleting
the file afterward."""
index_path = create_temporary_index(tree)
old_index_path = os.environ.get('GIT_INDEX_FILE')
os.environ['GIT_INDEX_FILE'] = index_path
try:
yield
finally:
if old_index_path is None:
del os.environ['GIT_INDEX_FILE']
else:
os.environ['GIT_INDEX_FILE'] = old_index_path
os.remove(index_path)
def create_temporary_index(tree=None):
"""Create a temporary index file and return the created file's path.
If `tree` is not None, use that as the tree to read in. Otherwise, an
empty index is created."""
gitdir = run('git', 'rev-parse', '--git-dir')
path = os.path.join(gitdir, temp_index_basename)
if tree is None:
tree = '--empty'
run('git', 'read-tree', '--index-output='+path, tree)
return path
def print_diff(old_tree, new_tree):
"""Print the diff between the two trees to stdout."""
# We use the porcelain 'diff' and not plumbing 'diff-tree' because the output
# is expected to be viewed by the user, and only the former does nice things
# like color and pagination.
subprocess.check_call(['git', 'diff', old_tree, new_tree, '--'])
def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
"""Apply the changes in `new_tree` to the working directory.
Bails if there are local changes in those files and not `force`. If
`patch_mode`, runs `git checkout --patch` to select hunks interactively."""
changed_files = run('git', 'diff-tree', '-r', '-z', '--name-only', old_tree,
new_tree).rstrip('\0').split('\0')
if not force:
unstaged_files = run('git', 'diff-files', '--name-status', *changed_files)
if unstaged_files:
print >>sys.stderr, ('The following files would be modified but '
'have unstaged changes:')
print >>sys.stderr, unstaged_files
print >>sys.stderr, 'Please commit, stage, or stash them first.'
sys.exit(2)
if patch_mode:
# In patch mode, we could just as well create an index from the new tree
# and checkout from that, but then the user will be presented with a
# message saying "Discard ... from worktree". Instead, we use the old
# tree as the index and checkout from new_tree, which gives the slightly
# better message, "Apply ... to index and worktree". This is not quite
# right, since it won't be applied to the user's index, but oh well.
with temporary_index_file(old_tree):
subprocess.check_call(['git', 'checkout', '--patch', new_tree])
index_tree = old_tree
else:
with temporary_index_file(new_tree):
run('git', 'checkout-index', '-a', '-f')
return changed_files
def run(*args, **kwargs):
stdin = kwargs.pop('stdin', '')
verbose = kwargs.pop('verbose', True)
strip = kwargs.pop('strip', True)
for name in kwargs:
raise TypeError("run() got an unexpected keyword argument '%s'" % name)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
stdout, stderr = p.communicate(input=stdin)
if p.returncode == 0:
if stderr:
if verbose:
print >>sys.stderr, '`%s` printed to stderr:' % ' '.join(args)
print >>sys.stderr, stderr.rstrip()
if strip:
stdout = stdout.rstrip('\r\n')
return stdout
if verbose:
print >>sys.stderr, '`%s` returned %s' % (' '.join(args), p.returncode)
if stderr:
print >>sys.stderr, stderr.rstrip()
sys.exit(2)
def die(message):
print >>sys.stderr, 'error:', message
sys.exit(2)
if __name__ == '__main__':
main()

192
help2rst.py Executable file
View File

@@ -0,0 +1,192 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# script to produce rst file from program's help output.
from __future__ import unicode_literals
from __future__ import print_function
import sys
import re
import argparse
arg_indent = ' ' * 14
def help2man(infile):
# We assume that first line is usage line like this:
#
# Usage: nghttp [OPTIONS]... URI...
#
# The second line is description of the command. Multiple lines
# are permitted. The blank line signals the end of this section.
# After that, we parses positional and optional arguments.
#
# The positional argument is enclosed with < and >:
#
# <PRIVATE_KEY>
#
# We may describe default behavior without any options by encoding
# ( and ):
#
# (default mode)
#
# "Options:" is treated specially and produces "OPTIONS" section.
# We allow subsection under OPTIONS. Lines not starting with (, <
# and Options: are treated as subsection name and produces section
# one level down:
#
# TLS/SSL:
#
# The above is an example of subsection.
#
# The description of arguments must be indented by len(arg_indent)
# characters. The default value should be placed in separate line
# and should be start with "Default: " after indentation.
line = infile.readline().strip()
m = re.match(r'^Usage: (.*)', line)
if not m:
print('usage line is invalid. Expected following lines:')
print('Usage: cmdname ...')
sys.exit(1)
synopsis = m.group(1).split(' ', 1)
if len(synopsis) == 2:
cmdname, args = synopsis
else:
cmdname, args = synopsis[0], ''
description = []
for line in infile:
line = line.strip()
if not line:
break
description.append(line)
print('''
.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
.. program:: {cmdname}
{cmdname}(1)
{cmdnameunderline}
SYNOPSIS
--------
**{cmdname}** {args}
DESCRIPTION
-----------
{description}
'''.format(cmdname=cmdname, args=args,
cmdnameunderline='=' * (len(cmdname) + 3),
synopsis=synopsis, description=format_text('\n'.join(description))))
in_arg = False
in_footer = False
for line in infile:
line = line.rstrip()
if not line.strip() and in_arg:
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):])))
continue
if in_arg:
print()
in_arg = False
if line == '--':
in_footer = True
continue
if in_footer:
print(line.strip())
continue
if line == 'Options:':
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())))
in_arg = True
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())))
in_arg = True
continue
if line.startswith(' -'):
# optional argument
m = re.match(
r'^(?:\s+)(-\S+?(?:, -\S+?)*)($| .*)',
line)
argname, rest = m.group(1), m.group(2)
print('.. option:: {}'.format(argname))
print()
rest = rest.strip()
if len(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()
continue
print(line.strip())
def format_text(text):
# escape *
if len(text) > len(arg_indent):
text = text[:len(arg_indent) + 1] + re.sub(r'\*', r'\*', text[len(arg_indent) + 1:])
else:
text = re.sub(r'\*', r'\*', text)
# markup option reference
text = re.sub(r'(^|\s)(-[a-zA-Z0-9-]+)', r'\1:option:`\2`', text)
# sphinx does not like markup like ':option:`-f`='. We need
# backslash between ` and =.
text = re.sub(r'(:option:`.*?`)(\S)', r'\1\\\2', text)
# file path should be italic
text = re.sub(r'(^|\s|\'|")(/[^\s\'"]*)', r'\1*\2*', text)
return text
def format_arg_text(text):
if text.strip().startswith('Default: '):
return '\n ' + re.sub(r'^(\s*Default: )(.*)$', r'\1``\2``', text)
return ' {}'.format(format_text(text))
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Produces rst document from help output.')
parser.add_argument('-i', '--include', metavar='FILE',
help='include content of <FILE> as verbatim. It should be ReST formatted text.')
args = parser.parse_args()
help2man(sys.stdin)
if args.include:
print()
with open(args.include) as f:
sys.stdout.write(f.read())

2
integration-tests/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
# generated files
config.go

View File

@@ -0,0 +1,44 @@
# 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 = \
nghttpx_http1_test.go \
nghttpx_http2_test.go \
nghttpx_spdy_test.go \
server_tester.go \
server.key \
server.crt \
alt-server.key \
alt-server.crt \
setenv
.PHONY: itprep it
itprep:
go get -d -v github.com/bradfitz/http2
go get -d -v github.com/tatsuhiro-t/go-nghttp2
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

@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDhzCCAm+gAwIBAgIJANfuEldiquMNMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmFsdC1kb21haW4wHhcNMTUwMTI1MDYy
NTQxWhcNMjUwMTIyMDYyNTQxWjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29t
ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYD
VQQDDAphbHQtZG9tYWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
0IwhDOGDipGrJQ9IoRSzPdkU/Ii4aJgGKHlXminym42X0VI3IW61RLvOHRlHVmVH
JQjFuDo2x+y81t9NlDg3HGUbSpzOzpm6StiutB7c4hreT5G4r0YKya1ugiemN0+p
qjIPJWm2jVnf448eZvUKRKEQ9W0MLZjiNjVGKrKlwo7fIlXg4N3+YixLYffAT1NV
d1T6V5jzlbruj15gK2nGjMQ9D1h1t9vTbTxY+mtk72aX0Y64IE6pPBWLFSSH8ozU
idDoL3AZwz2Jker+ALKK8CM4uho/RPpyW1C06HH+HLdH2MqEjDOROde/Nzxm668O
gK/JWGIEyUqYiUXx0yhFxwIDAQABo1AwTjAdBgNVHQ4EFgQU/Y0GDN2uPjbyePcu
95ZvYEK/gHIwHwYDVR0jBBgwFoAU/Y0GDN2uPjbyePcu95ZvYEK/gHIwDAYDVR0T
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAodD6LVCzL3wfsZ6TxTzf9TfgIdbj
ilL3SEMT/xnfTXT3SLYScTRqQIAI29Y7dOLMq89p4hY2wmeUEhBUAz+y9G2JVr8o
6EbxXrQpWgNJogELqoNnMdrDxB5RsmDDKEJ/rLjDfSkjWbK7B2PZsqVTDgjekCFw
u6FqTIjn/O1O/L5tjwxwxjHmQod/maFCvXoDOVBuwdHnkp298tqlvsHfHO8m++Wj
+XYB8plMIjpeTh9v4w9Jc4QZ59lK/3Tt4qaENeQrMEubKSY/Zen7L2bzhk+cChWT
GSGz9uNXieoZaH79D0wnyZaSZ5Ds4ActMevnGg3iYXuzuFqx8Pungn74Vg==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDQjCEM4YOKkasl
D0ihFLM92RT8iLhomAYoeVeaKfKbjZfRUjchbrVEu84dGUdWZUclCMW4OjbH7LzW
302UODccZRtKnM7OmbpK2K60HtziGt5PkbivRgrJrW6CJ6Y3T6mqMg8labaNWd/j
jx5m9QpEoRD1bQwtmOI2NUYqsqXCjt8iVeDg3f5iLEth98BPU1V3VPpXmPOVuu6P
XmAracaMxD0PWHW329NtPFj6a2TvZpfRjrggTqk8FYsVJIfyjNSJ0OgvcBnDPYmR
6v4AsorwIzi6Gj9E+nJbULTocf4ct0fYyoSMM5E51783PGbrrw6Ar8lYYgTJSpiJ
RfHTKEXHAgMBAAECggEBALTrjFSXY72YB+h7rN+JjMIwDIPUvF6I3HbKZhQpJf6K
xNVkRM2tNHavku0tm/S4ohLf3F+pqRKiL2Udjjjy1+S7VgTRqpwTQ0lhV5aNW8SP
2KMg4R61XfB+k+s4KHu9kYxEJ12mqydPe+r3o0FgfYryTDsOYk1AX6b1aqzqFOGF
7GaqLALSbKU59tcJJ1SZNBbpIKFUrAT9nZt9dW02/foqP5bzUk43Yjw48xmLwegc
bMXXcpZhNZSktltvwRw7Q4Foc9kuRlMdTAnAD9PnMCcZwicS/YeVVF6Rz4fGviKv
7/kPHQ7g4YpFktVDzuZ5xw6GDVFeJ6uGMVUX8+EePvkCgYEA+/nrcn82nFHCxm8Q
0iiUhi/AoXjZg+O5Ytaje9O/YNoX+c4ywe13h0+TXKH79O0KfTwXeJyDgPZbAIFV
9oURellRYUzKDafnBHis2f+Ywn6GqHL5e2X30ZxIp1GK46pcvne1YuvJhgGmiVay
vd7sRx09OKU124dG22rIFCis6asCgYEA0+CsA6LrEwQ/aPJYASY3VHNO/WoAOnPg
Cwsg+02XWsPEwP//lNmpanz8TUm2URS063ZK8bx7t3ejvDgBdsRwwjiMlDp7XTUU
3Zk+mhCV2qkMi02aKemvz29bDhmh5JoH7W3IwsXtJYO0yZDYrDR3ioiKRccioPoE
b/Nq781sEFUCgYEA4xqx9xRpaCLY5nicNI6WrwrDF8YQZisNn+PMnYKP7v8itOgA
H4GkRbSXINpueKZc2dsbXH3UmJtyEdaAYBw3UIrIKmZHhl9afFE3mZQhXssjGxfl
fC6/WZD+eq+n+uJFjPXf6jSSAdHjA828dB1D4CSeVTuyexZF6uUnR+QRVNkCgYEA
i+pb7XLSpZYygY03zFp+Q0h6KyKqz+7hTqmkuA8/GfMZpRHop1UtaWLsAeXhfZ2c
87kEOKptUHSzLYIWhWWnyLorK1+LQ7vf8Y5XJso5C1KDNCKk4XSuYt94U9FddWa6
QXI0F1s5BYL6Cfma++0R2+va08Vy+rbf40XtojoXWJkCgYEA0hMQSCvok7is27nQ
G80KXfmghU2eEB7zif3T00/fwJycxEbmnNeof+SKmhdY4ZgqTscfOxlQPflV/eqB
xs4GnFDDeM0F8KH0BimOXxr7sJPFCg22PCCQQcRtM/KoU+ip/kNmTfwrsC0xMFPU
HD8M1JCZF2eLMekXXP3cB0U4sUs=
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,5 @@
package nghttp2
const (
buildDir = "@top_builddir@"
)

View File

@@ -0,0 +1,549 @@
package nghttp2
import (
"bufio"
"bytes"
"fmt"
"github.com/bradfitz/http2/hpack"
"golang.org/x/net/websocket"
"io"
"net/http"
"syscall"
"testing"
)
// TestH1H1PlainGET tests whether simple HTTP/1 GET request works.
func TestH1H1PlainGET(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1PlainGET",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
want := 200
if got := res.status; got != want {
t.Errorf("status = %v; want %v", got, want)
}
}
// TestH1H1PlainGETClose tests whether simple HTTP/1 GET request with
// Connetion: close request header field works.
func TestH1H1PlainGETClose(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1PlainGETClose",
header: []hpack.HeaderField{
pair("Connection", "close"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
want := 200
if got := res.status; got != want {
t.Errorf("status = %v; want %v", got, want)
}
}
// 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) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
if _, err := io.WriteString(st.conn, fmt.Sprintf(`GET / HTTP/1.1
Host: %v
Test-Case: TestH1H1MultipleRequestCL
Content-Length: 0
Content-Length: 0
`, st.authority)); err != nil {
t.Fatalf("Error io.WriteString() = %v", err)
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err)
}
want := 400
if got := resp.StatusCode; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/1 backend failed.
func TestH1H1ConnectFailure(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
// shutdown backend server to simulate backend connect failure
st.ts.Close()
res, err := st.http1(requestParam{
name: "TestH1H1ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1GracefulShutdown tests graceful shutdown.
func TestH1H1GracefulShutdown(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1GracefulShutdown-1",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
st.cmd.Process.Signal(syscall.SIGQUIT)
res, err = st.http1(requestParam{
name: "TestH1H1GracefulShutdown-2",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := res.connClose, true; got != want {
t.Errorf("res.connClose: %v; want %v", got, want)
}
want := io.EOF
if _, err := st.conn.Read(nil); err == nil || err != want {
t.Errorf("st.conn.Read(): %v; want %v", err, want)
}
}
// TestH1H1HostRewrite tests that server rewrites Host header field
func TestH1H1HostRewrite(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("request-host", r.Host)
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1HostRewrite",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := res.header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want)
}
}
// TestH1H1HTTP10 tests that server can accept HTTP/1.0 request
// without Host header field
func TestH1H1HTTP10(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("request-host", r.Host)
})
defer st.Close()
if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err)
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err)
}
if got, want := resp.StatusCode, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want)
}
}
// TestH1H1HTTP10NoHostRewrite tests that server generates host header
// field using actual backend server even if --no-http-rewrite is
// used.
func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
st := newServerTester([]string{"--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("request-host", r.Host)
})
defer st.Close()
if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10NoHostRewrite\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err)
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err)
}
if got, want := resp.StatusCode, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want)
}
}
// TestH1H1RequestTrailer tests request trailer part is forwarded to
// backend.
func TestH1H1RequestTrailer(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
buf := make([]byte, 4096)
for {
_, err := r.Body.Read(buf)
if err == io.EOF {
break
}
if err != nil {
t.Fatalf("r.Body.Read() = %v", err)
}
}
if got, want := r.Trailer.Get("foo"), "bar"; got != want {
t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want)
}
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1RequestTrailer",
body: []byte("1"),
trailer: []hpack.HeaderField{
pair("foo", "bar"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
}
// 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) {
st := newServerTester([]string{"--http2-bridge"}, t, noopHandler)
defer st.Close()
// simulate backend connect attempt failure
st.ts.Close()
res, err := st.http1(requestParam{
name: "TestH1H2ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H2NoHost tests that server rejects request without Host
// header field for HTTP/2 backend.
func TestH1H2NoHost(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
// without Host header field, we expect 400 response
if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H2NoHost\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err)
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err)
}
want := 400
if got := resp.StatusCode; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H2HTTP10 tests that server can accept HTTP/1.0 request
// without Host header field
func TestH1H2HTTP10(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("request-host", r.Host)
})
defer st.Close()
if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err)
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err)
}
if got, want := resp.StatusCode, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want)
}
}
// TestH1H2HTTP10NoHostRewrite tests that server generates host header
// field using actual backend server even if --no-http-rewrite is
// used.
func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
st := newServerTester([]string{"--http2-bridge", "--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("request-host", r.Host)
})
defer st.Close()
if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10NoHostRewrite\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err)
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err)
}
if got, want := resp.StatusCode, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want)
}
}
// TestH1H2CrumbleCookie tests that Cookies are crumbled and assembled
// when forwarding to HTTP/2 backend link. go-nghttp2 server
// concatenates crumbled Cookies automatically, so this test is not
// much effective now.
func TestH1H2CrumbleCookie(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
t.Errorf("Cookie: %v; want %v", got, want)
}
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H2CrumbleCookie",
header: []hpack.HeaderField{
pair("Cookie", "alpha; bravo; charlie"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H2GenerateVia tests that server generates Via header field to and
// from backend server.
func TestH1H2GenerateVia(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H2GenerateVia",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.header.Get("Via"), "2 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
}
// TestH1H2AppendVia tests that server adds value to existing Via
// header field to and from backend server.
func TestH1H2AppendVia(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "foo, 1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
w.Header().Add("Via", "bar")
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H2AppendVia",
header: []hpack.HeaderField{
pair("via", "foo"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.header.Get("Via"), "bar, 2 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
}
// TestH1H2NoVia tests that server does not add value to existing Via
// header field to and from backend server.
func TestH1H2NoVia(t *testing.T) {
st := newServerTester([]string{"--http2-bridge", "--no-via"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "foo"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
w.Header().Add("Via", "bar")
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H2NoVia",
header: []hpack.HeaderField{
pair("via", "foo"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.header.Get("Via"), "bar"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
}

View File

@@ -0,0 +1,877 @@
package nghttp2
import (
"crypto/tls"
"fmt"
"github.com/bradfitz/http2"
"github.com/bradfitz/http2/hpack"
"io"
"io/ioutil"
"net/http"
"strings"
"syscall"
"testing"
)
// TestH2H1PlainGET tests whether simple HTTP/2 GET request works.
func TestH2H1PlainGET(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1PlainGET",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 200
if res.status != want {
t.Errorf("status = %v; want %v", res.status, want)
}
}
// TestH2H1AddXff tests that server generates X-Forwarded-For header
// field when forwarding request to backend.
func TestH2H1AddXff(t *testing.T) {
st := newServerTester([]string{"--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For")
want := "127.0.0.1"
if xff != want {
t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1AddXff",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1AddXff2 tests that server appends X-Forwarded-For header
// field to existing one when forwarding request to backend.
func TestH2H1AddXff2(t *testing.T) {
st := newServerTester([]string{"--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For")
want := "host, 127.0.0.1"
if xff != want {
t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1AddXff2",
header: []hpack.HeaderField{
pair("x-forwarded-for", "host"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1StripXff tests that --strip-incoming-x-forwarded-for
// option.
func TestH2H1StripXff(t *testing.T) {
st := newServerTester([]string{"--strip-incoming-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
if xff, found := r.Header["X-Forwarded-For"]; found {
t.Errorf("X-Forwarded-For = %v; want nothing", xff)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1StripXff1",
header: []hpack.HeaderField{
pair("x-forwarded-for", "host"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1StripAddXff tests that --strip-incoming-x-forwarded-for and
// --add-x-forwarded-for options.
func TestH2H1StripAddXff(t *testing.T) {
args := []string{
"--strip-incoming-x-forwarded-for",
"--add-x-forwarded-for",
}
st := newServerTester(args, t, func(w http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For")
want := "127.0.0.1"
if xff != want {
t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1StripAddXff",
header: []hpack.HeaderField{
pair("x-forwarded-for", "host"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1GenerateVia tests that server generates Via header field to and
// from backend server.
func TestH2H1GenerateVia(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "2 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1GenerateVia",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
}
// TestH2H1AppendVia tests that server adds value to existing Via
// header field to and from backend server.
func TestH2H1AppendVia(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "foo, 2 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
w.Header().Add("Via", "bar")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1AppendVia",
header: []hpack.HeaderField{
pair("via", "foo"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
}
// TestH2H1NoVia tests that server does not add value to existing Via
// header field to and from backend server.
func TestH2H1NoVia(t *testing.T) {
st := newServerTester([]string{"--no-via"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "foo"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
w.Header().Add("Via", "bar")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1NoVia",
header: []hpack.HeaderField{
pair("via", "foo"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.header.Get("Via"), "bar"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
}
// TestH2H1HostRewrite tests that server rewrites host header field
func TestH2H1HostRewrite(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("request-host", r.Host)
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1HostRewrite",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := res.header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want)
}
}
// TestH2H1NoHostRewrite tests that server does not rewrite host
// header field
func TestH2H1NoHostRewrite(t *testing.T) {
st := newServerTester([]string{"--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("request-host", r.Host)
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1NoHostRewrite",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want)
}
}
// TestH2H1BadRequestCL tests that server rejects request whose
// content-length header field value does not match its request body
// size.
func TestH2H1BadRequestCL(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
// we set content-length: 1024, but the actual request body is
// 3 bytes.
res, err := st.http2(requestParam{
name: "TestH2H1BadRequestCL",
method: "POST",
header: []hpack.HeaderField{
pair("content-length", "1024"),
},
body: []byte("foo"),
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := http2.ErrCodeProtocol
if res.errCode != want {
t.Errorf("res.errCode = %v; want %v", res.errCode, want)
}
}
// TestH2H1BadResponseCL tests that server returns error when
// content-length response header field value does not match its
// response body size.
func TestH2H1BadResponseCL(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
// we set content-length: 1024, but only send 3 bytes.
w.Header().Add("Content-Length", "1024")
w.Write([]byte("foo"))
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1BadResponseCL",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := http2.ErrCodeProtocol
if res.errCode != want {
t.Errorf("res.errCode = %v; want %v", res.errCode, want)
}
}
// TestH2H1LocationRewrite tests location header field rewriting
// works.
func TestH2H1LocationRewrite(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
// TODO we cannot get st.ts's port number here.. 8443
// is just a place holder. We ignore it on rewrite.
w.Header().Add("Location", "http://127.0.0.1:8443/p/q?a=b#fragment")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1LocationRewrite",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := fmt.Sprintf("http://127.0.0.1:%v/p/q?a=b#fragment", serverPort)
if got := res.header.Get("Location"); got != want {
t.Errorf("Location: %v; want %v", got, want)
}
}
// TestH2H1ChunkedRequestBody tests that chunked request body works.
func TestH2H1ChunkedRequestBody(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
want := "[chunked]"
if got := fmt.Sprint(r.TransferEncoding); got != want {
t.Errorf("Transfer-Encoding: %v; want %v", got, want)
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Fatalf("Error reading r.body: %v", err)
}
want = "foo"
if got := string(body); got != want {
t.Errorf("body: %v; want %v", got, want)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1ChunkedRequestBody",
method: "POST",
body: []byte("foo"),
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1MultipleRequestCL tests that server rejects request with
// multiple Content-Length request header fields.
func TestH2H1MultipleRequestCL(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1MultipleRequestCL",
header: []hpack.HeaderField{
pair("content-length", "1"),
pair("content-length", "1"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
t.Errorf("res.errCode: %v; want %v", got, want)
}
}
// TestH2H1InvalidRequestCL tests that server rejects request with
// Content-Length which cannot be parsed as a number.
func TestH2H1InvalidRequestCL(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1InvalidRequestCL",
header: []hpack.HeaderField{
pair("content-length", ""),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
t.Errorf("res.errCode: %v; want %v", got, want)
}
}
// TestH2H1ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/1 backend failed.
func TestH2H1ConnectFailure(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
// shutdown backend server to simulate backend connect failure
st.ts.Close()
res, err := st.http2(requestParam{
name: "TestH2H1ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// 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) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
t.Errorf("Cookie: %v; want %v", got, want)
}
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1AssembleCookies",
header: []hpack.HeaderField{
pair("cookie", "alpha"),
pair("cookie", "bravo"),
pair("cookie", "charlie"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1TETrailers tests that server accepts TE request header
// field if it has trailers only.
func TestH2H1TETrailers(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1TETrailers",
header: []hpack.HeaderField{
pair("te", "trailers"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1TEGzip tests that server resets stream if TE request header
// field contains gzip.
func TestH2H1TEGzip(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Error("server should not forward bad request")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1TEGzip",
header: []hpack.HeaderField{
pair("te", "gzip"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
t.Errorf("res.errCode = %v; want %v", res.errCode, want)
}
}
// TestH2H1SNI tests server's TLS SNI extension feature. It must
// choose appropriate certificate depending on the indicated
// server_name from client.
func TestH2H1SNI(t *testing.T) {
st := newServerTesterTLSConfig([]string{"--subcert=" + testDir + "/alt-server.key:" + testDir + "/alt-server.crt"}, t, noopHandler, &tls.Config{
ServerName: "alt-domain",
})
defer st.Close()
tlsConn := st.conn.(*tls.Conn)
connState := tlsConn.ConnectionState()
cert := connState.PeerCertificates[0]
if got, want := cert.Subject.CommonName, "alt-domain"; got != want {
t.Errorf("CommonName: %v; want %v", got, want)
}
}
// TestH2H1TLSXfp tests nghttpx sends x-forwarded-proto header field
// with http value since :scheme is http, even if the frontend
// connection is encrypted.
func TestH2H1TLSXfp(t *testing.T) {
st := newServerTesterTLS(nil, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
}
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1TLSXfp",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
}
// TestH2H1ServerPush tests server push using Link header field from
// backend server.
func TestH2H1ServerPush(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
// only resources marked as rel=preload are pushed
if !strings.HasPrefix(r.URL.Path, "/css/") {
w.Header().Add("Link", "</css/main.css>; rel=preload, </foo>, </css/theme.css>; rel=preload")
}
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1ServerPush",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
if got, want := len(res.pushResponse), 2; got != want {
t.Fatalf("len(res.pushResponse): %v; want %v", got, want)
}
mainCSS := res.pushResponse[0]
if got, want := mainCSS.status, 200; got != want {
t.Errorf("mainCSS.status: %v; want %v", got, want)
}
themeCSS := res.pushResponse[1]
if got, want := themeCSS.status, 200; got != want {
t.Errorf("themeCSS.status: %v; want %v", got, want)
}
}
// TestH2H1RequestTrailer tests request trailer part is forwarded to
// backend.
func TestH2H1RequestTrailer(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
buf := make([]byte, 4096)
for {
_, err := r.Body.Read(buf)
if err == io.EOF {
break
}
if err != nil {
t.Fatalf("r.Body.Read() = %v", err)
}
}
if got, want := r.Trailer.Get("foo"), "bar"; got != want {
t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want)
}
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1RequestTrailer",
body: []byte("1"),
trailer: []hpack.HeaderField{
pair("foo", "bar"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
}
// 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) {})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH2H1Upgrade",
header: []hpack.HeaderField{
pair("Connection", "Upgrade, HTTP2-Settings"),
pair("Upgrade", "h2c"),
pair("HTTP2-Settings", "AAMAAABkAAQAAP__"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 101; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
res, err = st.http2(requestParam{
httpUpgrade: true,
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
}
// TestH2H1GracefulShutdown tests graceful shutdown.
func TestH2H1GracefulShutdown(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
fmt.Fprint(st.conn, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
if err := st.fr.WriteSettings(); err != nil {
t.Fatalf("st.fr.WriteSettings(): %v", err)
}
header := []hpack.HeaderField{
pair(":method", "GET"),
pair(":scheme", "http"),
pair(":authority", st.authority),
pair(":path", "/"),
}
for _, h := range header {
_ = st.enc.WriteField(h)
}
if err := st.fr.WriteHeaders(http2.HeadersFrameParam{
StreamID: 1,
EndStream: false,
EndHeaders: true,
BlockFragment: st.headerBlkBuf.Bytes(),
}); err != nil {
t.Fatalf("st.fr.WriteHeaders(): %v", err)
}
// send SIGQUIT signal to nghttpx to perform graceful shutdown
st.cmd.Process.Signal(syscall.SIGQUIT)
// after signal, finish request body
if err := st.fr.WriteData(1, true, nil); err != nil {
t.Fatalf("st.fr.WriteData(): %v", err)
}
numGoAway := 0
for {
fr, err := st.readFrame()
if err != nil {
if err == io.EOF {
want := 2
if got := numGoAway; got != want {
t.Fatalf("numGoAway: %v; want %v", got, want)
}
return
}
t.Fatalf("st.readFrame(): %v", err)
}
switch f := fr.(type) {
case *http2.GoAwayFrame:
numGoAway += 1
want := http2.ErrCodeNo
if got := f.ErrCode; got != want {
t.Fatalf("f.ErrCode(%v): %v; want %v", numGoAway, got, want)
}
switch numGoAway {
case 1:
want := (uint32(1) << 31) - 1
if got := f.LastStreamID; got != want {
t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want)
}
case 2:
want := uint32(1)
if got := f.LastStreamID; got != want {
t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want)
}
case 3:
t.Fatalf("too many GOAWAYs received")
}
}
}
}
// TestH2H2MultipleResponseCL tests that server returns error if
// multiple Content-Length response header fields are received.
func TestH2H2MultipleResponseCL(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("content-length", "1")
w.Header().Add("content-length", "1")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H2MultipleResponseCL",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.errCode, http2.ErrCodeInternal; got != want {
t.Errorf("res.errCode: %v; want %v", got, want)
}
}
// TestH2H2InvalidResponseCL tests that server returns error if
// Content-Length response header field value cannot be parsed as a
// number.
func TestH2H2InvalidResponseCL(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("content-length", "")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H2InvalidResponseCL",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.errCode, http2.ErrCodeInternal; got != want {
t.Errorf("res.errCode: %v; want %v", got, want)
}
}
// TestH2H2ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/2 backend failed.
func TestH2H2ConnectFailure(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, noopHandler)
defer st.Close()
// simulate backend connect attempt failure
st.ts.Close()
res, err := st.http2(requestParam{
name: "TestH2H2ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H2HostRewrite tests that server rewrites host header field
func TestH2H2HostRewrite(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("request-host", r.Host)
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H2HostRewrite",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := res.header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want)
}
}
// TestH2H2NoHostRewrite tests that server does not rewrite host
// header field
func TestH2H2NoHostRewrite(t *testing.T) {
st := newServerTester([]string{"--http2-bridge", "--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("request-host", r.Host)
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H2NoHostRewrite",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want)
}
}
// TestH2H2TLSXfp tests nghttpx sends x-forwarded-proto header field
// with http value since :scheme is http, even if the frontend
// connection is encrypted.
func TestH2H2TLSXfp(t *testing.T) {
st := newServerTesterTLS([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
}
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H2TLSXfp",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
}

View File

@@ -0,0 +1,252 @@
package nghttp2
import (
"github.com/bradfitz/http2/hpack"
"github.com/tatsuhiro-t/spdy"
"net/http"
"testing"
)
// TestS3H1PlainGET tests whether simple SPDY GET request works.
func TestS3H1PlainGET(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, noopHandler)
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1PlainGET",
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := 200
if got := res.status; got != want {
t.Errorf("status = %v; want %v", got, want)
}
}
// TestS3H1BadRequestCL tests that server rejects request whose
// content-length header field value does not match its request body
// size.
func TestS3H1BadRequestCL(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, noopHandler)
defer st.Close()
// we set content-length: 1024, but the actual request body is
// 3 bytes.
res, err := st.spdy(requestParam{
name: "TestS3H1BadRequestCL",
method: "POST",
header: []hpack.HeaderField{
pair("content-length", "1024"),
},
body: []byte("foo"),
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := spdy.ProtocolError
if got := res.spdyRstErrCode; got != want {
t.Errorf("res.spdyRstErrCode = %v; want %v", got, want)
}
}
// TestS3H1MultipleRequestCL tests that server rejects request with
// multiple Content-Length request header fields.
func TestS3H1MultipleRequestCL(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 bad request")
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1MultipleRequestCL",
header: []hpack.HeaderField{
pair("content-length", "1"),
pair("content-length", "1"),
},
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := 400
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestS3H1InvalidRequestCL tests that server rejects request with
// Content-Length which cannot be parsed as a number.
func TestS3H1InvalidRequestCL(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 bad request")
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1InvalidRequestCL",
header: []hpack.HeaderField{
pair("content-length", ""),
},
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := 400
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestS3H1GenerateVia tests that server generates Via header field to and
// from backend server.
func TestS3H1GenerateVia(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1GenerateVia",
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
}
// TestS3H1AppendVia tests that server adds value to existing Via
// header field to and from backend server.
func TestS3H1AppendVia(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "foo, 1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
w.Header().Add("Via", "bar")
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1AppendVia",
header: []hpack.HeaderField{
pair("via", "foo"),
},
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
}
// TestS3H1NoVia tests that server does not add value to existing Via
// header field to and from backend server.
func TestS3H1NoVia(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--no-via"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "foo"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
w.Header().Add("Via", "bar")
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1NoVia",
header: []hpack.HeaderField{
pair("via", "foo"),
},
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
if got, want := res.header.Get("Via"), "bar"; got != want {
t.Errorf("Via: %v; want %v", got, want)
}
}
// 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) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--http2-bridge"}, t, noopHandler)
defer st.Close()
// simulate backend connect attempt failure
st.ts.Close()
res, err := st.spdy(requestParam{
name: "TestS3H2ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}

View File

@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDhTCCAm2gAwIBAgIJAOvIx8xIxgyOMA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCTEyNy4wLjAuMTAeFw0xNTAxMjMxMjI0
MjdaFw0yNTAxMjAxMjI0MjdaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l
LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV
BAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMuI
QZRI/iBaxPTjTWGemt8tCEfzZWxuIW3hY/gIhwJDfH2SbourBh1s9vqcqhBq5vmo
kdfVQXAnNLjIG1uhWmcHuNnKrE5hU82N6i9RsmuM5TQRvhsamHri4G+EXJMu9GqF
Mso8g7MWpRSGKf+8gfjAVNwfCHFiu8oBcMmy3l54MFHgRLSveAMhiPB0e3Xlnpr5
2bS/oGTx5ynwPgBpEn2FrpT4Z/aLCLzJ/ysgNH8BXEh7n/v7xM3vd5grqB039rd5
JoxlWvp+4XpzKp5upaqmOcVUq4pDSFUQ3w6C+v33Z3OK6Qaon7GMxLv3Us3b7PZ3
1CLoWJR2o3OSnUfO/gUCAwEAAaNQME4wHQYDVR0OBBYEFLc5JWPUUVx4GJesogMV
w2Rz0L3yMB8GA1UdIwQYMBaAFLc5JWPUUVx4GJesogMVw2Rz0L3yMAwGA1UdEwQF
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAP/cJWpM+GEjmVYHFacKTdbXBMox2Xn
QY2NLm00WPOGvKnO7czMFfX/pEmiq71kD45rLLfbaJP205QpxqiAIvhFhuq50Co7
sTDtwcDTPLX9H7Ugjt4sTMPiwC14uVXFfoT/J46zMjXwP00qKyfszc2tkIgHfrTl
h4M1hkdfmMximir/Ii7TdYYJ3oGS8tdcYb6D4DZwAljKmxF6iUOwFCUgpTmqDBT5
irXY8D27DzuNN5Pg07rwAlwXLCzrJE10UtO4MmRVXwpzmoaRQD4/tna6bZzdetvs
gPdGP6W1o0q85gullieMJWeKyQA/wasoE7fypn4pHAdTZm/vH+v7GHg=
-----END CERTIFICATE-----

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