Compare commits

..

326 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
efa344be98 Add assert to ensure non-null dep_stream 2014-11-08 23:23:54 +09:00
Tatsuhiro Tsujikawa
2ba9a009fe nghttpd: Fix resource leak 2014-11-08 23:07:40 +09:00
Tatsuhiro Tsujikawa
c59ffa09e0 Update man pages 2014-11-08 22:55:24 +09:00
Tatsuhiro Tsujikawa
72f5e028d0 Bump up version number to 0.6.6, LT revision to 7:1:2 2014-11-08 22:52:45 +09:00
Tatsuhiro Tsujikawa
80b361dbb0 nghttpx: Use exit instead of abort for DIE macro 2014-11-08 21:38:57 +09:00
Tatsuhiro Tsujikawa
58254adb11 h2load: Print used SSL/TLS cipher name and parameters 2014-11-08 21:24:24 +09:00
Tatsuhiro Tsujikawa
7f60e8a307 Fix C++ lib sample 2014-11-08 16:52:03 +09:00
Tatsuhiro Tsujikawa
c31be5af4d Assign default priority if dep_stream in PRIORITY does not exist 2014-11-08 16:12:13 +09:00
Tatsuhiro Tsujikawa
292c01fda2 Add test to make sure that default priority is assigned 2014-11-08 11:37:53 +09:00
Tatsuhiro Tsujikawa
91f7d43e84 Assign default priority if dependency parent stream does not exist 2014-11-08 11:23:18 +09:00
Tatsuhiro Tsujikawa
ce71e65aee nghttpx: Replace WARNING with WARN for consistency 2014-11-08 10:51:56 +09:00
Tatsuhiro Tsujikawa
1119701071 nghttpx: Fix -L option help message
WARNING should be WARN.
2014-11-08 10:45:58 +09:00
Tatsuhiro Tsujikawa
42122c270a Don't reprioritize stream if it is not in dependency tree
Normally stream is in dependency tree, but sometimes it isn't.  For
example, client does not put pushed reserved stream in dependency
tree.
2014-11-08 10:31:53 +09:00
Tatsuhiro Tsujikawa
1348621d9e Fix bug that priority is ignored if dependency parent does not exist 2014-11-08 10:18:10 +09:00
Tatsuhiro Tsujikawa
8c5ea61376 Merge branch 'LPardue-log_notice' 2014-11-07 21:21:21 +09:00
Tatsuhiro Tsujikawa
c410f4055f Merge branch 'log_notice' of https://github.com/LPardue/nghttp2 into LPardue-log_notice 2014-11-07 21:15:02 +09:00
Tatsuhiro Tsujikawa
1e86635572 h2load: Make shutdown sequence simpler 2014-11-07 00:28:10 +09:00
Tatsuhiro Tsujikawa
62ede05c09 Fix heap-use-after-free due to duplicated push of DATA item 2014-11-06 23:47:41 +09:00
Lucas Pardue
a067eb02a5 Add LOG_NOTICE level logging for application lifecycle events 2014-11-06 14:32:56 +00:00
Tatsuhiro Tsujikawa
154876a17b nghttpx: Apply TLS record length limit to DATA frame payload
This is not obvious but it makes intermediaries flush and forward DATA
frame boundary without excessive buffering.  Since we have different
TCP connections frontend and backend, this may not work.  This is
still experimental.
2014-11-06 21:14:14 +09:00
Tatsuhiro Tsujikawa
f8c70993c0 nghttpx: Adjust TLS record size dynamically
Use the same behaviour the current Google server does: start with 1300
TLS record size and after transmitting 1MiB, change record size to
16384.  After 1 second idle time, reset to 1300.  Only applies to
HTTP/2 and SPDY upstream connections.
2014-11-06 02:36:53 +09:00
Tatsuhiro Tsujikawa
03a2828fcf src: Disable SSL_MODE_ENABLE_PARTIAL_WRITE for apps which use libevent 2014-11-05 01:15:38 +09:00
Tatsuhiro Tsujikawa
2fc0056ada nghttp: Allow multiple -v option to increase verbosity
Now the number of -v option specifies verbosity level.  Current all
verbose output are turned on for at lest one -v option, except for the
debug output for each data chunk which is only turned on more than one
-v options.
2014-11-05 00:42:12 +09:00
Tatsuhiro Tsujikawa
9a33116526 Fix bug in priority tree
This change fixes the bug that stream is out of dependency tree if the
number of nodes in a dependency tree which we add new node to is
already maximum (NGHTTP2_MAX_DEP_TREE_LENGTH) and the number of
maximum concurrent streams is more than more than
NGHTTP2_MAX_DEP_TREE_LENGTH.
2014-11-05 00:32:16 +09:00
Tatsuhiro Tsujikawa
29fcd7c946 nghttpd: Use http2::Headers 2014-11-02 23:33:04 +09:00
Tatsuhiro Tsujikawa
189f122dd7 nghttpd: Perform redirect if directory is requested 2014-11-02 23:27:38 +09:00
Tatsuhiro Tsujikawa
69c708be44 Bump up version number to 0.6.6-DEV 2014-11-02 23:27:16 +09:00
Tatsuhiro Tsujikawa
14e56fcd81 Update man pages 2014-10-31 00:11:38 +09:00
Tatsuhiro Tsujikawa
db67412511 Bump up version number to 0.6.5, LT revision to 7:0:2 2014-10-31 00:05:09 +09:00
Tatsuhiro Tsujikawa
76800dc8e7 Remove unused functions 2014-10-30 23:31:36 +09:00
Tatsuhiro Tsujikawa
7d282cd0bd Code cleanup 2014-10-30 23:31:28 +09:00
Tatsuhiro Tsujikawa
49b8d1d88c Rename max_header_set_size as max_header_list_size 2014-10-30 22:42:15 +09:00
Tatsuhiro Tsujikawa
4d93dd9d91 Upate to draft-15
* Add NGHTTP2_HTTP_1_1_REQUIRED error code
* Allow transmission of WINDOW_UPDATE on reserved (remote)
* Allow reception of WINDOW_UPDATE on reserved (local)
* Treat frame larger than MAX_FRAME_SIZE as FRAME_SIZE_ERROR

ALPN identifier is still h2-14 to continue interop, since draft-14 and
-15 are binary compatible.  The new error code was added in draft-15,
but HTTP/2 allows extensions can freely add new error code, so it is
not a problem.
2014-10-30 22:40:02 +09:00
Tatsuhiro Tsujikawa
be1a513c59 nghttpx: Shut up scan-build 2014-10-30 22:36:22 +09:00
Tatsuhiro Tsujikawa
20900b133e nghttpx: Fix heap-use-after-free in ClientHandler object
This bug was found by scan-build
2014-10-30 21:47:38 +09:00
Tatsuhiro Tsujikawa
279fc2ad37 Update doc 2014-10-30 00:56:19 +09:00
Tatsuhiro Tsujikawa
0ef99b90d9 asio-lib: Make request_cb take const ref and use int64_t as http_date arg 2014-10-28 01:01:48 +09:00
Tatsuhiro Tsujikawa
1bd8f6a0e2 Update doc 2014-10-28 00:51:51 +09:00
Tatsuhiro Tsujikawa
f70c142e10 doc: Remove note about legacy NULL concatenation of header field 2014-10-28 00:39:46 +09:00
Tatsuhiro Tsujikawa
b3fbf047b2 Update man pages 2014-10-28 00:35:44 +09:00
Tatsuhiro Tsujikawa
0cd8da2cd9 Update doc 2014-10-28 00:18:28 +09:00
Tatsuhiro Tsujikawa
7fa0f2763e nghttpx: Update Alt-Svc header field spec to alt-svc-04 2014-10-28 00:17:32 +09:00
Tatsuhiro Tsujikawa
f381b13c91 mod a+x to auto-gen scripts 2014-10-27 21:27:41 +09:00
Tatsuhiro Tsujikawa
6b9382d865 Add comments to the auto-generated table 2014-10-27 21:27:03 +09:00
Tatsuhiro Tsujikawa
2c335dbc7a Add more comment about local window size adjustment 2014-10-27 21:24:41 +09:00
Tatsuhiro Tsujikawa
b3463b20a3 Update doc 2014-10-27 21:24:41 +09:00
Tatsuhiro Tsujikawa
15bdf048cc mkstatictbl.py: Update doc 2014-10-27 21:24:41 +09:00
Tatsuhiro Tsujikawa
992ca93533 mkhufftbl.py: Update doc 2014-10-27 21:24:41 +09:00
Tatsuhiro Tsujikawa
b4ed3324c0 mkcipherlist.py: Update doc 2014-10-27 21:24:41 +09:00
Tatsuhiro Tsujikawa
98fd6019cf man2rst.py: Add purpose of the script 2014-10-27 21:24:41 +09:00
Tatsuhiro Tsujikawa
6ccae48f7c man2rst.py: Add "DO NOT MODIFY THIS FILE!" comment 2014-10-27 21:24:41 +09:00
Tatsuhiro Tsujikawa
6933e0ef54 h2load: Use Headers instead of std::vector<std::pair<>> to store custom headers 2014-10-27 21:23:36 +09:00
Tatsuhiro Tsujikawa
a9ecdca08a h2load: Read URIs from stdin if -i- is used 2014-10-27 21:23:36 +09:00
Tatsuhiro Tsujikawa
af5bedd45f h2load: Move code pasing URIs to separate function 2014-10-27 21:23:36 +09:00
Tatsuhiro Tsujikawa
7097a31968 h2load: Uniform handling of URIs from command-line and file 2014-10-27 21:23:36 +09:00
Tatsuhiro Tsujikawa
4122920dc6 h2load: Fix doc and remove trailing spaces 2014-10-27 21:23:36 +09:00
Tatsuhiro Tsujikawa
9aed11e3dc Merge branch 'LPardue-master' 2014-10-27 21:22:21 +09:00
Lucas Pardue
9ea4905f68 Added X-Forwarded-For header stripping option to nghttpx 2014-10-27 10:23:20 +00:00
Tatsuhiro Tsujikawa
c6cfcc3c30 src: Disable insecure SSLv3 2014-10-22 23:14:07 +09:00
Tatsuhiro Tsujikawa
4bc5e55113 Merge branch 'kennypeng-header_add_override' 2014-10-22 21:30:31 +09:00
Tatsuhiro Tsujikawa
566a252577 Merge branch 'header_add_override' of https://github.com/kennypeng/nghttp2 into kennypeng-header_add_override 2014-10-22 21:25:53 +09:00
Kenny (kang-yen) Peng
27c766cb04 fix some comments and descriptions 2014-10-21 22:38:45 +00:00
Kenny (kang-yen) Peng
41dd6d0205 use option i to accept input URI list file 2014-10-21 22:29:36 +00:00
Kenny (kang-yen) Peng
db071ca35c fix comments of header add/override 2014-10-21 21:25:38 +00:00
Tatsuhiro Tsujikawa
e3af9d8bd3 nghttp: Use Headers to store custom headers 2014-10-21 23:24:50 +09:00
Tatsuhiro Tsujikawa
73955f0519 nghttp: Take advantage the fact that custom headers are already lower cased 2014-10-21 23:17:53 +09:00
Tatsuhiro Tsujikawa
5df21e3683 nghttp: Add missing metavar to -H and add example 2014-10-21 22:47:24 +09:00
Kenny (kang-yen) Peng
a6e1a40c05 support uri list file input 2014-10-20 20:59:55 +00:00
Tatsuhiro Tsujikawa
e330520341 Fix compile error on arm 2014-10-19 22:40:39 +09:00
Tatsuhiro Tsujikawa
d13ed04b17 Add Dockerfile.android 2014-10-19 21:51:43 +09:00
Tatsuhiro Tsujikawa
75a23c6c7e Add sample nghttpx logrotate configuration 2014-10-19 18:09:01 +09:00
Tatsuhiro Tsujikawa
eaca5d83b0 Add nghttpx init file for convenience 2014-10-19 18:06:34 +09:00
Tatsuhiro Tsujikawa
9c1b5e8fb1 Update .gitignore 2014-10-18 18:55:42 +09:00
Tatsuhiro Tsujikawa
0c31dbb5d9 Add aux script 2014-10-18 18:55:07 +09:00
Tatsuhiro Tsujikawa
8a0b11e9e1 Add aux script 2014-10-18 18:54:50 +09:00
Tatsuhiro Tsujikawa
7ca2787cc8 man2rst.py: Erase \& 2014-10-18 18:29:59 +09:00
Tatsuhiro Tsujikawa
cfbf907418 doc: Disable smartypants since we use '--' prefix for cmd options 2014-10-18 18:25:37 +09:00
Kenny Peng
dd02c4cd9b support header add/override 2014-10-17 15:25:59 -07:00
Tatsuhiro Tsujikawa
93ee5bdba6 REAMDE.rst: Add make and binutils to required ubuntu packages 2014-10-17 23:55:08 +09:00
Tatsuhiro Tsujikawa
f2aa6f4e2b nghttp: Document prioritization with -a option 2014-10-16 23:17:19 +09:00
Tatsuhiro Tsujikawa
bc8a583184 Refactor stream tree code 2014-10-16 21:59:52 +09:00
Tatsuhiro Tsujikawa
502ff24568 Avoid iterate siblings when adding/removing stream tree 2014-10-16 01:12:59 +09:00
Tatsuhiro Tsujikawa
47692d113c Bump up version number to 0.6.5-DEV 2014-10-14 23:49:10 +09:00
Tatsuhiro Tsujikawa
19c2805d0d Update man pages 2014-10-14 23:30:44 +09:00
Tatsuhiro Tsujikawa
df078dc004 Bump up version number to 0.6.4
Library code has not changed at all since the last release, so LT
revision stays the same.
2014-10-14 23:27:35 +09:00
Tatsuhiro Tsujikawa
e570225e97 tiny-nghttpd: Simplify timer event handling 2014-10-14 21:52:30 +09:00
Tatsuhiro Tsujikawa
8fffa05513 src: Fix possible heap-use-after free for OpenSSL global locking
This is simply programming error, but it is interesting that using
libstdc++ does not reveal this error.  With clang++-libc++, we got
std::system_error: mutex lock faild: Invalid argument.  This is
because we did not give a name to lock object, so it is immediately
destructed.  I think this will fix the reported crash on Mac OSX.
2014-10-14 21:47:07 +09:00
Tatsuhiro Tsujikawa
0d4120ce2c nghttpx: Apply same fix from a225bb2 to spdy upstream 2014-10-13 21:13:45 +09:00
Tatsuhiro Tsujikawa
20de432725 nghttpx: Pool http downstream connection per thread 2014-10-13 21:09:00 +09:00
Tatsuhiro Tsujikawa
325bb0115e Bump up version number to 0.6.4-DEV 2014-10-11 00:22:25 +09:00
Tatsuhiro Tsujikawa
cc3b41ec96 Bump up version number to 0.6.3, LT revision to 6:1:1 2014-10-11 00:08:32 +09:00
Tatsuhiro Tsujikawa
225b90eefd Use switch-case instead of if 2014-10-10 22:52:47 +09:00
Tatsuhiro Tsujikawa
3931a0b04d Fix bugs found by coverity scan 2014-10-10 22:50:35 +09:00
Tatsuhiro Tsujikawa
70c0558443 Set payload length when expected SETTINGS is not received 2014-10-10 21:46:02 +09:00
Tatsuhiro Tsujikawa
f2bfe623fc Update doc 2014-10-09 21:40:26 +09:00
Tatsuhiro Tsujikawa
80dcb565eb Check first SETTINGS strictly 2014-10-09 21:37:18 +09:00
Tatsuhiro Tsujikawa
6d42b6697b examples: Disable tiny-nghttpd if timerfd_create is not available 2014-10-09 21:18:24 +09:00
Tatsuhiro Tsujikawa
bcbb2e8649 src: Use fcntl and FD_CLOEXEC if O_CLOEXEC is undefined
We may run into race condition if execve is called at the same time
when fcntl is called.  But we just does this for now to compile
nghttp2 applications under older kernel.
2014-10-08 23:44:38 +09:00
Tatsuhiro Tsujikawa
ba92935f64 Define NOTHREADS if std:future is not available 2014-10-08 23:36:55 +09:00
Tatsuhiro Tsujikawa
402c262de5 Push stream to queue after effective weight was calculated 2014-10-08 22:44:02 +09:00
Tatsuhiro Tsujikawa
03c4092862 Distribute closed or blocked stream's weight to its siblings
This also means that at least one stream whose dpri is
NGHTTP2_STREAM_DPRI_TOP exists, its siblings descendants have no
chance to send streams, even if their parent stream has
NGHTTP2_STREAM_DPRI_NODATA.
2014-10-07 23:52:36 +09:00
Tatsuhiro Tsujikawa
a225bb29df nghttpx: Fix request is sent to backend prematurely with http2 upstream 2014-10-07 00:31:35 +09:00
Tatsuhiro Tsujikawa
f3a76d84f1 Document that only one data is allowed for one stream at a time 2014-10-06 23:47:43 +09:00
Tatsuhiro Tsujikawa
7a09feebc3 h2load: Don't use std::future with --disable-threads
Now we don't use std::future with --disable-threads, checking
std::future in configure.ac was removed and building h2load is always
enabled.
2014-10-05 14:25:15 +09:00
Tatsuhiro Tsujikawa
32ddca532a Use 256 elements table in nghttp2_downcast 2014-10-04 00:40:51 +09:00
Svante Signell
df875db989 Avoid PATH_MAX by using getcwd(nullptr, 0) as supported by modern glibc-based OSes. 2014-10-03 21:58:15 +09:00
Tatsuhiro Tsujikawa
1d138accb9 Unify DATA and other frames in nghttp2_outbound_item and save malloc() 2014-10-03 21:31:37 +09:00
Tatsuhiro Tsujikawa
7e6019aef1 nghttp2_hd: Don't malloc if name/value is in first chunk without indexing 2014-09-30 23:01:58 +09:00
Tatsuhiro Tsujikawa
e20b417b84 Embed aux_data to nghttp2_outbound_item so that we can save some malloc() calls 2014-09-30 21:45:15 +09:00
Tatsuhiro Tsujikawa
df56b69060 nghttp2_map: Use initial size 256 so that we don't resize it until 100 streams 2014-09-29 22:46:13 +09:00
Tatsuhiro Tsujikawa
b6d0a32d0e tiny-nghttpd: Save number of read(2) calls using file size 2014-09-29 22:37:41 +09:00
Tatsuhiro Tsujikawa
a82956d1d6 nghttp2_hd: Use binary search to lookup static table (again) 2014-09-29 21:58:37 +09:00
Tatsuhiro Tsujikawa
9c0760e3c1 Bump up version number to 0.6.3-DEV 2014-09-29 00:08:21 +09:00
Tatsuhiro Tsujikawa
4e71e9e2e8 Update man pages 2014-09-28 23:34:07 +09:00
Tatsuhiro Tsujikawa
521450c7ad Bump up version number to 0.6.2, LT revision to 6:0:1 2014-09-28 23:33:10 +09:00
Tatsuhiro Tsujikawa
aa57e91e85 Fix make distcheck 2014-09-28 23:29:57 +09:00
Tatsuhiro Tsujikawa
4023c26cf1 Update doc 2014-09-28 23:24:39 +09:00
Tatsuhiro Tsujikawa
a0f558ee3c doc: Add example to use nghttp2::asio_http2::server::request::run_task 2014-09-28 16:55:32 +09:00
Tatsuhiro Tsujikawa
4f0d03b4b9 libnghttp2_asio: Move common types and functions to nghttp2::asio_http2 ns 2014-09-28 16:54:00 +09:00
Tatsuhiro Tsujikawa
88d7abcc23 libnghttp2_asio: Add request::run_task to execute task in separate thread 2014-09-28 16:25:45 +09:00
Tatsuhiro Tsujikawa
409316018d examples: Fix travis error: unreachable-code 2014-09-28 00:02:13 +09:00
Tatsuhiro Tsujikawa
d25b9da9f6 Check Boost library only when it is requested 2014-09-27 23:50:33 +09:00
Tatsuhiro Tsujikawa
b48ceac56c nghttp2_hd: Search dynamic table first
Since recently used headers are in dynamic header table, it is
advantageous to search dynamic table first, saving time to search
through static table.
2014-09-27 23:45:58 +09:00
Tatsuhiro Tsujikawa
34413d8d7c examples: Build tiny-nghttpd only when epoll is available 2014-09-27 23:45:57 +09:00
Tatsuhiro Tsujikawa
b7ccca4c47 examples: Add tiny-nghttpd
tiny-nghttpd is HTTP/2 server and its purpose is measure the
performance of nghttp2 library code.  Currently it only accepts direct
HTTP/2 connection only.
2014-09-27 23:44:33 +09:00
Tatsuhiro Tsujikawa
e887b2516f Remove boost LDFLAGS from examples 2014-09-26 21:42:31 +09:00
Tatsuhiro Tsujikawa
be0f6dcaaf Clear 2 types of stream deferred flag indenpendently
Previously when nghttp2_stream_resume_deferred_data() is called,
deferred flags in stream->flags are all cleared.  This is not ideal
because if application returned NGHTTP2_ERR_DEFERRED, and also that
stream is deferred by flow control, then all flags are cleared and
read callback will be invoked again.  This commit fixes this issue.
This changes error condition of nghttp2_session_resume_data().
Previously we return error if stream was deferred by flow control.
Now we don't return error in this case.  We just clear
NGHTTP2_FLAG_DEFERRED_USER and if still
NGHTTP2_FLAG_DEFERRED_FLOW_CONTROL is set, just return 0.
2014-09-26 21:32:17 +09:00
Tatsuhiro Tsujikawa
937bb9f768 Update doc 2014-09-26 01:25:00 +09:00
Tatsuhiro Tsujikawa
a11fbf6e2f Optimize connection level remote flow control
Previously when connection level remote flow control window gets 0, we
mark the stream having DATA frame with
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL.  When connection level
WINDOW_UPDATE is received, we checks all existing streams, including
closed ones, and call nghttp2_stream_resume_deferred_data().  The
profiler shows this is expensive.

Now we prepare dedicated priority queue for DATA frames.  And we don't
mark stream with NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL when DATA
cannot be sent solely due to connection level flow control.  Instead,
we just queue DATA item to queue.  We won't pop DATA item from queue
when connection level remote window size is 0.  This way, we avoid the
expensive operation for all streams when WINDOW_UPDATE is arrived.
2014-09-26 00:01:51 +09:00
Tatsuhiro Tsujikawa
9aa914c756 Update README.rst 2014-09-25 02:08:09 +09:00
Tatsuhiro Tsujikawa
e20d2ba9c1 nghttpx: Don't send x-forwarded-proto if -s or -p is used 2014-09-25 00:41:38 +09:00
Tatsuhiro Tsujikawa
c1be28684a libnghttp2_asio: Add request::closed() to indicate that stream has been closed 2014-09-25 00:15:52 +09:00
Tatsuhiro Tsujikawa
fd07f5e142 src: Add utility APIs to asio_http2.h; add asio-sv2 example to serve files 2014-09-24 23:05:13 +09:00
Tatsuhiro Tsujikawa
99ca15cae0 Lower boost version requirement to 1.54.0 2014-09-24 21:07:37 +09:00
Tatsuhiro Tsujikawa
3651467c71 src: Silence compiler warning 2014-09-24 00:57:43 +09:00
Tatsuhiro Tsujikawa
c27ec6f57b doc: Add doc how to enable multi threading in libnghttp2_asio 2014-09-24 00:45:40 +09:00
Tatsuhiro Tsujikawa
485d04851c Add libnghttp2_asio.pc to .gitignore 2014-09-24 00:45:40 +09:00
Tatsuhiro Tsujikawa
83728219db Update doc 2014-09-24 00:45:40 +09:00
Tatsuhiro Tsujikawa
5d0bf4cc84 Add C++ library libnghttp2_asio on top of libnghttp2
The libnghttp2_asio library is C++ library built on top of libnghttp2.
Currently, it has server API and easily create HTTP/2 server using
node.js like API calls.  See the example server source code in
examples/asio-sv.cc.  The library depends on Boost::ASIO library.
2014-09-24 00:45:40 +09:00
Tatsuhiro Tsujikawa
446f8f13aa src: Move libevent related helper functions to libevent_util 2014-09-24 00:45:40 +09:00
Tatsuhiro Tsujikawa
96bb9c2018 Move Makefile.msvc under lib 2014-09-24 00:44:45 +09:00
Tatsuhiro Tsujikawa
a9b74261b6 nghttpd: Rewrite using bufferevent (again) for simplicity 2014-09-19 00:58:32 +09:00
Tatsuhiro Tsujikawa
89c3c08590 tests: Fix compiler warning 2014-09-19 00:20:54 +09:00
Tatsuhiro Tsujikawa
83309b6391 nghttpx: Reduce epoll_ctl call 2014-09-18 23:56:01 +09:00
Tatsuhiro Tsujikawa
23dd428d65 nghttpx: Reset timeouts when either read or write succeeds
See previous commit message why we need this.
2014-09-18 23:19:28 +09:00
Tatsuhiro Tsujikawa
b305495a75 nghttpx: Reset both timeouts when either read or write succeeds
Previously read and write timeouts work independently.  When we are
writing response to the client, read timeout still ticks (e.g., HTTP/2
or tunneled HTTPS connection).  So read timeout may occur during long
download.  This commit fixes this issue.  This commit only fixes the
upstream part.  We need similar fix for the downstream.
2014-09-18 23:03:36 +09:00
Tatsuhiro Tsujikawa
727662257c Add missing NGHTTP2_ERR_BAD_PREFACE to nghttp2_strerror 2014-09-17 23:25:47 +09:00
Tatsuhiro Tsujikawa
b2f88f8fe3 Fix memory leak around stream->data_item
Previously we missed the case where stream->data_item is not deleted
and it caused leak.  Now stream->data_item is properly deleted when
session is deleted.  We decided not to delete data_item in
nghttp2_stream_free() since we need nghttp2_session to decide whether
data_item should be deleted or not there.
2014-09-17 23:16:00 +09:00
Tatsuhiro Tsujikawa
44ac571037 nghttpx: Add more handling situation where response ends before request 2014-09-17 22:53:29 +09:00
Tatsuhiro Tsujikawa
5bff48a15a nghttpx: Call upstream resume_read after sending pending request to backend
With the combination of HTTP/1 upstream and HTTP/2 downstream,
downstream tells SHRPX_NO_BUFFER while connecting to the backend
server.  Previously, we did not call upstream resume_read and upload
was blocked.  This commit now calls upstream resume_read to unblock.
This commit also remove pending output buffer size of Http2Session
when calculating downstream connection's buffer is full.  This is
desirable since we only operate resume_read by stream basis.
2014-09-17 22:36:42 +09:00
Tatsuhiro Tsujikawa
e4751a798a Replace auto_delete* with defer 2014-09-16 23:39:38 +09:00
Tatsuhiro Tsujikawa
6fc12caa6d Just link to github releases page for released versions 2014-09-14 22:46:59 +09:00
Tatsuhiro Tsujikawa
d00d4d647d Compile with android NDK r10b 32bit target
Android does not have _Exit.  We detect this and use _exit instead.
clang-3.4 has an issue around undefined reference to
__atomic_fetch_add_4, so we stick to gcc-4.8 for now.
2014-09-14 21:32:53 +09:00
Tatsuhiro Tsujikawa
5ff73de195 libevent-server: Use nghttp2_option_set_recv_client_preface() 2014-09-13 21:24:45 +09:00
Tatsuhiro Tsujikawa
901de5fbce Add nghttp2_option_set_recv_client_preface()
By default, nghttp2 library only handles HTTP/2 frames and does not
recognize first 24 bytes of client connection preface. This design
choice is done due to the fact that server may want to detect the
application protocol based on first few bytes on clear text
communication. But for simple servers which only speak HTTP/2, it is
easier for developers if nghttp2 library takes care of client
connection preface.

If this option is used with nonzero val, nghttp2 library checks first
24 bytes client connection preface. If it is not a valid one,
nghttp2_session_recv() and nghttp2_session_mem_recv() will return
error NGHTTP2_ERR_BAD_PREFACE, which is fatal error.
2014-09-13 19:50:44 +09:00
Tatsuhiro Tsujikawa
5847a56c40 Bump up version number to 0.6.2-DEV 2014-09-11 00:36:56 +09:00
Tatsuhiro Tsujikawa
0da0140026 Update man pages 2014-09-11 00:31:02 +09:00
Tatsuhiro Tsujikawa
207b1db6af Bump up version number to 0.6.1 2014-09-11 00:28:48 +09:00
Tatsuhiro Tsujikawa
85f605f20d src: Check availability of ENONET 2014-09-02 01:00:27 +09:00
Tatsuhiro Tsujikawa
5cf07f5c21 Bump up version number to 0.6.1-DEV 2014-08-30 00:18:25 +09:00
Tatsuhiro Tsujikawa
340b52da84 Update man pages 2014-08-30 00:15:31 +09:00
Tatsuhiro Tsujikawa
3de678e164 Bump up version number to 0.6.0 and LT revision to 5:0:0 2014-08-30 00:09:37 +09:00
Tatsuhiro Tsujikawa
0af71ee6be Update sphinx_rtd_theme 2014-08-30 00:07:48 +09:00
Tatsuhiro Tsujikawa
d8c0d87c90 src: Add missing SETTINGS ID to debug output
SETTINGS_MAX_FRAME_SIZE and SETTINGS_MAX_HEADER_LIST_SIZE are 2
missing SETTINGS IDs and now they are shown correctly.
2014-08-29 00:14:10 +09:00
Tatsuhiro Tsujikawa
9b2c24ad68 tests: Remove debug output 2014-08-28 23:32:14 +09:00
Tatsuhiro Tsujikawa
b4bb6a6101 Add reserved bits to header and frames
Currently reserved bit is always set to 0.  The addition of reserved
bit is for future extension.
2014-08-28 23:30:42 +09:00
Tatsuhiro Tsujikawa
8890e593e6 src: Add util::array_size 2014-08-28 00:45:12 +09:00
Tatsuhiro Tsujikawa
ec0a2e7cca Add Makefile for MSVC
Contributed by G. Vanem
2014-08-27 23:54:29 +09:00
Tatsuhiro Tsujikawa
f8471a5f45 nghttpx: Move --backend-http-proxy-uri to Connections section 2014-08-27 23:37:54 +09:00
Tatsuhiro Tsujikawa
f34cbf9b45 tests: Include config.h 2014-08-27 23:36:57 +09:00
Tatsuhiro Tsujikawa
a23a705121 nghttpx: Strict integer config validation 2014-08-27 23:36:36 +09:00
Tatsuhiro Tsujikawa
822ec75814 nghttpx: Add --listener-disable-timeout option 2014-08-27 22:34:00 +09:00
Tatsuhiro Tsujikawa
0209b7c083 nghttpx: Fix location rewrite is failed because request headers are empty
Previously we empties request headers after they are sent to
downstream in order to free memory.  But it turns out that we use
request headers when rewriting location header response field.  Also
user reported that request headers are useful to add new features.
This commits defers the deletion of request headers to the point when
response headers are deleted (which is after response headers are sent
to upstream client).
2014-08-27 21:25:25 +09:00
Tatsuhiro Tsujikawa
70a8fd59b1 python: Add version 2014-08-26 23:52:19 +09:00
Tatsuhiro Tsujikawa
223242b512 nghttpx: Don't consume response data in downstream on_stream_close_callback
Even after on_stream_close_callback, Http2DownstreamConnection is
still alive and upstream keeps sending response to the client.  The
consumed bytes are processed normally (data_source_read_callback) and
also we have a code to consume all allocated bytes for
Http2DownstreamConnection object when it is deleted.  This means that
we don't need to and should not consume response data in downstream
on_stream_close_callback.  If we do, we may get assertion error in
Http2DownstreamConnection::resume_read().
2014-08-26 22:16:19 +09:00
Tatsuhiro Tsujikawa
42ac80d3da python: Fix build error 2014-08-26 00:13:53 +09:00
Tatsuhiro Tsujikawa
4c11cd0671 Add test to submit DATA frame twice
This commit adds test to submit DATA frame twice and fixes the bug
that 2nd DATA is not sent.
2014-08-25 23:46:17 +09:00
Tatsuhiro Tsujikawa
4c5c6749a0 Check buffer capacity explicitly 2014-08-25 23:12:17 +09:00
Tatsuhiro Tsujikawa
dd038bf753 Fix crash when buffer was reallocated after read_length_callback
Added test for this crash.
2014-08-25 23:05:39 +09:00
Tatsuhiro Tsujikawa
577512f2ca Use datamax if buffer reallocation failed 2014-08-25 22:46:55 +09:00
Tatsuhiro Tsujikawa
565c635e9b Wrap longer lines (> 80) 2014-08-25 22:41:34 +09:00
Tatsuhiro Tsujikawa
0b1ab90fb8 Move frame_type parameter in front of stream_id
This commit moves frame_type parameter of
nghttp2_data_soruce_read_length_callback in front of stream_id
parameter.  The motivation is that other callback is generally put
frame related parameters first.  To make it consistent, we move
frame_type, which is frame ralted parameter, to the left.
2014-08-25 22:31:11 +09:00
Tatsuhiro Tsujikawa
93b4d9efc3 Allow application to call nghttp2_submit_data() in on_frame_send_callback
Previously we always call on_frame_send_callback before calling
nghttp2_stream_detach_data() after sending DATA frame.  As a result,
even if DATA frame has END_STREAM, application cannot call
nghttp2_submit_data() in on_frame_send_callback because previous data
is still attached.  This commit makes a change so that
nghttp2_stream_detach_data() is called before on_frame_send_callback
so that application can issue nghttp2_submit_data() in the callback.
2014-08-25 21:53:40 +09:00
Tatsuhiro Tsujikawa
82bc7198e6 Change nghttp2_session_get_stream_remote_window_size behavior
Now it returns only stream's available remote window size, without
considering connection level window size.  For connection-level window
size, nghttp2_session_get_remote_window_size() is added by this
commit.  To get old behavior of
nghttp2_session_get_stream_remote_window_size() is use
min(nghttp2_session_get_stream_remote_window_size(),
nghttp2_session_get_remote_window_size()).  The reason of this change
is that it is desirable to know just stream level window size without
taking into connection level window size.  This is useful for
debugging purpose.
2014-08-25 21:44:22 +09:00
Tatsuhiro Tsujikawa
03ed29953e Move nghttp2_data_source_read_length_callback to session callbacks section
Also edited its documentation to make hyperlink works.
2014-08-25 21:38:08 +09:00
Tatsuhiro Tsujikawa
a36c4c6f5f Add nghttp2_on_begin_frame_callback
nghttp2_on_begin_frame_callback will be invoked when a frame header is
received.
2014-08-25 21:26:50 +09:00
Tatsuhiro Tsujikawa
3daa6f2c30 doc: Update tutorials 2014-08-25 21:24:04 +09:00
Tatsuhiro Tsujikawa
53ee21caa9 Remove nghttp2_on_unknown_frame_recv_callback
It is not used by library for a while.  It could be used to pass
unsupported extension frames to application, but its interface
requires library to buffer entire frame, which we'd like to avoid.
For unsupported extension frames, we will add new callbacks which does
not require buffering if they are required.
2014-08-25 21:24:04 +09:00
Tatsuhiro Tsujikawa
31528b6267 Use uint32_t for HTTP/2 error_code
h2-14 now allows extensions to define new error codes.  To allow
application callback to access such error codes, we uses uint32_t as
error_code type for structs and function parameters.  Previously we
treated unknown error code as INTERNAL_ERROR, but this change removes
this and unknown error code is passed to application callback as is.
2014-08-25 21:24:04 +09:00
Tatsuhiro Tsujikawa
ab5b81bee1 Hide nghttp2_session_callbacks details and provide setter like functions
To make it possible to add new callbacks without bumping so name, we
decided to hide details of nghttp2_session_callbacks.  We provide
setter like functions to set individual callback function.
2014-08-25 21:24:04 +09:00
Tatsuhiro Tsujikawa
9f6bb989e3 Merge branch 'akamai-window_size_control' 2014-08-25 21:15:38 +09:00
Tatsuhiro Tsujikawa
3655090997 Merge branch 'window_size_control' of https://github.com/akamai/nghttp2 into akamai-window_size_control 2014-08-25 21:09:26 +09:00
Scott Mitchell
3cd08251ca Send window size API extension
Motivation:

The send window size is currently fixed by a macro at compile time.
In order for users of the library to impact the send window size they
would have to change a macro at compile time. The window size may be dynamic
depending on the environment and deployment scheme. The library users
currently have no way to change this parameter.

Modifications:

Add a new optional callback method which is called before data is sent to
obtain the desired send window size. The callback return value will be
subject to a range check for the current session, stream, and settings
limits defined by flow control.

Result:
Library users have control over their send sizes.
2014-08-24 11:32:44 -04:00
Tatsuhiro Tsujikawa
1673ae2c99 src: Add 308 Permanent Redirect (RFC 7238) 2014-08-24 22:56:48 +09:00
Tatsuhiro Tsujikawa
bf48ef9bab Add test to check consumed size when no auto window update is enabled 2014-08-24 22:36:35 +09:00
Tatsuhiro Tsujikawa
1093b3eeab Check explicitly that padding field is really read 2014-08-24 22:29:05 +09:00
Tatsuhiro Tsujikawa
d5da7611fa nghttpx: Remove unused member function and variable 2014-08-24 22:27:10 +09:00
Tatsuhiro Tsujikawa
9893ae81af Add nghttp2_bufs_realloc 2014-08-24 15:34:55 +09:00
Tatsuhiro Tsujikawa
7bfa276e96 Fix bug that NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE causes session failure
Previously returning NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE from
on_header_callback moves input offset badly and it causes header
decompression error on the subsequent frames.  This commit fix this
bug.
2014-08-24 00:50:55 +09:00
Tatsuhiro Tsujikawa
02c5621c61 Refactor functions to update consumed size 2014-08-23 18:56:04 +09:00
Tatsuhiro Tsujikawa
9ad2c0887e nghttpx: Use _Exit() instead of exit() when execve is failed in child process 2014-08-23 18:15:47 +09:00
Tatsuhiro Tsujikawa
0c7e2fbec6 Use parenthesis explicitly for bit wise operation 2014-08-23 18:03:20 +09:00
Tatsuhiro Tsujikawa
cfee9cab36 Avoid possible double-free and make nghttp2_buf{s}_free(NULL) success 2014-08-23 11:16:49 +09:00
Tatsuhiro Tsujikawa
679a0a0fa1 README.rst: Require spdylay >= 1.3.0 2014-08-21 22:50:19 +09:00
Tatsuhiro Tsujikawa
d5dcbf6f3b nghttpx: Fix possible flow control issue
Previously we only update consumed flow control window when number of
bytes read in nghttp2 and spdylay callback is 0.  Now we notify
nghttp2 library the consumed bytes even if number of bytes read > 0.
This change also uses newly added spdylay_session_consume() API, so we
require spdylay >= 1.3.0.
2014-08-21 21:22:16 +09:00
Tatsuhiro Tsujikawa
69b9ce6b68 nghttpx: Fix possible deadlock due to exhaustion of send window 2014-08-20 01:39:07 +09:00
Tatsuhiro Tsujikawa
c81e87bf37 nghttpx: Fix dereference after null check 2014-08-20 00:17:50 +09:00
Tatsuhiro Tsujikawa
97533c966d nghttpx: Fix gcc compiler warning 2014-08-20 00:09:18 +09:00
Tatsuhiro Tsujikawa
d6b495f2a7 nghttpx: Returns 503 if downstream connect fail for https upstream 2014-08-19 23:41:53 +09:00
Tatsuhiro Tsujikawa
c7e9fe8154 nghttpx: Implement connection blocker for HTTP/1 backend 2014-08-19 23:36:04 +09:00
Tatsuhiro Tsujikawa
fb62a5ed4f nghttpx: Use pointer for worker_config 2014-08-19 22:29:44 +09:00
Tatsuhiro Tsujikawa
345121975a nghttpx: Handle socket creation error 2014-08-19 22:29:44 +09:00
Tatsuhiro Tsujikawa
a5dfe24e49 nghttpx: Use std::unique_ptr for DownstreamConnection 2014-08-19 00:20:57 +09:00
Tatsuhiro Tsujikawa
273d9f4f7d nghttpx: Use std::unique_ptr for Downstream object 2014-08-19 00:20:56 +09:00
Tatsuhiro Tsujikawa
500c5eea56 nghttpx: Rename Http2Upstream::add_downstream as add_pending_downstream 2014-08-18 21:38:03 +09:00
Tatsuhiro Tsujikawa
83a39f5b49 nghttpx: Fix stream handling of upgraded request 2014-08-18 21:36:55 +09:00
Tatsuhiro Tsujikawa
2fb675f13c nghttpx: Open default log files for errors occurred while parsing options 2014-08-17 22:37:30 +09:00
Tatsuhiro Tsujikawa
eebd1f5492 nghttpx: Add some more info about prohibition of --read-burst=0 2014-08-17 22:31:44 +09:00
Tatsuhiro Tsujikawa
00ead22395 Don't allow frame submission for pending new frame
This is partial revert of bbe4f5a3d1.
Only documentation is reverted.  Since we have 2 queues to handle
maximum concurrent streams, we are not ready to allow immediate frame
submission for pending new frames.
2014-08-17 21:26:56 +09:00
Tatsuhiro Tsujikawa
2b4bd57c7f doc: Add building-android-binary document 2014-08-17 19:15:19 +09:00
Tatsuhiro Tsujikawa
86dd1519b4 nghttpx: Android specific hack for special files for logging
Android lacks /dev/stderr, so directly use /proc/self/fd/2 as default
errorlog-file.  Android does not like O_APPEND for /proc/self/fd/1 and
/proc/self/fd/2, so omit the flag for these paths.
2014-08-17 19:01:51 +09:00
Tatsuhiro Tsujikawa
a507fc80b6 Isolate std::future when NOTHREADS is defined and build without SOCK_{NONBLOCK, CLOEXEC} 2014-08-17 18:50:10 +09:00
Tatsuhiro Tsujikawa
69c3920a1a android-config: Disable libxml2 for user build, use long clang names 2014-08-17 18:49:21 +09:00
Tatsuhiro Tsujikawa
bbe4f5a3d1 Allow frame submission immediately after nghttp2_submit_{request,headers,pp}
This commit makes handling of outgoing HEADERS and PUSH_PROMISE in the
same priority of other frames on the stream, so these frames are
processed in the order they are submitted.  This allows application to
submit frames to a stream returned by nghttp2_submit_{request,
headers, push_promise} immediately.  The only exception is
WINDOW_UPDATA frame, which requires nghttp2_stream object, which is
not created yet.
2014-08-17 17:31:43 +09:00
Tatsuhiro Tsujikawa
49a9ec2cb3 nghttpx: Use int for resonse_rst_stream_error_code_ 2014-08-17 16:36:02 +09:00
Tatsuhiro Tsujikawa
5d2390deba nghttpx: Bring per-connection rate limit back
--read-burst=0 still does not work.  But specifying n > 0 workarounds
this.
2014-08-17 16:17:10 +09:00
Tatsuhiro Tsujikawa
02c347fe6b Add text dealing license around contribution to COPYING 2014-08-17 15:10:57 +09:00
Tatsuhiro Tsujikawa
3c056973a1 nghttpx: Ignore SIGCHLD not to create zombie on SIGUSR2 if -D is used 2014-08-17 00:05:24 +09:00
Tatsuhiro Tsujikawa
d17f35a488 Add Contribution section to README.rst 2014-08-16 23:23:52 +09:00
Tatsuhiro Tsujikawa
1b8ad61779 doc: Add note how to re-open log files in nghttpx 2014-08-16 23:00:35 +09:00
Tatsuhiro Tsujikawa
ede801d099 doc: Update man pages 2014-08-16 22:54:15 +09:00
Tatsuhiro Tsujikawa
9649b2d346 doc: Fix typo 2014-08-16 22:53:12 +09:00
Tatsuhiro Tsujikawa
53e52194b5 Bump up version number to 0.6.0-DEV 2014-08-16 22:50:33 +09:00
Tatsuhiro Tsujikawa
0e8419ac37 nghttpx: Add backend-connections-per-frontend option
This option limits the number of backend connections per frontend.
This is meaningful for the combination of HTTP/2 and SPDY frontend and
HTTP/1 backend.
2014-08-16 22:24:17 +09:00
Tatsuhiro Tsujikawa
da08ba5d50 nghttpx: Reset upstream timer on upgrade 2014-08-15 10:29:46 +09:00
Tatsuhiro Tsujikawa
30fa6d24d0 nghttpx: Rewirte server header field if configured as reverse proxy 2014-08-14 22:45:21 +09:00
Tatsuhiro Tsujikawa
f776c50d43 nghttpx: Just record error code when RST_STREAM is received
libnghttp2 will call on_stream_close callback when RST_STREAM is
received.  So we can use on_stream_close callback to handle existing
stream, instead of on_frame_recv callback.
2014-08-14 12:48:30 +09:00
Tatsuhiro Tsujikawa
7b85f6c50d nghttpx: Store errno to a variable temporarly 2014-08-13 22:13:08 +09:00
Tatsuhiro Tsujikawa
21cbf417c8 nghttpx: Use SOCK_NONBLOCK and SOCK_CLOEXEC flag in socketpair to avoid race 2014-08-13 22:09:35 +09:00
Tatsuhiro Tsujikawa
ca680c16e3 nghttpx: Chown file to effective user 2014-08-13 01:53:44 +09:00
Tatsuhiro Tsujikawa
bf13d91264 nghttpx: Add hot deploy feature
nghttpx supports hot deploy feature using signals.  The host deploy 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
current and new processes can accept requests.  To gracefully shutdown
current process, send QUIT signal to current nghttpx process.  When
all existing frontend connections are done, the current process will
exit.  At this point, only new nghttpx process exists and serves
incoming requests.
2014-08-13 00:43:54 +09:00
Tatsuhiro Tsujikawa
8aa6580d89 nghttpx: Chown log files with --user 2014-08-10 20:58:02 +09:00
Tatsuhiro Tsujikawa
11fa71ba6c Update doc 2014-08-10 18:05:24 +09:00
Tatsuhiro Tsujikawa
58afce2382 nghttp: Verbose output for received DATA chunk with current received window 2014-08-10 17:18:28 +09:00
Tatsuhiro Tsujikawa
24cfb52b5a nghttpx: Add --no-location-rewrite option
--no-location-rewrite option disallows location header rewrite on
--http2-bridge, --client and default mode.  This option is useful when
connecting nghttpx proxy with --http2-bridge to backend nghttpx with
http2-proxy mode.
2014-08-10 12:39:27 +09:00
Tatsuhiro Tsujikawa
d499803221 Fix another heap-use-after-free bug 2014-08-10 12:20:36 +09:00
Tatsuhiro Tsujikawa
894783f572 Add note how to specify error code on NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE 2014-08-10 00:18:41 +09:00
Tatsuhiro Tsujikawa
93ed89df5f nghttpx: Make stream timeout disable by default
It might be useful to clean the unused stream out to make up the room
for new streams.  On the other hand, proxy should maintain the
connection between upstream client and downstream server and they have
the timeout for their own.  Proxy just reacts to their decision.
2014-08-10 00:08:44 +09:00
Tatsuhiro Tsujikawa
1a2e50ca08 nghttpx: Lower timeouts 2014-08-09 22:59:31 +09:00
Tatsuhiro Tsujikawa
76703f79fa nghttpx: Add stream level timeout for HTTP/2 and SPDY upstream/downstream 2014-08-09 22:56:27 +09:00
Tatsuhiro Tsujikawa
4679188069 Fix crash 2014-08-09 18:41:08 +09:00
Tatsuhiro Tsujikawa
4c3aa081a0 nghttp: Improve error logging a bit 2014-08-09 00:03:33 +09:00
Tatsuhiro Tsujikawa
ab9b0538bc Add doc how to issue non-final response headers 2014-08-08 23:38:20 +09:00
Tatsuhiro Tsujikawa
24edd2972d Remove note about 0x00 concatenation rule and add note about pseudo-headers 2014-08-08 23:32:45 +09:00
Tatsuhiro Tsujikawa
a8b7fa524f Merge branch 'alagoutte-travis' 2014-08-08 23:15:42 +09:00
Tatsuhiro Tsujikawa
b827b99b2f Merge branch 'travis' of https://github.com/alagoutte/nghttp2 into alagoutte-travis 2014-08-08 23:14:58 +09:00
Tatsuhiro Tsujikawa
88add854ff nghttpx: Treat malformed request as PROTOCOL_ERROR 2014-08-08 23:11:58 +09:00
Tatsuhiro Tsujikawa
704bbbfcaa nghttpx: Fail if :status is not digits on http2 downstream 2014-08-08 23:08:24 +09:00
Tatsuhiro Tsujikawa
e217e789de nghttp: Support non-final response and check pseudo headers 2014-08-08 23:03:12 +09:00
Tatsuhiro Tsujikawa
d4d56e1846 nghttpd, nghttpx: Check that pseudo headers come before normal headers 2014-08-08 20:52:32 +09:00
Alexis La Goutte
8883df2fd6 Add make check to Travis 2014-08-08 13:20:48 +02:00
Tatsuhiro Tsujikawa
d496c42dc9 Revert "nghttpx, nghttpd: Check pseudo header fields come before normal header fields"
This reverts commit cc24b9aaf0.
2014-08-08 20:17:03 +09:00
Alexis La Goutte
8433a75a6b Travis : Disable GCC build (don't work with GCC travis release) 2014-08-08 13:14:18 +02:00
Tatsuhiro Tsujikawa
76b3ba2832 nghttp: Sort request header fields using http2::name_less 2014-08-08 00:27:04 +09:00
Tatsuhiro Tsujikawa
05f982dcfb src: Sort header fields so that pseudo headers come first 2014-08-07 23:27:13 +09:00
Tatsuhiro Tsujikawa
cc24b9aaf0 nghttpx, nghttpd: Check pseudo header fields come before normal header fields 2014-08-07 22:49:34 +09:00
Tatsuhiro Tsujikawa
e6695d9ba7 nghttp: Check HTTP header field characters 2014-08-07 22:01:00 +09:00
Tatsuhiro Tsujikawa
9fb2bc8468 src: Remove http2::sort_nva
This function is no longer necessary because 0x00 concatenation rule
is gone.
2014-08-07 21:55:30 +09:00
Tatsuhiro Tsujikawa
6ccf06c6da nghtp2_hd: Calculate hash values once 2014-08-06 22:00:12 +09:00
Tatsuhiro Tsujikawa
49e3fd6862 Add some header names which won't be indexed 2014-08-06 21:50:54 +09:00
Tatsuhiro Tsujikawa
9c1a956e47 hpackcheck.py: Remove sorting to check ordering requirements 2014-08-06 20:34:51 +09:00
Tatsuhiro Tsujikawa
86b089f957 Fix buffer overrun in raw_sbuf 2014-08-06 01:49:36 +09:00
Tatsuhiro Tsujikawa
3f212a60a5 nghttpx: Fix android build error 2014-08-06 00:23:46 +09:00
Tatsuhiro Tsujikawa
5c61917007 src: Move jemalloc front so that it is surely linked 2014-08-05 22:27:54 +09:00
Tatsuhiro Tsujikawa
8736f61fbd Detect static libjemalloc
libjemalloc as static library requires -pthread flag to link.  Without
that, the check in configure.ac fails with unresolved symbols.
2014-08-05 21:49:50 +09:00
Tatsuhiro Tsujikawa
04e94824a0 Merge branch 'alagoutte-misc' 2014-08-05 01:06:15 +09:00
Alexis La Goutte
ec93c9f55f Fix some other shorten-64-to-32 casting error found by MSVC (64bits)
Thanks to Pascal
2014-08-04 09:04:49 +02:00
Alexis La Goutte
6c71889552 Fix some other shorten-64-to-32 casting error found by MSVC (64bits) 2014-08-03 16:09:30 +02:00
Tatsuhiro Tsujikawa
4bbb4172aa Fix typo 2014-08-03 14:07:35 +09:00
Tatsuhiro Tsujikawa
9ccf4c037d Update README.rst 2014-08-03 01:08:42 +09:00
Tatsuhiro Tsujikawa
1f356391f1 Update README.rst 2014-08-03 00:52:40 +09:00
Tatsuhiro Tsujikawa
3c603ec4ae add_hd_table_incremental: Remove unused bufs parameter 2014-08-02 16:21:42 +09:00
Tatsuhiro Tsujikawa
d36bea8554 Add debug output for HPACK decoded integer 2014-08-02 10:40:25 +09:00
Tatsuhiro Tsujikawa
16101b8b3f Fix compile error with --enable-debug 2014-08-02 10:16:32 +09:00
Tatsuhiro Tsujikawa
455d911f61 src, examples: Call OPENSSL_config() 2014-08-02 10:11:45 +09:00
Tatsuhiro Tsujikawa
2fb750f2e3 nghttp2_check_header_value: Disallow 0x00 2014-08-02 00:30:09 +09:00
Tatsuhiro Tsujikawa
7c781bcd1a nghttpx: Issue RST_STREAM instead of returning NGHTTP2_ERR_TEMPORAL_CALLBACKFAILURE
NGHTTP2_ERR_TEMPORAL_CALLBACKFAILURE is not supported in
on_frame_recv_callback.
2014-08-02 00:26:43 +09:00
Tatsuhiro Tsujikawa
a234166fc4 Merge branch 'bagder-server-tutorial' 2014-08-01 20:55:45 +09:00
Tatsuhiro Tsujikawa
ecb7e7db74 Merge branch 'server-tutorial' of https://github.com/bagder/nghttp2 into bagder-server-tutorial 2014-08-01 20:52:39 +09:00
Tatsuhiro Tsujikawa
99ceb7df33 Merge branch 'alagoutte-misc' 2014-08-01 20:51:49 +09:00
Daniel Stenberg
2e0775d506 tutorial-server.rst: language
I went through and fixed the English and grammar somwhat
2014-08-01 10:50:23 +02:00
Alexis La Goutte
ac28cd7efa Fix typo 2014-08-01 09:05:37 +02:00
Tatsuhiro Tsujikawa
a5ec5c1a1d Merge branch 'h2-14' 2014-07-31 23:39:04 +09:00
Tatsuhiro Tsujikawa
7952029752 Advertise h2-14 2014-07-31 23:34:54 +09:00
Tatsuhiro Tsujikawa
2e083352d5 nghttpx: Fix crash on http2 downstream disconnect 2014-07-31 23:34:33 +09:00
Tatsuhiro Tsujikawa
d848b9815a python: Use draft-09 2014-07-31 23:19:31 +09:00
Tatsuhiro Tsujikawa
48734b6d05 Update doc 2014-07-31 23:18:39 +09:00
Tatsuhiro Tsujikawa
8838f666cb Update doc 2014-07-31 23:16:52 +09:00
Tatsuhiro Tsujikawa
d8d14a3fc9 Code cleanup 2014-07-31 23:08:51 +09:00
Tatsuhiro Tsujikawa
6e027ad830 nghttpd, nghttpx: Check allowed pseudo headers 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
9d78167297 nghttpx: Treat unexpected HEADERS as stream error 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
c13329b328 Treat delta 0 WINDOW_UPDATE as error 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
b8a2bf2675 Remove END_SEGMENT flag 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
98be65a1eb Allow submission of unknown SETTINGS 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
742b28833a Rename NGHTTP2_SETTINGS_MAX_HEADER_SET_SIZE as NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
77374ac6e2 Implement SETTINGS_MAX_FRAME_SIZE and SETTINGS_MAX_HEADER_LIST_SIZE 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
c4be7d48a0 nghttp2_hd: Code cleanup 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
0752ce6701 nghttp2_hd_deflate_bound: Take into account possible 2nd context update 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
8d5422c9bb Remove check for incoming header block size
The application should be responsible for the size of incoming header
block size.  Framing layer just passes everything (we have size limit
for one header/field though) to application.
2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
04b5d1679f nghttpx: Log non-final response headers 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
15055c11f9 nghttpx: Support server-wide OPTIONS in http/1 upstream 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
c859fb8f7c nghttpx: Don't respond DATA frame for HEAD request or 204, 304, 1xx 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
dd1850aed0 Emit minimum header table size in encoding context update 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
079db14d45 Add nghttp2_session_consume() API
Reworked no automatic WINDOW_UPDATE feature.  We added new API
nghttp2_session_consume() which tells the library how many bytes are
consumed by the application.  Instead of submitting WINDOW_UPDATE by
the application, the library is now responsible to submit
WINDOW_UPDATE based on consumed bytes.  This is more reliable method,
since it enables us to properly send WINDOW_UPDATE for stream and
connection individually.  The previous implementation of nghttpx had
broken connection window management.
2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
9f17bee51d Fix unittest failure 2014-07-31 23:05:53 +09:00
Tatsuhiro Tsujikawa
e904842504 Update doc 2014-07-31 23:05:52 +09:00
Tatsuhiro Tsujikawa
4f815521ae nghttpx, nghttpd: Support non-final response 2014-07-31 23:05:52 +09:00
Tatsuhiro Tsujikawa
78df530b90 Don't ignore aux_data for HEADERS with NGHTTP2_HCAT_HEADERS tag 2014-07-31 23:05:52 +09:00
Tatsuhiro Tsujikawa
e147c14186 Remove ent_name member and use index solely 2014-07-31 23:05:52 +09:00
Tatsuhiro Tsujikawa
06453fb15e Remove unused role member in nghttp2_hd_context 2014-07-31 23:05:52 +09:00
Tatsuhiro Tsujikawa
af5fd2019d src: Remove 0x00 concatenation for headers
Now concatenating header values with 0x00 as delimiter is not
necessary because HPACK reference set is removed and the order of
header field fed into HPACK encoder is preserved when they are
decoded.
2014-07-31 23:05:52 +09:00
Tatsuhiro Tsujikawa
744ec4dba1 Don't copy static header and put static table in front of dynamic table 2014-07-31 23:05:52 +09:00
Tatsuhiro Tsujikawa
38bfbffb1b Remove HPACK reference set 2014-07-31 23:05:52 +09:00
Tatsuhiro Tsujikawa
63398f30dd Extend frame length field to 24 bits 2014-07-31 23:05:52 +09:00
Tatsuhiro Tsujikawa
961dcf614a Fix wrong detection of neverIndex bit 2014-07-26 23:27:34 +09:00
Tatsuhiro Tsujikawa
5b572d8d59 Bump up version number to 0.5.2-DEV 2014-07-23 00:51:46 +09:00
178 changed files with 15988 additions and 5014 deletions

7
.gitignore vendored
View File

@@ -21,6 +21,7 @@ install-sh
.libs
lib/includes/nghttp2/nghttp2ver.h
lib/libnghttp2.pc
src/libnghttp2_asio.pc
ltmain.sh
stamp-h1
.deps/
@@ -39,3 +40,9 @@ 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

View File

@@ -1,7 +1,8 @@
language: cpp
compiler:
- clang
- gcc
#Disable gcc build for the moment...
# - gcc
python:
- "3.4"
before_install:
@@ -34,3 +35,4 @@ before_script:
- ./configure --enable-werror
script:
- make
- make check

19
COPYING
View File

@@ -20,3 +20,22 @@ 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!

100
Dockerfile.android Normal file
View File

@@ -0,0 +1,100 @@
# Dockerfile to build nghttp2 android binary
#
# $ sudo docker build -t nghttp2-android - < Dockerfile.android
#
# After successful build, android binaries are located under
# /root/build/nghttp2. You can copy the binary using docker cp. For
# example, to copy nghttpx binary to host file system location
# /path/to/dest, do this:
#
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
FROM ubuntu
MAINTAINER Tatsuhiro Tsujikawa
ENV ANDROID_HOME /root/android
ENV PREFIX $ANDROID_HOME/usr/local
ENV TOOLCHAIN $ANDROID_HOME/toolchain
ENV PATH $TOOLCHAIN/bin:$PATH
# It would be better to use nearest ubuntu archive mirror for faster
# downloads.
# RUN sed -ie 's/archive\.ubuntu/jp.archive.ubuntu/g' /etc/apt/sources.list
RUN apt-get update
# genisoimage, libc6-i386 and lib32stdc++6 are required to decompress ndk.
RUN apt-get install -y make binutils autoconf automake autotools-dev libtool \
pkg-config git curl dpkg-dev libxml2-dev \
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
WORKDIR /root/build/android-ndk-r10c
RUN /bin/bash build/tools/make-standalone-toolchain.sh \
--install-dir=$ANDROID_HOME/toolchain \
--toolchain=arm-linux-androideabi-4.9 --llvm-version=3.5 \
--system=linux-x86_64
WORKDIR /root/build
RUN git clone https://github.com/tatsuhiro-t/spdylay
WORKDIR /root/build/spdylay
RUN autoreconf -i && \
./configure \
--disable-shared \
--host=arm-linux-androideabi \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--prefix=$PREFIX \
--without-libxml2 \
--disable-src \
--disable-examples \
CPPFLAGS="-I$PREFIX/include" \
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-L$PREFIX/lib" && \
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 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 \
--host=arm-linux-androideabi \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--prefix=$PREFIX \
--disable-shared \
--enable-static \
CPPFLAGS=-I$PREFIX/include \
LDFLAGS=-L$PREFIX/lib && \
make install
WORKDIR /root/build
RUN git clone https://github.com/tatsuhiro-t/nghttp2
WORKDIR /root/build/nghttp2
RUN autoreconf -i && \
./configure \
--disable-shared \
--host=arm-linux-androideabi \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--with-xml-prefix="$PREFIX" \
--without-libxml2 \
--disable-python-bindings \
--disable-examples \
--disable-threads \
LIBSPDYLAY_CFLAGS=-I$PREFIX/usr/local/include \
LIBSPDYLAY_LIBS="-L$PREFIX/usr/local/lib -lspdylay" \
CPPFLAGS="-I$PREFIX/include" \
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-L$PREFIX/lib" && \
make && \
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp

View File

@@ -20,10 +20,11 @@
# 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
SUBDIRS = lib third-party src examples python tests doc contrib
ACLOCAL_AMFLAGS = -I m4
dist_doc_DATA = README.rst
EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make
EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make \
Dockerfile.android

View File

@@ -4,12 +4,14 @@ nghttp2 - HTTP/2 C Library
This is an implementation of Hypertext Transfer Protocol version 2
in C.
The framing layer of HTTP/2 is implemented as form of reusable C
The framing layer of HTTP/2 is implemented as a form of reusable C
library. On top of that, we have implemented HTTP/2 client, server
and proxy. Also we have developed load test/benchmarking tool for
and proxy. We have also developed load test and benchmarking tool for
HTTP/2 and SPDY.
HPACK encoding and decoding are available as public API.
HPACK encoder and decoder are available as public API.
The experimental high level C++ library is also available.
We have Python binding of this libary, but we have not covered
everything yet.
@@ -17,10 +19,12 @@ everything yet.
Development Status
------------------
We started to implement h2-13
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-13) and the
header compression
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08).
We started to implement h2-14
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), the header
compression
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09)
and HTTP Alternative Services
(http://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-04).
The nghttp2 code base was forked from spdylay project.
@@ -30,32 +34,25 @@ HTTP/2 Features Support
Core frames handling Yes
Dependency Tree Yes
Large header (CONTINUATION) Yes
ALTSVC extension Yes \*1
ALTSVC extension Yes
=========================== =======
* \*1 As described in draft-12, but reserved byte was removed. ALTSVC
may be removed from nghttp2 public API since it is not stabilized
yet.
BLOCKED frame, which once existed in h2-12, was removed in h2-13.
Public Test Server
------------------
The following endpoints are available to try out nghttp2
implementation.
* https://nghttp2.org/ (TLS + NPN)
* https://nghttp2.org/ (TLS + ALPN/NPN)
NPN offer ``h2-13``, ``spdy/3.1`` and ``http/1.1``.
ALPN is currently disabled.
NPN offer ``h2-14``, ``spdy/3.1`` and ``http/1.1``.
This endpoint requires TLSv1.2 and DHE or EDCHE with GCM cipher
suite for HTTP/2 connection.
* http://nghttp2.org/ (Upgrade / Direct)
``h2c-13`` and ``http/1.1``. We configured this server to send
``h2c-14`` and ``http/1.1``. We configured this server to send
ALTSVC frame or Alt-Svc header field to announce that alternative
service is available at port 443.
@@ -89,7 +86,7 @@ ALPN support requires unreleased version OpenSSL >= 1.0.2.
To enable SPDY protocol in the application program ``nghttpx`` and
``h2load``, the following package is required:
* spdylay >= 1.2.3
* spdylay >= 1.3.0
To enable ``-a`` option (getting linked assets from the downloaded
resource) in ``nghttp``, the following package is required:
@@ -105,6 +102,11 @@ To mitigate heap fragmentation in long running server programs
* jemalloc
libnghttp2_asio C++ library requires the following packages:
* libboost-dev >= 1.54.0
* libboost-thread-dev >= 1.54.0
The Python bindings require the following packages:
* cython >= 0.19
@@ -113,6 +115,8 @@ The Python bindings require the following packages:
If you are using Ubuntu 14.04 LTS, you need the following packages
installed:
* make
* binutils
* autoconf
* automake
* autotools-dev
@@ -186,10 +190,10 @@ output from ``nghttp`` client::
$ src/nghttp -nv https://nghttp2.org
[ 0.033][NPN] server offers:
* h2-13
* h2-14
* spdy/3.1
* http/1.1
The negotiated protocol: h2-13
The negotiated protocol: h2-14
[ 0.068] send SETTINGS frame <length=15, flags=0x00, stream_id=0>
(niv=3)
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
@@ -258,7 +262,7 @@ The HTTP Upgrade is performed like this::
GET / HTTP/1.1
Host: nghttp2.org
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c-13
Upgrade: h2c-14
HTTP2-Settings: AwAAAGQEAAD__wUAAAAB
Accept: */*
User-Agent: nghttp2/0.4.0-DEV
@@ -267,7 +271,7 @@ The HTTP Upgrade is performed like this::
[ 0.024] HTTP Upgrade response
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c-13
Upgrade: h2c-14
[ 0.024] HTTP Upgrade success
@@ -281,7 +285,7 @@ The HTTP Upgrade is performed like this::
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
[ 0.024] recv ALTSVC frame <length=43, flags=0x00, stream_id=0>
(max-age=86400, port=443, protocol_id=h2-13, host=nghttp2.org, origin=http://nghttp2.org)
(max-age=86400, port=443, protocol_id=h2-14, host=nghttp2.org, origin=http://nghttp2.org)
[ 0.024] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
@@ -389,7 +393,7 @@ information. Here is sample output from ``nghttpd`` server::
nghttpx - proxy
+++++++++++++++
``nghttpx`` is a multi-threaded reverse proxy for ``h2-13``, SPDY and
``nghttpx`` is a multi-threaded reverse proxy for ``h2-14``, SPDY and
HTTP/1.1 and powers nghttp2.org site. It has several operation modes:
================== ============================ ============== =============
@@ -403,7 +407,7 @@ default mode HTTP/2, SPDY, HTTP/1.1 (TLS) HTTP/1.1 Reverse proxy
================== ============================ ============== =============
The interesting mode at the moment is the default mode. It works like
a reverse proxy and listens for ``h2-13``, SPDY and HTTP/1.1 and can
a reverse proxy and listens for ``h2-14``, SPDY and HTTP/1.1 and can
be deployed SSL/TLS terminator for existing web server.
The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
@@ -966,6 +970,49 @@ associated value includes the state of dynamic header table after the
corresponding header set was processed. The format is the same as
``deflatehd``.
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.
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
configure flag to build libnghttp2_asio. The required Boost libraries
are:
* Boost::Asio
* Boost::System
* Boost::Thread
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[])
{
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");
});
}
For more details, see the documentation of libnghttp2_asio.
Python bindings
---------------
@@ -1081,3 +1128,25 @@ BaseRequestHandler usage:
# 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()
Contribution
------------
[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!

View File

@@ -36,12 +36,10 @@ PATH=$TOOLCHAIN/bin:$PATH
--host=arm-linux-androideabi \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--with-xml-prefix="$PREFIX" \
--without-libxml2 \
--disable-python-bindings \
--disable-examples \
--enable-werror \
--disable-threads \
CC=clang \
CXX=clang++ \
CPPFLAGS="-I$PREFIX/include" \
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-L$PREFIX/lib"

View File

@@ -21,14 +21,14 @@ 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.
AC_PREREQ(2.61)
AC_INIT([nghttp2], [0.5.1], [t-tujikawa@users.sourceforge.net])
AC_INIT([nghttp2], [0.6.6], [t-tujikawa@users.sourceforge.net])
LT_PREREQ([2.2.6])
LT_INIT()
dnl See versioning rule:
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 4)
AC_SUBST(LT_CURRENT, 7)
AC_SUBST(LT_REVISION, 1)
AC_SUBST(LT_AGE, 0)
AC_SUBST(LT_AGE, 2)
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
@@ -76,6 +76,11 @@ AC_ARG_ENABLE([hpack-tools],
[Build HPACK tools [default=check]])],
[request_hpack_tools=$enableval], [request_hpack_tools=check])
AC_ARG_ENABLE([asio-lib],
[AS_HELP_STRING([--enable-asio-lib],
[Build C++ libnghttp2_asio library [default=no]])],
[request_asio_lib=$enableval], [request_asio_lib=no])
AC_ARG_ENABLE([examples],
[AS_HELP_STRING([--enable-examples],
[Build examples [default=check]])],
@@ -205,7 +210,8 @@ case "$host" in
SRC_LIBS="$SRC_LIBS -lstdc++ -lsupc++"
;;
*)
SRC_LIBS="$SRC_LIBS -pthread"
PTHREAD_LDFLAGS="-pthread"
SRC_LIBS="$SRC_LIBS $PTHREAD_LDFLAGS"
;;
esac
@@ -293,7 +299,8 @@ AM_CONDITIONAL([HAVE_LIBXML2], [ test "x${have_libxml2}" = "xyes" ])
have_jemalloc=no
if test "x${request_jemalloc}" != "xno"; then
LIBS_OLD=$LIBS
AC_SEARCH_LIBS([malloc_stats_print], [jemalloc], [have_jemalloc=yes])
AC_SEARCH_LIBS([malloc_stats_print], [jemalloc], [have_jemalloc=yes], [],
[$PTHREAD_LDFLAGS])
LIBS=$LIBS_OLD
if test "x${have_jemalloc}" = "xyes" &&
test "x${ac_cv_search_malloc_stats_print}" != "xnone required"; then
@@ -310,7 +317,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.2.3],
PKG_CHECK_MODULES([LIBSPDYLAY], [libspdylay >= 1.3.0],
[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.])
@@ -327,6 +334,25 @@ fi
AM_CONDITIONAL([HAVE_SPDYLAY], [ test "x${have_spdylay}" = "xyes" ])
# Check Boost Asio library
have_asio_lib=no
if test "x${request_asio_lib}" = "xyes"; then
AX_BOOST_BASE([1.54.0], [have_boost_base=yes], [have_boost_base=no])
if test "x${have_boost_base}" = "xyes"; then
AX_BOOST_ASIO()
AX_BOOST_SYSTEM()
AX_BOOST_THREAD()
if test "x${ax_cv_boost_asio}" = "xyes" &&
test "x${ax_cv_boost_system}" = "xyes" &&
test "x${ax_cv_boost_thread}" = "xyes"; then
have_asio_lib=yes
fi
fi
fi
# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL
# and libevent_openssl
enable_app=no
@@ -343,7 +369,6 @@ if test "x${request_app}" = "xyes" &&
fi
AM_CONDITIONAL([ENABLE_APP], [ test "x${enable_app}" = "xyes" ])
AM_CONDITIONAL([ENABLE_H2LOAD], [ test "x${have_std_future}" = "xyes" ])
enable_hpack_tools=no
# HPACK tools requires jansson
@@ -359,6 +384,16 @@ fi
AM_CONDITIONAL([ENABLE_HPACK_TOOLS], [ test "x${enable_hpack_tools}" = "xyes" ])
# C++ library libnghttp2_asio
enable_asio_lib=no
if test "x${request_asio_lib}" != "xno" &&
test "x${have_asio_lib}" = "xyes"; then
enable_asio_lib=yes
fi
AM_CONDITIONAL([ENABLE_ASIO_LIB], [ test "x${enable_asio_lib}" = "xyes" ])
# The example programs depend on OpenSSL and libevent_openssl
enable_examples=no
if test "x${request_examples}" != "xno" &&
@@ -435,12 +470,26 @@ if test "x$cross_compiling" != "xyes"; then
AC_FUNC_MALLOC
fi
AC_CHECK_FUNCS([ \
_Exit \
getpwnam \
memmove \
memset \
timegm \
])
# timerfd_create was added in linux kernel 2.6.25
AC_CHECK_FUNC([timerfd_create],
[have_timerfd_create=yes], [have_timerfd_create=no])
# Checks for epoll availability, primarily for examples/tiny-nghttpd
AX_HAVE_EPOLL([have_epoll=yes], [have_epoll=no])
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*)
@@ -485,7 +534,9 @@ if test "x$debug" != "xno"; then
AC_DEFINE([DEBUGBUILD], [1], [Define to 1 to enable debug output.])
fi
if test "x$threads" != "xyes"; then
# 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
AC_DEFINE([NOTHREADS], [1], [Define to 1 if you want to disable threads.])
fi
@@ -502,6 +553,8 @@ AC_CONFIG_FILES([
tests/testdata/Makefile
third-party/Makefile
src/Makefile
src/includes/Makefile
src/libnghttp2_asio.pc
examples/Makefile
python/Makefile
python/setup.py
@@ -514,9 +567,13 @@ AC_CONFIG_FILES([
doc/tutorial-hpack.rst
doc/nghttpx-howto.rst
doc/h2load-howto.rst
doc/libnghttp2_asio.rst
doc/python-apiref.rst
doc/building-android-binary.rst
doc/nghttp2.h.rst
doc/nghttp2ver.h.rst
doc/asio_http2.h.rst
contrib/Makefile
])
AC_OUTPUT
@@ -549,8 +606,14 @@ AC_MSG_NOTICE([summary of build options:
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}

39
contrib/Makefile.am Normal file
View File

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

173
contrib/nghttpx-init.in Normal file
View File

@@ -0,0 +1,173 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: nghttpx
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: nghttpx initscript
# Description: nghttpx initscript
### END INIT INFO
# Author: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
#
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
DESC="HTTP/2 reverse proxy"
NAME=nghttpx
# Depending on the configuration, binary may be located under @sbindir@
DAEMON=@bindir@/$NAME
PIDFILE=/var/run/$NAME.pid
DAEMON_ARGS="--conf /etc/nghttpx/nghttpx.conf --pid-file=$PIDFILE"
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
#start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
#[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
upgrade)
log_daemon_msg "Upgrade $DESC" "$NAME"
pid=`pidofproc -p $PIDFILE $NAME`
case "$?" in
0) echo "Sending USR2 signal to $pid"
kill -USR2 $pid
echo "Waiting for new binary..."
sleep 5
echo "Sending QUIT signal to $pid"
kill -QUIT $pid
log_end_msg 0
;;
*) echo "pidofproc() failed"
log_end_msg 1
;;
esac
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload|upgrade}" >&2
exit 3
;;
esac
:

18
contrib/nghttpx-logrotate Normal file
View File

@@ -0,0 +1,18 @@
/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
}

View File

@@ -37,7 +37,9 @@ EXTRA_DIST = \
sources/tutorial-hpack.rst \
sources/nghttpx-howto.rst \
sources/h2load-howto.rst \
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 \

View File

@@ -23,7 +23,7 @@
{% endif %}
{# CSS #}
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/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 %}
@@ -82,7 +82,9 @@
{# SIDE NAV, TOGGLES ON MOBILE #}
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-nav-search">
<a href="{{ pathto(master_doc) }}" class="fa fa-home"> {{ project }}</a>
{% block sidebartitle %}
<a href="{{ pathto(master_doc) }}" class="fa fa-home"> {{ project }}</a>
{% endblock %}
{% include "searchbox.html" %}
</div>
@@ -111,7 +113,7 @@
<div class="wy-nav-content">
<div class="rst-content">
{% include "breadcrumbs.html" %}
<div role="main">
<div role="main" class="document">
{% block body %}{% endblock %}
</div>
{% include "footer.html" %}

View File

@@ -1 +1,2 @@
.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:"\f02d"}.icon-book:before{content:"\f02d"}.fa-caret-down:before{content:"\f0d7"}.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}
.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}
/*# sourceMappingURL=badge_only.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -26,6 +26,8 @@ do not send client connection preface
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. The applications are
responsible to receive it before calling these functions if
:type:`nghttp2_session` is configured as server.
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.

4
doc/asio_http2.h.rst.in Normal file
View File

@@ -0,0 +1,4 @@
asio_http2.h
============
.. literalinclude:: @top_srcdir@/src/includes/nghttp2/asio_http2.h

View File

@@ -0,0 +1 @@
.. include:: @top_srcdir@/doc/sources/building-android-binary.rst

View File

@@ -155,7 +155,7 @@ html_theme_path = ['@top_srcdir@/doc/_themes']
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
html_use_smartypants = False
# Custom sidebar templates, maps document names to template names.
html_sidebars = {

View File

@@ -1,10 +1,10 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.45.1.
.TH H2LOAD "1" "July 2014" "h2load nghttp2/0.5.1" "User Commands"
.\" 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"
.SH NAME
h2load \- HTTP/2 benchmarking tool
.SH SYNOPSIS
.B h2load
[\fI\,OPTIONS\/\fR]... \fI\,<URI>\/\fR...
[\fI\,OPTIONS\/\fR]... [\fI\,URI\/\fR]...
.SH DESCRIPTION
benchmarking tool for HTTP/2 and SPDY server
.TP
@@ -26,6 +26,17 @@ Number of concurrent clients. Default: 1
\fB\-t\fR, \fB\-\-threads=\fR<N>
Number of native threads. Default: 1
.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.
.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
@@ -41,12 +52,15 @@ Sets the connection level initial window size to
than 16, this option is ignored. Otherwise
2**<N> is used for SPDY.
.TP
\fB\-H\fR, \fB\-\-header=\fR<HEADER>
Add/Override a header to the requests.
.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\-13
Default: h2c\-13
h2c\-14
Default: h2c\-14
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Output debug information.

View File

@@ -1,3 +1,5 @@
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
.. program:: h2load
h2load(1)
@@ -9,7 +11,7 @@ h2load - HTTP/2 benchmarking tool
SYNOPSIS
--------
**h2load** [OPTIONS]... <URI>...
**h2load** [OPTIONS]... [URI]...
DESCRIPTION
-----------
@@ -42,6 +44,19 @@ OPTIONS
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.
.. option:: -m, --max-concurrent-streams=(auto|<N>)
@@ -63,14 +78,19 @@ OPTIONS
than 16, this option is ignored. Otherwise
2\*\*<N> is used for SPDY.
.. 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-13
Default: h2c-13
h2c-14
Default: h2c-14
.. option:: -v, --verbose

View File

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

View File

@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.45.1.
.TH NGHTTP "1" "July 2014" "nghttp nghttp2/0.5.1" "User Commands"
.\" 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"
.SH NAME
nghttp \- HTTP/2 experimental client
.SH SYNOPSIS
@@ -14,7 +14,9 @@ Specify URI to access.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Print debug information such as reception and
transmission of frames and name/value pairs.
transmission of frames and name/value pairs.
Specifying this option multiple times increases
verbosity.
.TP
\fB\-n\fR, \fB\-\-null\-out\fR
Discard downloaded data.
@@ -40,13 +42,18 @@ Sets the connection level initial window size to
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.
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
Print statistics.
.TP
\fB\-H\fR, \fB\-\-header\fR
Add a header to the requests.
\fB\-H\fR, \fB\-\-header=\fR<HEADER>
Add a header to the requests. Example:
\fB\-H\fR':method: PUT'
.TP
\fB\-\-cert=\fR<CERT>
Use the specified client certificate file. The

View File

@@ -1,3 +1,5 @@
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
.. program:: nghttp
nghttp(1)
@@ -26,7 +28,9 @@ OPTIONS
Print debug information such as reception and
transmission of frames and name/value pairs.
transmission of frames and name/value pairs.
Specifying this option multiple times increases
verbosity.
.. option:: -n, --null-out
@@ -38,7 +42,7 @@ OPTIONS
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
'/', 'index.html' is used as a filename. Not
implemented yet.
.. option:: -t, --timeout=<N>
@@ -64,17 +68,22 @@ OPTIONS
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.
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
.. option:: -H, --header=<HEADER>
Add a header to the requests.
Add a header to the requests. Example:
-H':method: PUT'
.. option:: --cert=<CERT>

View File

@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.45.1.
.TH NGHTTPD "1" "July 2014" "nghttpd nghttp2/0.5.1" "User Commands"
.\" 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"
.SH NAME
nghttpd \- HTTP/2 experimental server
.SH SYNOPSIS

View File

@@ -1,3 +1,5 @@
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
.. program:: nghttpd
nghttpd(1)

View File

@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.45.1.
.TH NGHTTPX "1" "July 2014" "nghttpx nghttp2/0.5.1" "User Commands"
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
.TH NGHTTPX "1" "November 2014" "nghttpx nghttp2/0.6.6" "User Commands"
.SH NAME
nghttpx \- HTTP/2 experimental proxy
.SH SYNOPSIS
@@ -42,12 +42,54 @@ Resolve backend hostname to IPv4 address only.
.TP
\fB\-\-backend\-ipv6\fR
Resolve backend hostname to IPv6 address only.
.TP
\fB\-\-backend\-http\-proxy\-uri=\fR<URI>
Specify proxy URI in the form
http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a
proxy requires authentication, specify <USER> and
<PASS>. Note that they must be properly
percent\-encoded. This proxy is used when the
backend connection is HTTP/2. First, make a
CONNECT request to the proxy and it connects to
the backend on behalf of nghttpx. This forms
tunnel. After that, nghttpx performs SSL/TLS
handshake with the downstream through the tunnel.
The timeouts when connecting and making CONNECT
request can be specified by
\fB\-\-backend\-read\-timeout\fR and
\fB\-\-backend\-write\-timeout\fR options.
.SS "Performance:"
.TP
\fB\-n\fR, \fB\-\-workers=\fR<CORES>
Set the number of worker threads.
Default: 1
.TP
\fB\-\-read\-rate=\fR<RATE>
Set maximum average read rate on frontend
connection. Setting 0 to this option means read
rate is unlimited.
Default: 0
.TP
\fB\-\-read\-burst=\fR<SIZE>
Set maximum read burst size on frontend
connection. Setting 0 does not work, but it is
not a problem because \fB\-\-read\-rate\fR=\fI\,0\/\fR will give
unlimited read rate regardless of this option
value.
Default: 1073741824
.TP
\fB\-\-write\-rate=\fR<RATE>
Set maximum average write rate on frontend
connection. Setting 0 to this option means write
rate is unlimited.
Default: 0
.TP
\fB\-\-write\-burst=\fR<SIZE>
Set maximum write burst size on frontend
connection. Setting 0 to this option means write
burst size is unlimited.
Default: 0
.TP
\fB\-\-worker\-read\-rate=\fR<RATE>
Set maximum average read rate on frontend
connection per worker. Setting 0 to this option
@@ -76,6 +118,13 @@ Default: 0
Set maximum number of simultaneous connections
frontend accepts. Setting 0 means unlimited.
Default: 0
.TP
\fB\-\-backend\-connections\-per\-frontend=\fR<NUM>
Set maximum number of backend simultaneous
connections per frontend. This option is
meaningful when the combination of HTTP/2 or SPDY
frontend and HTTP/1 backend is used.
Default: 100
.SS "Timeout:"
.TP
\fB\-\-frontend\-http2\-read\-timeout=\fR<SEC>
@@ -86,41 +135,41 @@ Default: 180
\fB\-\-frontend\-read\-timeout=\fR<SEC>
Specify read timeout for HTTP/1.1 frontend
connection.
Default: 180
Default: 30
.TP
\fB\-\-frontend\-write\-timeout=\fR<SEC>
Specify write timeout for all frontend
connections.
Default: 60
Default: 30
.TP
\fB\-\-stream\-read\-timeout=\fR<SEC>
Specify read timeout for HTTP/2 and SPDY streams.
0 means no timeout.
Default: 0
.TP
\fB\-\-stream\-write\-timeout=\fR<SEC>
Specify write timeout for HTTP/2 and SPDY
streams. 0 means no timeout.
Default: 0
.TP
\fB\-\-backend\-read\-timeout=\fR<SEC>
Specify read timeout for backend connection.
Default: 900
Default: 30
.TP
\fB\-\-backend\-write\-timeout=\fR<SEC>
Specify write timeout for backend connection.
Default: 60
Default: 30
.TP
\fB\-\-backend\-keep\-alive\-timeout=\fR<SEC>
Specify keep\-alive timeout for backend
connection.
Default: 60
.TP
\fB\-\-backend\-http\-proxy\-uri=\fR<URI>
Specify proxy URI in the form
http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a
proxy requires authentication, specify <USER> and
<PASS>. Note that they must be properly
percent\-encoded. This proxy is used when the
backend connection is HTTP/2. First, make a
CONNECT request to the proxy and it connects to
the backend on behalf of nghttpx. This forms
tunnel. After that, nghttpx performs SSL/TLS
handshake with the downstream through the tunnel.
The timeouts when connecting and making CONNECT
request can be specified by
\fB\-\-backend\-read\-timeout\fR and
\fB\-\-backend\-write\-timeout\fR options.
\fB\-\-listener\-disable\-timeout=\fR<SEC>
After accepting connection failed, connection
listener is disabled for a given time in seconds.
Specifying 0 disables this feature.
Default: 0
.SS "SSL/TLS:"
.TP
\fB\-\-ciphers=\fR<SUITE>
@@ -171,7 +220,7 @@ most desirable protocol comes first. This is
used in both ALPN and NPN. The parameter must be
delimited by a single comma only and any white
spaces are treated as a part of protocol string.
Default: h2\-13,spdy/3.1,spdy/3,spdy/2,http/1.1
Default: h2\-14,spdy/3.1,spdy/3,spdy/2,http/1.1
.TP
\fB\-\-verify\-client\fR
Require and verify client certificate.
@@ -193,8 +242,8 @@ used in backend client authentication.
\fB\-\-tls\-proto\-list=\fR<LIST>
Comma delimited list of SSL/TLS protocol to be
enabled. The following protocols are available:
TLSv1.2, TLSv1.1, TLSv1.0 and SSLv3. The name
matching is done in case\-insensitive manner. The
TLSv1.2, TLSv1.1 and TLSv1.0. The name matching
is done in case\-insensitive manner. The
parameter must be delimited by a single comma
only and any white spaces are treated as a part
of protocol string.
@@ -279,8 +328,9 @@ URI, suitable for use as a forward proxy.
.TP
\fB\-L\fR, \fB\-\-log\-level=\fR<LEVEL>
Set the severity level of log output. <LEVEL>
must be one of INFO, WARNING, ERROR and FATAL.
Default: WARNING
must be one of INFO, NOTICE, WARN, ERROR and
FATAL.
Default: NOTICE
.TP
\fB\-\-accesslog\-file=\fR<PATH>
Set path to write access log. To reopen file,
@@ -308,10 +358,21 @@ Default: daemon
Append X\-Forwarded\-For header field to the
downstream request.
.TP
\fB\-\-strip\-incoming\-x\-forwarded\-for\fR
Strip X\-Forwarded\-For header field from inbound
client requests.
.TP
\fB\-\-no\-via\fR
Don't append to Via header field. If Via header
field is received, it is left unaltered.
.TP
\fB\-\-no\-location\-rewrite\fR
Don't rewrite location header field on
\fB\-\-http2\-bridge\fR, \fB\-\-client\fR and default mode. For
\fB\-\-http2\-proxy\fR and \fB\-\-client\-proxy\fR mode, location
header field will not be altered regardless of
this option.
.TP
\fB\-\-altsvc=\fR<PROTOID,PORT[,HOST,[ORIGIN]]>
Specify protocol ID, port, host and origin of
alternative service. <HOST> and <ORIGIN> are

View File

@@ -1,3 +1,5 @@
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
.. program:: nghttpx
nghttpx(1)
@@ -66,6 +68,24 @@ Connections
Resolve backend hostname to IPv6 address only.
.. option:: --backend-http-proxy-uri=<URI>
Specify proxy URI in the form
http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a
proxy requires authentication, specify <USER> and
<PASS>. Note that they must be properly
percent-encoded. This proxy is used when the
backend connection is HTTP/2. First, make a
CONNECT request to the proxy and it connects to
the backend on behalf of nghttpx. This forms
tunnel. After that, nghttpx performs SSL/TLS
handshake with the downstream through the tunnel.
The timeouts when connecting and making CONNECT
request can be specified by
:option:`--backend-read-timeout` and
:option:`--backend-write-timeout` options.
Performance
^^^^^^^^^^^
@@ -75,6 +95,40 @@ Performance
Set the number of worker threads.
Default: 1
.. option:: --read-rate=<RATE>
Set maximum average read rate on frontend
connection. Setting 0 to this option means read
rate is unlimited.
Default: 0
.. option:: --read-burst=<SIZE>
Set maximum read burst size on frontend
connection. Setting 0 does not work, but it is
not a problem because --read-rate=0 will give
unlimited read rate regardless of this option
value.
Default: 1073741824
.. option:: --write-rate=<RATE>
Set maximum average write rate on frontend
connection. Setting 0 to this option means write
rate is unlimited.
Default: 0
.. option:: --write-burst=<SIZE>
Set maximum write burst size on frontend
connection. Setting 0 to this option means write
burst size is unlimited.
Default: 0
.. option:: --worker-read-rate=<RATE>
@@ -114,6 +168,15 @@ Performance
frontend accepts. Setting 0 means unlimited.
Default: 0
.. option:: --backend-connections-per-frontend=<NUM>
Set maximum number of backend simultaneous
connections per frontend. This option is
meaningful when the combination of HTTP/2 or SPDY
frontend and HTTP/1 backend is used.
Default: 100
Timeout
^^^^^^^
@@ -129,26 +192,40 @@ Timeout
Specify read timeout for HTTP/1.1 frontend
connection.
Default: 180
Default: 30
.. option:: --frontend-write-timeout=<SEC>
Specify write timeout for all frontend
connections.
Default: 60
Default: 30
.. option:: --stream-read-timeout=<SEC>
Specify read timeout for HTTP/2 and SPDY streams.
0 means no timeout.
Default: 0
.. option:: --stream-write-timeout=<SEC>
Specify write timeout for HTTP/2 and SPDY
streams. 0 means no timeout.
Default: 0
.. option:: --backend-read-timeout=<SEC>
Specify read timeout for backend connection.
Default: 900
Default: 30
.. option:: --backend-write-timeout=<SEC>
Specify write timeout for backend connection.
Default: 60
Default: 30
.. option:: --backend-keep-alive-timeout=<SEC>
@@ -157,23 +234,13 @@ Timeout
connection.
Default: 60
.. option:: --backend-http-proxy-uri=<URI>
.. option:: --listener-disable-timeout=<SEC>
Specify proxy URI in the form
http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a
proxy requires authentication, specify <USER> and
<PASS>. Note that they must be properly
percent-encoded. This proxy is used when the
backend connection is HTTP/2. First, make a
CONNECT request to the proxy and it connects to
the backend on behalf of nghttpx. This forms
tunnel. After that, nghttpx performs SSL/TLS
handshake with the downstream through the tunnel.
The timeouts when connecting and making CONNECT
request can be specified by
:option:`--backend-read-timeout` and
:option:`--backend-write-timeout` options.
After accepting connection failed, connection
listener is disabled for a given time in seconds.
Specifying 0 disables this feature.
Default: 0
SSL/TLS
^^^^^^^
@@ -242,7 +309,7 @@ SSL/TLS
used in both ALPN and NPN. The parameter must be
delimited by a single comma only and any white
spaces are treated as a part of protocol string.
Default: h2-13,spdy/3.1,spdy/3,spdy/2,http/1.1
Default: h2-14,spdy/3.1,spdy/3,spdy/2,http/1.1
.. option:: --verify-client
@@ -274,8 +341,8 @@ SSL/TLS
Comma delimited list of SSL/TLS protocol to be
enabled. The following protocols are available:
TLSv1.2, TLSv1.1, TLSv1.0 and SSLv3. The name
matching is done in case-insensitive manner. The
TLSv1.2, TLSv1.1 and TLSv1.0. The name matching
is done in case-insensitive manner. The
parameter must be delimited by a single comma
only and any white spaces are treated as a part
of protocol string.
@@ -395,8 +462,9 @@ Logging
Set the severity level of log output. <LEVEL>
must be one of INFO, WARNING, ERROR and FATAL.
Default: WARNING
must be one of INFO, NOTICE, WARN, ERROR and
FATAL.
Default: NOTICE
.. option:: --accesslog-file=<PATH>
@@ -438,12 +506,27 @@ Misc
Append X-Forwarded-For header field to the
downstream request.
.. option:: --strip-incoming-x-forwarded-for
Strip X-Forwarded-For header field from inbound
client requests.
.. option:: --no-via
Don't append to Via header field. If Via header
field is received, it is left unaltered.
.. option:: --no-location-rewrite
Don't rewrite location header field on
:option:`--http2-bridge`, :option:`--client` and default mode. For
:option:`--http2-proxy` and :option:`--client-proxy` mode, location
header field will not be altered regardless of
this option.
.. option:: --altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>

View File

@@ -0,0 +1,124 @@
Building Android binary
=======================
In this article, we briefly describe how to build Android binary using
`Android NDK <http://developer.android.com/tools/sdk/ndk/index.html>`_
cross-compiler on Debian Linux.
The easiest way to build android binary is use Dockerfile.android.
See Dockerfile.android for more details. If you cannot use
Dockerfile.android for whatever reason, continue to read the rest of
this article.
We offer ``android-config`` and ``android-make`` scripts to make the
build easier. To make these script work, NDK toolchain must be
installed in the following way. First, let us introduce
``ANDROID_HOME`` environment variable. We need to install toolchain
under ``$ANDROID_HOME/toolchain``. An user can freely choose the path
for ``ANDROID_HOME``. For example, to install toolchain under
``$ANDROID_HOME/toolchain``, do this in the the directory where NDK is
unpacked::
$ build/tools/make-standalone-toolchain.sh \
--install-dir=$ANDROID_HOME/toolchain \
--toolchain=arm-linux-androideabi-4.8
The additional flag ``--system=linux-x86_64`` may be required if you
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
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.
If SPDY support is required for nghttpx and h2load, build and install
spdylay as well.
Before running ``android-config`` and ``android-make``,
``ANDROID_HOME`` environment variable must be set to point to the
correct path. Also add ``$ANDROID_HOME/toolchain/bin`` to ``PATH``::
$ export PATH=$PATH:$ANDROID_HOME/toolchain/bin
To configure OpenSSL, use the following script::
#!/bin/sh
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
export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi-
./Configure --prefix=$PREFIX android
And run ``make install`` to build and install.
To configure libevent, use the following script::
#!/bin/sh
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
./configure \
--host=arm-linux-androideabi \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--prefix=$PREFIX \
--disable-shared \
--enable-static \
CPPFLAGS=-I$PREFIX/include \
LDFLAGS=-L$PREFIX/lib
And run ``make install`` to build and install.
To configure spdylay, use the following script::
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
./configure \
--disable-shared \
--host=arm-linux-androideabi \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--prefix=$PREFIX \
--without-libxml2 \
--disable-src \
--disable-examples \
CPPFLAGS="-I$PREFIX/include" \
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
After prerequisite libraries are prepared, run ``android-config`` and
then ``android-make`` to compile nghttp2 source files.
If all went well, application binaries, such as nghttpx, are created
under src directory. Strip debugging information from the binary
using the following command::
$ arm-linux-androideabi-strip src/nghttpx

View File

@@ -17,6 +17,7 @@ Contents:
:maxdepth: 2
package_README
building-android-binary
tutorial-client
tutorial-server
tutorial-hpack
@@ -27,24 +28,22 @@ Contents:
nghttpx-howto
h2load-howto
apiref
libnghttp2_asio
python-apiref
nghttp2.h
nghttp2ver.h
asio_http2.h
Source <https://github.com/tatsuhiro-t/nghttp2>
Issues <https://github.com/tatsuhiro-t/nghttp2/issues>
Released Versions
=================
* `v0.3.2 <released-versions/v0.3.2/>`_ `(Download v0.3.2) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.3.2>`_
* `v0.3.1 <released-versions/v0.3.1/>`_ `(Download v0.3.1) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.3.1>`_
* `v0.3.0 <released-versions/v0.3.0/>`_ `(Download v0.3.0) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.3.0>`_
* `v0.2.0 <released-versions/v0.2.0/>`_ `(Download v0.2.0) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.2.0>`_
* `v0.1.0 <released-versions/v0.1.0/>`_ `(Download v0.1.0) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.1.0>`_
https://github.com/tatsuhiro-t/nghttp2/releases
Resources
---------
* http://tools.ietf.org/html/draft-ietf-httpbis-http2-13
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08
* 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

View File

@@ -0,0 +1,248 @@
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.
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
configure flag to build libnghttp2_asio. The required Boost libraries
are:
* Boost::Asio
* Boost::System
* Boost::Thread
To use libnghttp2_asio, first include following header file:
.. code-block:: cpp
#include <nghttp2/asio_http2.h>
Also take a look at that header file :doc:`asio_http2.h`.
Server API
----------
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[])
{
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");
});
}
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.
The ``req`` and ``res`` represent HTTP request and response
respectively. ``nghttp2::asio_http2_::server::response::write_head``
constructs HTTP response header fields. The first argument is HTTP
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.
In the above example, we send string "hello, world".
Serving static files and enabling SSL/TLS
+++++++++++++++++++++++++++++++++++++++++
In this example, we serve a couple of static files and also enable
SSL/TLS.
.. 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[])
{
http2 server;
server.tls("server.key", "server.crt");
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>");
}
});
}
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.
In the above example, if request path is either "/" or "/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.
Server push
+++++++++++
Server push is also supported.
.. 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[])
{
http2 server;
server.tls("server.key", "server.crt");
server.listen
("*", 3000,
[](const std::shared_ptr<request>& req,
const std::shared_ptr<response>& res)
{
if(req->path() == "/") {
req->push("GET", "/my.css");
res->write_head(200);
res->end(file_reader("index.html"));
return;
}
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>");
});
}
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".
Enable multi-threading
++++++++++++++++++++++
Enabling multi-threading is very easy. Just call
``nghttp2::asio_http2::server::http2::num_threads`` function with the
desired number of threads:
.. code-block:: cpp
http2 server;
// Use 4 native threads
server.num_threads(4);
Run blocking tasks in background thread
+++++++++++++++++++++++++++++++++++++++
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:
.. code-block:: cpp
#include <unistd.h>
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char* argv[])
{
http2 server;
server.num_concurrent_tasks(16);
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.
// using res directly here is not safe. Capturing it by
// value is safe because it is std::shared_ptr.
sleep(1);
channel.post
([res]()
{
// executed in the same thread where request callback
// was executed.
res->write_head(200);
res->end("hello, world");
});
});
});
}
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.
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.

View File

@@ -197,9 +197,9 @@ connection, so the connection gets insecure. To disable SSL/TLS in
backend connection, use ``--backend-no-tls`` option.
The backend server is supporsed to be a HTTP/2 web server or HTTP/2
proxy. Since HTTP/2 requests opaque between proxied and non-proxied
request, the backend server may be proxy or just web server depending
on the context of incoming requests.
proxy. If backend server is HTTP/2 proxy, use
``--no-location-rewrite`` option to disable rewriting location header
field.
The use-case of this mode is aggregate the incoming connections to one
HTTP/2 connection. One backend HTTP/2 connection is created per
@@ -235,20 +235,13 @@ Read/write rate limit
---------------------
nghttpx supports transfer rate limiting on frontend connections. You
can do rate limit per connection or per worker (thread) for reading
and writeing individually.
To rate limit per connection for reading, use ``--read-rate`` and
``--read-burst`` options. For writing, use ``--write-rate`` and
``--write-burst`` options.
can do rate limit per worker (thread) for reading and writeing
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``.
If both per connection and per worker rate limit configurations are
specified, the lower rate is used.
Please note that rate limit is performed on top of TCP and nothing to
do with HTTP/2 flow control.
@@ -269,3 +262,25 @@ used in frontend, and host is replaced with which appears in
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
----------
nghttpx supports hot deploy feature using signals. The hot deploy 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
current and new processes can accept requests. To gracefully shutdown
current process, send QUIT signal to current nghttpx process. When
all existing frontend connections are done, the current process will
exit. At this point, only new nghttpx process exists and serves
incoming requests.
Re-opening log files
--------------------
When rotating log files, it is desirable to re-open log files after
log rotation daemon renamed existing log files. To tell nghttpx to
re-open log files, send USR1 signal to nghttpx process. It will
re-open files specified by ``--accesslog-file`` and
``--errorlog-file`` options.

View File

@@ -156,15 +156,30 @@ finished successfully. We first initialize nghttp2 session object in
static void initialize_nghttp2_session(http2_session_data *session_data)
{
nghttp2_session_callbacks callbacks = {0};
nghttp2_session_callbacks *callbacks;
callbacks.send_callback = send_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
nghttp2_session_client_new(&session_data->session, &callbacks, session_data);
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_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_header_callback
(callbacks, on_header_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);
}
Since we are creating client, we use `nghttp2_session_client_new()` to
@@ -291,11 +306,9 @@ frames. The ``session_send()`` function is defined as follows::
}
The `nghttp2_session_send()` function serializes the frame into wire
format and call :member:`nghttp2_session_callbacks.send_callback` with
it. We set ``send_callback()`` function to
:member:`nghttp2_session_callbacks.send_callback` in
``initialize_nghttp2_session()`` function described earlier. It is
defined as follows::
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,
@@ -311,15 +324,14 @@ Since we use bufferevent to abstract network I/O, we just write the
data to the bufferevent object. Note that `nghttp2_session_send()`
continues to write all frames queued so far. If we were writing the
data to the non-blocking socket directly using ``write()`` system call
in the :member:`nghttp2_session_callbacks.send_callback`, we will
surely get ``EAGAIN`` or ``EWOULDBLOCK`` since the socket has limited
send buffer. If that happens, we can return
:macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the nghttp2 library to stop
sending further data. But writing to the bufferevent, we have to
regulate the amount data to be buffered by ourselves to avoid possible
huge memory consumption. In this example client, we do not limit
anything. To see how to regulate the amount of buffered data, see the
``send_callback()`` in the server tutorial.
in the ``send_callback()``, we will surely get ``EAGAIN`` or
``EWOULDBLOCK`` since the socket has limited send buffer. If that
happens, we can return :macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the
nghttp2 library to stop sending further data. But writing to the
bufferevent, we have to regulate the amount data to be buffered by
ourselves to avoid possible huge memory consumption. In this example
client, we do not limit anything. To see how to regulate the amount of
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::

View File

@@ -66,18 +66,6 @@ size of buffer.
To delete :type:`nghttp2_hd_deflater` object, use `nghttp2_hd_deflate_del()`
function.
.. note::
Generally, the order of header fields passed to
`nghttp2_hd_deflate_hd()` function is not preserved. It is known
that the relative ordering of header fields which do not share the
same name is insignificant. But some header fields sharing the
same name require the explicit ordering. To preserve this
ordering, those header values are concatenated into single header
field value using NULL (0x00) as delimiter. This is transparent to
HPACK API. Therefore, the application should examine the inflated
header values and split into multiple header field values by NULL.
Inflating (decoding) headers
----------------------------

View File

@@ -3,29 +3,28 @@ Tutorial: HTTP/2 server
In this tutorial, we are going to write single-threaded, event-based
HTTP/2 web server, which supports HTTPS only. It can handle
concurrent multiple requests, but only GET method is supported. The
concurrent multiple requests, but only the GET method is supported. The
complete source code, `libevent-server.c`_, is attached at the end of
this page. It also resides in examples directory in the archive or
repository.
This simple server takes 3 arguments, a port number to listen to, a
path to SSL/TLS private key file and certificate file. Its synopsis
is like this::
This simple server takes 3 arguments, a port number to listen to, a path to
your SSL/TLS private key file and a path to your certificate file. Its
synopsis is like this::
$ libevent-server PORT /path/to/server.key /path/to/server.crt
We use libevent in this tutorial to handle networking I/O. Please
note that nghttp2 itself does not depend on libevent.
First we do some setup routine for libevent and OpenSSL library in
function ``main()`` and ``run()``, which is not so relevant to nghttp2
library use. The one thing you should look at is setup NPN callback.
The NPN callback is used for the server to advertise the application
protocols the server supports to a client. In this example program,
when creating ``SSL_CTX`` object, we stores the application protocol
name in the wire format of NPN in statically allocated buffer. This is
safe because we only create 1 ``SSL_CTX`` object in the entire program
life time::
First we create a setup routine for libevent and OpenSSL in the functions
``main()`` and ``run()``. One thing in there you should look at, is the setup
of the NPN callback. The NPN callback is used for the server to advertise
which application protocols the server supports to a client. In this example
program, when creating ``SSL_CTX`` object, we store the application protocol
name in the wire format of NPN in a statically allocated buffer. This is safe
because we only create one ``SSL_CTX`` object in the program's entire life
time::
static unsigned char next_proto_list[256];
static size_t next_proto_list_len;
@@ -54,25 +53,25 @@ life time::
return ssl_ctx;
}
The wire format of NPN is a sequence of length prefixed string. The
exactly one byte is used to specify the length of each protocol
identifier. In this tutorial, we advertise the HTTP/2 protocol the
nghttp2 library supports. The nghttp2 library exports its identifier
in :macro:`NGHTTP2_PROTO_VERSION_ID`. The ``next_proto_cb()`` function
is the server-side NPN callback. In OpenSSL implementation, we just
assign the pointer to the NPN buffers we filled earlier. The NPN
callback function is set to ``SSL_CTX`` object using
The wire format of NPN is a sequence of length prefixed string. Exactly one
byte is used to specify the length of each protocol identifier. In this
tutorial, we advertise the specific HTTP/2 protocol version the current
nghttp2 library supports. The nghttp2 library exports its identifier in
:macro:`NGHTTP2_PROTO_VERSION_ID`. The ``next_proto_cb()`` function is the
server-side NPN callback. In the OpenSSL implementation, we just assign the
pointer to the NPN buffers we filled in earlier. The NPN callback function is
set to the ``SSL_CTX`` object using
``SSL_CTX_set_next_protos_advertised_cb()``.
We use ``app_content`` structure to store the application-wide data::
We use the ``app_content`` structure to store application-wide data::
struct app_context {
SSL_CTX *ssl_ctx;
struct event_base *evbase;
};
We use ``http2_session_data`` structure to store the session-level
(which corresponds to 1 HTTP/2 connection) data::
We use the ``http2_session_data`` structure to store session-level
(which corresponds to one HTTP/2 connection) data::
typedef struct http2_session_data {
struct http2_stream_data root;
@@ -80,11 +79,9 @@ We use ``http2_session_data`` structure to store the session-level
app_context *app_ctx;
nghttp2_session *session;
char *client_addr;
size_t handshake_leftlen;
} http2_session_data;
We use ``http2_stream_data`` structure to store the stream-level
data::
We use the ``http2_stream_data`` structure to store stream-level data::
typedef struct http2_stream_data {
struct http2_stream_data *prev, *next;
@@ -93,23 +90,18 @@ data::
int fd;
} http2_stream_data;
1 HTTP/2 session can have multiple streams. We manage these multiple
streams by intrusive doubly linked list to add and remove the object
in O(1). The first element of this list is pointed by the
``root->next`` in ``http2_session_data``. Initially, ``root->next``
is ``NULL``. The ``handshake_leftlen`` member of
``http2_session_data`` is used to track the number of bytes remaining
when receiving first client connection preface
(:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`), which is 24 bytes magic
byte string, from the client. We use libevent's bufferevent structure
to perform network I/O. Notice that bufferevent object is in
``http2_session_data`` and not in ``http2_stream_data``. This is
because ``http2_stream_data`` is just a logical stream multiplexed
A single HTTP/2 session can have multiple streams. We manage these
multiple streams with a doubly linked list. The first element of this
list is pointed to by the ``root->next`` in ``http2_session_data``.
Initially, ``root->next`` is ``NULL``. We use libevent's bufferevent
structure to perform network I/O. Note that the bufferevent object is
kept in ``http2_session_data`` and not in ``http2_stream_data``. This
is because ``http2_stream_data`` is just a logical stream multiplexed
over the single connection managed by bufferevent in
``http2_session_data``.
We first create listener object to accept incoming connections.
We use libevent's ``struct evconnlistener`` for this purpose::
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)
@@ -143,8 +135,8 @@ We use libevent's ``struct evconnlistener`` for this purpose::
errx(1, "Could not start listener");
}
We specify ``acceptcb`` callback which is called when a new connection
is accepted::
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)
@@ -153,15 +145,16 @@ is accepted::
http2_session_data *session_data;
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
bufferevent_setcb(session_data->bev, handshake_readcb, NULL, eventcb,
session_data);
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data);
}
Here we create ``http2_session_data`` object. The bufferevent for this
connection is also initialized at this time. We specify 2 callbacks
for the bufferevent: ``handshake_readcb`` and ``eventcb``.
Here we create the ``http2_session_data`` object. The bufferevent for
this connection is also initialized at this time. We specify three
callbacks for the bufferevent: ``readcb``, ``writecb`` and
``eventcb``.
The ``eventcb()`` is invoked by libevent event loop when an event
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::
@@ -170,6 +163,14 @@ underlying network socket::
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) {
delete_http2_session_data(session_data);
return;
}
return;
}
if(events & BEV_EVENT_EOF) {
@@ -182,77 +183,64 @@ underlying network socket::
delete_http2_session_data(session_data);
}
For ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR`` and ``BEV_EVENT_TIMEOUT``
event, we just simply tear down the connection. The
``delete_http2_session_data()`` function destroys
``http2_session_data`` object and thus its bufferevent member. As a
result, the underlying connection is closed. The
For the ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR`` and
``BEV_EVENT_TIMEOUT`` events, we just simply tear down the connection.
The ``delete_http2_session_data()`` function destroys the
``http2_session_data`` object and thus also its bufferevent member.
As a result, the underlying connection is closed. The
``BEV_EVENT_CONNECTED`` event is invoked when SSL/TLS handshake is
finished successfully.
finished successfully. Now we are ready to start the HTTP/2
communication.
The ``handshake_readcb()`` is a callback function to handle 24 bytes
magic byte string from a client, since nghttp2 library does not handle
it::
static void handshake_readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
uint8_t data[24];
struct evbuffer *input = bufferevent_get_input(session_data->bev);
int readlen = evbuffer_remove(input, data, session_data->handshake_leftlen);
const char *conhead = NGHTTP2_CLIENT_CONNECTION_PREFACE;
if(memcmp(conhead + NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
- session_data->handshake_leftlen, data, readlen) != 0) {
delete_http2_session_data(session_data);
return;
}
session_data->handshake_leftlen -= readlen;
if(session_data->handshake_leftlen == 0) {
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, ptr);
/* Process pending data in buffer since they are not notified
further */
initialize_nghttp2_session(session_data);
if(send_server_connection_header(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
if(session_recv(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
}
}
We check that the received byte string matches
:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`. When they match, the
connection state is ready for starting HTTP/2 communication. First
we change the callback functions for the bufferevent object. We use
same ``eventcb`` as before. But we specify new ``readcb`` and
``writecb`` function to handle HTTP/2 communication. We describe
these 2 functions later.
We initialize nghttp2 session object which is done in
We initialize a nghttp2 session object which is done in
``initialize_nghttp2_session()``::
static void initialize_nghttp2_session(http2_session_data *session_data)
{
nghttp2_session_callbacks callbacks = {0};
nghttp2_option *option;
nghttp2_session_callbacks *callbacks;
callbacks.send_callback = send_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
nghttp2_session_server_new(&session_data->session, &callbacks, session_data);
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_stream_close_callback
(callbacks, on_stream_close_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_server_new2(&session_data->session, callbacks, session_data,
option);
nghttp2_session_callbacks_del(callbacks);
nghttp2_option_del(option);
}
Since we are creating server, nghttp2 session object is created using
`nghttp2_session_server_new()` function. We registers 5 callbacks to
nghttp2 session object. We'll talk about these callbacks later.
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.
After initialization of nghttp2 session object, we are going to send
server connection header in ``send_server_connection_header()``::
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)
{
@@ -270,18 +258,18 @@ server connection header in ``send_server_connection_header()``::
return 0;
}
The server connection header is SETTINGS frame. We specify
SETTINGS_MAX_CONCURRENT_STREAMS to 100 in SETTINGS frame. To queue
The server connection header is a SETTINGS frame. We specify
SETTINGS_MAX_CONCURRENT_STREAMS to 100 in the 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 actually send it. All
``nghttp2_submit_*()`` family functions have this property. To
actually send the frame, `nghttp2_session_send()` is used, which is
described about later.
function only queues the frame and it does not actually send it. All
functions in the ``nghttp2_submit_*()`` family have this property. To
actually send the frame, `nghttp2_session_send()` should be used, as
described later.
Since bufferevent may buffer more than first 24 bytes from the client,
we have to process them here since libevent won't invoke callback
functions for these pending data. To process received data, we call
Since bufferevent may buffer more than the first 24 bytes from the client, we
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)
@@ -306,12 +294,12 @@ functions for these pending data. To process received data, we call
return 0;
}
In this function, we feed all unprocessed, received data to nghttp2
session object using `nghttp2_session_mem_recv()` function. The
`nghttp2_session_mem_recv()` processes the received data and may
invoke nghttp2 callbacks and also queue outgoing frames. Since there
may be pending frames, we call ``session_send()`` function to send
those frames. The ``session_send()`` function is defined as follows::
In this function, we feed all unprocessed but already received data to the
nghttp2 session object using the `nghttp2_session_mem_recv()` function. The
`nghttp2_session_mem_recv()` function processes the data and may invoke the
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)
{
@@ -325,11 +313,9 @@ those frames. The ``session_send()`` function is defined as follows::
}
The `nghttp2_session_send()` function serializes the frame into wire
format and call :member:`nghttp2_session_callbacks.send_callback` with
it. We set ``send_callback()`` function to
:member:`nghttp2_session_callbacks.send_callback` in
``initialize_nghttp2_session()`` function described earlier. It is
defined as follows::
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,
@@ -349,18 +335,17 @@ defined as follows::
Since we use bufferevent to abstract network I/O, we just write the
data to the bufferevent object. Note that `nghttp2_session_send()`
continues to write all frames queued so far. If we were writing the
data to the non-blocking socket directly using ``write()`` system call
in the :member:`nghttp2_session_callbacks.send_callback`, we will
surely get ``EAGAIN`` or ``EWOULDBLOCK`` since the socket has limited
send buffer. If that happens, we can return
:macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the nghttp2 library to stop
sending further data. But writing to the bufferevent, we have to
regulate the amount data to be buffered by ourselves to avoid possible
huge memory consumption. To achieve this, we check the size of output
buffer and if it is more than or equal to
``OUTPUT_WOULDBLOCK_THRESHOLD`` bytes, we stop writing data and return
:macro:`NGHTTP2_ERR_WOULDBLOCK` to tell the library to stop calling
send_callback.
data to a non-blocking socket directly using ``write()`` system call
in the ``send_callback()``, we would surely get ``EAGAIN`` or
``EWOULDBLOCK`` back since the socket has limited send buffer. If that
happens, we can return :macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the
nghttp2 library to stop sending further data. But when writing to the
bufferevent, we have to regulate the amount data to get buffered
ourselves to avoid using huge amounts of memory. To achieve this, we
check the size of the output buffer and if it reaches more than or
equal to ``OUTPUT_WOULDBLOCK_THRESHOLD`` bytes, we stop writing data
and return :macro:`NGHTTP2_ERR_WOULDBLOCK` to tell the library to stop
calling send_callback.
The next bufferevent callback is ``readcb()``, which is invoked when
data is available to read in the bufferevent input buffer::
@@ -377,8 +362,8 @@ data is available to read in the bufferevent input buffer::
In this function, we just call ``session_recv()`` to process incoming
data.
The third bufferevent callback is ``writecb()``, which is invoked when
all data written in the bufferevent output buffer have been sent::
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)
{
@@ -397,29 +382,28 @@ all data written in the bufferevent output buffer have been sent::
}
}
First we check whether we should drop connection or not. The nghttp2
session object keeps track of reception and transmission of GOAWAY
frame and other error conditions as well. Using these information,
nghttp2 session object will tell whether the connection should be
dropped or not. More specifically, both `nghttp2_session_want_read()`
and `nghttp2_session_want_write()` return 0, we have no business in
the connection. But since we are using bufferevent and its deferred
callback option, the bufferevent output buffer may contain the pending
data when the ``writecb()`` is called. To handle this situation, we
also check whether the output buffer is empty or not. If these
conditions are met, we drop connection.
First we check whether we should drop the connection or not. The nghttp2
session object keeps track of reception and transmission of GOAWAY frames and
other error conditions as well. Using this information, the nghttp2 session
object will tell whether the connection should be dropped or not. More
specifically, if both `nghttp2_session_want_read()` and
`nghttp2_session_want_write()` return 0, we have no business left in the
connection. But since we are using bufferevent and its deferred callback
option, the bufferevent output buffer may contain pending data when the
``writecb()`` is called. To handle this, we check whether the output buffer is
empty or not. If all these conditions are met, we drop connection.
Otherwise, we call ``session_send()`` to process pending output
data. Remember that in ``send_callback()``, we may not write all data
to bufferevent to avoid excessive buffering. We continue process
pending data when output buffer becomes empty.
Otherwise, we call ``session_send()`` to process the pending output
data. Remember that in ``send_callback()``, we must not write all data to
bufferevent to avoid excessive buffering. We continue processing pending data
when the output buffer becomes empty.
We have already described about nghttp2 callback ``send_callback()``.
Let's describe remaining nghttp2 callbacks we setup in
We have already described the nghttp2 callback ``send_callback()``. Let's
learn about the remaining nghttp2 callbacks we setup in
``initialize_nghttp2_setup()`` function.
The ``on_begin_headers_callback()`` function is invoked when reception
of header block in HEADERS or PUSH_PROMISE frame is started::
The ``on_begin_headers_callback()`` function is invoked when the reception of
a header block in HEADERS or PUSH_PROMISE frame is started::
static int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
@@ -438,17 +422,17 @@ of header block in HEADERS or PUSH_PROMISE frame is started::
return 0;
}
We only interested in HEADERS frame in this function. Since HEADERS
frame has several roles in HTTP/2 protocol, we check that it is a
request HEADERS, which opens new stream. If frame is request HEADERS,
then we create ``http2_stream_data`` object to store stream related
data. We associate created ``http2_stream_data`` object to the stream
in nghttp2 session object using `nghttp2_set_stream_user_data()` in
order to get the object without searching through doubly linked list.
We are only interested in the HEADERS frame in this function. Since the
HEADERS frame has several roles in the HTTP/2 protocol, we check that it is a
request HEADERS, which opens new stream. If the frame is a request HEADERS, we
create a ``http2_stream_data`` object to store the stream related data. We
associate the created ``http2_stream_data`` object with the stream in the
nghttp2 session object using `nghttp2_set_stream_user_data()` to get the
object without searching through the doubly linked list.
In this example server, we want to serve files relative to the current
working directory the program was invoked. Each header name/value pair
is emitted via ``on_header_callback`` function, which is called after
In this example server, we want to serve files relative to the current working
directory in which the program was invoked. Each header name/value pair is
emitted via ``on_header_callback`` function, which is called after
``on_begin_headers_callback()``::
static int on_header_callback(nghttp2_session *session,
@@ -479,10 +463,10 @@ is emitted via ``on_header_callback`` function, which is called after
return 0;
}
We search ``:path`` header field in request headers and keep the
requested path in ``http2_stream_data`` object. In this example
program, we ignore ``:method`` header field and always treat the
request as GET request.
We search for the ``:path`` header field among the request headers and store
the requested path in the ``http2_stream_data`` object. In this example
program, we ignore ``:method`` header field and always treat the request as a
GET request.
The ``on_frame_recv_callback()`` function is invoked when a frame is
fully received::
@@ -513,15 +497,15 @@ fully received::
return 0;
}
First we retrieve ``http2_stream_data`` object associated to the
stream in ``on_begin_headers_callback()``. It is done using
`nghttp2_session_get_stream_user_data()`. If the requested path cannot
be served for some reasons (e.g., file is not found), we send 404
response, which is done in ``error_reply()``. Otherwise, we open
requested file and send its content. We send 1 header field
``:status`` as a response header.
First we retrieve the ``http2_stream_data`` object associated with the stream
in ``on_begin_headers_callback()``. It is done using
`nghttp2_session_get_stream_user_data()`. If the requested path cannot be
served for some reason (e.g., file is not found), we send a 404 response,
which is done in ``error_reply()``. Otherwise, we open the requested file and
send its content. We send the header field ``:status`` as a single response
header.
Sending content of a file is done in ``send_response()`` function::
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)
@@ -539,12 +523,12 @@ Sending content of a file is done in ``send_response()`` function::
return 0;
}
The nghttp2 library uses :type:`nghttp2_data_provider` structure to
The nghttp2 library uses the :type:`nghttp2_data_provider` structure to
send entity body to the remote peer. The ``source`` member of this
structure is a union and it can be either void pointer or int which is
intended to be used as file descriptor. In this example server, we use
file descriptor. We also set ``file_read_callback()`` callback
function to read content of the file::
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,
@@ -563,14 +547,14 @@ function to read content of the file::
return r;
}
If error happens while reading file, we return
If an error happens while reading the file, we return
:macro:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. This tells the
library to send RST_STREAM to the stream. When all data are read, set
:macro:`NGHTTP2_DATA_FLAG_EOF` flag to ``*data_flags`` to tell the
nghttp2 library that we have finished reading file.
library to send RST_STREAM to the stream. When all data has been read, set
the :macro:`NGHTTP2_DATA_FLAG_EOF` flag to ``*data_flags`` to tell the
nghttp2 library that we have finished reading the file.
The `nghttp2_submit_response()` is used to send response to the remote
peer.
The `nghttp2_submit_response()` function is used to send the response to the
remote peer.
The ``on_stream_close_callback()`` function is invoked when the stream
is about to close::
@@ -592,5 +576,5 @@ is about to close::
return 0;
}
We destroy ``http2_stream_data`` object in this function since the
stream is about to close and we no longer use that object.
We destroy the ``http2_stream_data`` object in this function since the stream
is about to close and we no longer use that object.

4
examples/.gitignore vendored
View File

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

View File

@@ -27,6 +27,7 @@ AM_CPPFLAGS = \
-Wall \
-I$(top_srcdir)/lib/includes \
-I$(top_builddir)/lib/includes \
-I$(top_srcdir)/src/includes \
-I$(top_srcdir)/third-party \
@LIBEVENT_OPENSSL_CFLAGS@ \
@OPENSSL_CFLAGS@ \
@@ -48,4 +49,37 @@ libevent_server_SOURCES = libevent-server.c
deflate_SOURCES = deflate.c
if ENABLE_TINY_NGHTTPD
noinst_PROGRAMS += tiny-nghttpd
tiny_nghttpd_SOURCES = tiny-nghttpd.c
endif # ENABLE_TINY_NGHTTPD
if ENABLE_ASIO_LIB
noinst_PROGRAMS += asio-sv asio-sv2 asio-sv3
ASIOCPPFLAGS = ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
ASIOLDFLAGS = @JEMALLOC_LIBS@
ASIOLDADD = $(top_builddir)/src/libnghttp2_asio.la
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}
endif # ENABLE_ASIO_LIB
endif # ENABLE_EXAMPLES

79
examples/asio-sv.cc Normal file
View File

@@ -0,0 +1,79 @@
/*
* 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 <iostream>
#include <string>
#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 < 3) {
std::cerr << "Usage: asio-sv <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]);
http2 server;
server.num_threads(num_threads);
if(argc >= 5) {
server.tls(argv[3], argv[4]);
}
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) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}

111
examples/asio-sv2.cc Normal file
View File

@@ -0,0 +1,111 @@
/*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#include <string>
#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-sv2 <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];
http2 server;
server.num_threads(num_threads);
if(argc >= 6) {
server.tls(argv[4], argv[5]);
}
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) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}

151
examples/asio-sv3.cc Normal file
View File

@@ -0,0 +1,151 @@
/*
* 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

@@ -44,6 +44,7 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/conf.h>
enum {
IO_NONE,
@@ -309,13 +310,21 @@ static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
*/
static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks)
{
memset(callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks->send_callback = send_callback;
callbacks->recv_callback = recv_callback;
callbacks->on_frame_send_callback = on_frame_send_callback;
callbacks->on_frame_recv_callback = on_frame_recv_callback;
callbacks->on_stream_close_callback = on_stream_close_callback;
callbacks->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
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_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_data_chunk_recv_callback
(callbacks, on_data_chunk_recv_callback);
}
/*
@@ -506,7 +515,7 @@ static void request_free(struct Request *req)
*/
static void fetch_uri(const struct URI *uri)
{
nghttp2_session_callbacks callbacks;
nghttp2_session_callbacks *callbacks;
int fd;
SSL_CTX *ssl_ctx;
SSL *ssl;
@@ -518,8 +527,6 @@ static void fetch_uri(const struct URI *uri)
request_init(&req, uri);
setup_nghttp2_callbacks(&callbacks);
/* Establish connection and setup SSL */
fd = connect_to(req.host, req.port);
if(fd == -1) {
@@ -550,8 +557,20 @@ static void fetch_uri(const struct URI *uri)
set_tcp_nodelay(fd);
printf("[INFO] SSL/TLS handshake completed\n");
rv = nghttp2_session_client_new(&connection.session, &callbacks,
rv = nghttp2_session_callbacks_new(&callbacks);
if(rv != 0) {
diec("nghttp2_session_callbacks_new", rv);
}
setup_nghttp2_callbacks(callbacks);
rv = nghttp2_session_client_new(&connection.session, callbacks,
&connection);
nghttp2_session_callbacks_del(callbacks);
if(rv != 0) {
diec("nghttp2_session_client_new", rv);
}
@@ -685,6 +704,8 @@ 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();

View File

@@ -32,6 +32,7 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <event.h>
#include <event2/event.h>
@@ -330,17 +331,30 @@ static SSL* create_ssl(SSL_CTX *ssl_ctx)
static void initialize_nghttp2_session(http2_session_data *session_data)
{
nghttp2_session_callbacks callbacks;
nghttp2_session_callbacks *callbacks;
memset(&callbacks, 0, sizeof(callbacks));
nghttp2_session_callbacks_new(&callbacks);
callbacks.send_callback = send_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
nghttp2_session_client_new(&session_data->session, &callbacks, session_data);
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_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_header_callback
(callbacks, on_header_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)
@@ -560,6 +574,8 @@ 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();

View File

@@ -36,6 +36,7 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <event.h>
#include <event2/event.h>
@@ -68,7 +69,6 @@ typedef struct http2_session_data {
app_context *app_ctx;
nghttp2_session *session;
char *client_addr;
size_t handshake_leftlen;
} http2_session_data;
struct app_context {
@@ -191,7 +191,6 @@ static http2_session_data* create_http2_session_data(app_context *app_ctx,
(app_ctx->evbase, fd, ssl,
BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
session_data->handshake_leftlen = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN;
rv = getnameinfo(addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
if(rv != 0) {
session_data->client_addr = strdup("(unknown)");
@@ -554,16 +553,38 @@ static int on_stream_close_callback(nghttp2_session *session,
static void initialize_nghttp2_session(http2_session_data *session_data)
{
nghttp2_session_callbacks callbacks;
nghttp2_option *option;
nghttp2_session_callbacks *callbacks;
memset(&callbacks, 0, sizeof(callbacks));
nghttp2_option_new(&option);
callbacks.send_callback = send_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
nghttp2_session_server_new(&session_data->session, &callbacks, session_data);
/* 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_stream_close_callback
(callbacks, on_stream_close_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_server_new2(&session_data->session, callbacks, session_data,
option);
nghttp2_session_callbacks_del(callbacks);
nghttp2_option_del(option);
}
/* Send HTTP/2 client connection header, which includes 24 bytes
@@ -626,6 +647,14 @@ static void eventcb(struct bufferevent *bev, 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) {
delete_http2_session_data(session_data);
return;
}
return;
}
if(events & BEV_EVENT_EOF) {
@@ -638,38 +667,6 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr)
delete_http2_session_data(session_data);
}
/* readcb for bufferevent to check first 24 bytes client connection
header. */
static void handshake_readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
uint8_t data[24];
struct evbuffer *input = bufferevent_get_input(session_data->bev);
int readlen = evbuffer_remove(input, data, session_data->handshake_leftlen);
const char *conhead = NGHTTP2_CLIENT_CONNECTION_PREFACE;
if(memcmp(conhead + NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
- session_data->handshake_leftlen, data, readlen) != 0) {
delete_http2_session_data(session_data);
return;
}
session_data->handshake_leftlen -= readlen;
if(session_data->handshake_leftlen == 0) {
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, ptr);
/* Process pending data in buffer since they are not notified
further */
initialize_nghttp2_session(session_data);
if(send_server_connection_header(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
if(session_recv(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
}
}
/* callback for evconnlistener */
static void acceptcb(struct evconnlistener *listener, int fd,
struct sockaddr *addr, int addrlen, void *arg)
@@ -678,8 +675,8 @@ static void acceptcb(struct evconnlistener *listener, int fd,
http2_session_data *session_data;
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
bufferevent_setcb(session_data->bev, handshake_readcb, NULL, eventcb,
session_data);
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data);
}
static void start_listen(struct event_base *evbase, const char *service,
@@ -755,6 +752,8 @@ 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();

1324
examples/tiny-nghttpd.c Normal file

File diff suppressed because it is too large Load Diff

30
gendowncasetbl.py Executable file
View File

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

0
gennmchartbl.py Normal file → Executable file
View File

0
genvchartbl.py Normal file → Executable file
View File

View File

@@ -22,6 +22,8 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = includes
EXTRA_DIST = Makefile.msvc
AM_CFLAGS = -Wall
AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes @DEFS@
@@ -41,7 +43,8 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c \
nghttp2_version.c \
nghttp2_priority_spec.c \
nghttp2_option.c
nghttp2_option.c \
nghttp2_callbacks.c
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_frame.h \
@@ -52,7 +55,8 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_net.h \
nghttp2_hd.h nghttp2_hd_huffman.h \
nghttp2_priority_spec.h \
nghttp2_option.h
nghttp2_option.h \
nghttp2_callbacks.h
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
libnghttp2_la_LDFLAGS = -no-undefined \

266
lib/Makefile.msvc Normal file
View File

@@ -0,0 +1,266 @@
#
# GNU Makefile for nghttp2 / MSVC.
#
# By G. Vanem <gvanem@yahoo.no> 2013
# The MIT License apply.
#
#
# Choose your weapons:
# Set 'ZLIB_ROOT' to the root of zlib.
# Set 'USE_CYTHON=1' to build and install the 'nghttp2.pyd' Python extension.
#
ZLIB_ROOT = g:/MingW32/src/Compression/zlib-1.2.8
USE_CYTHON = 1
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV], //g')
_VERSION := $(subst ., ,$(_VERSION))
VER_MAJOR = $(word 1,$(_VERSION))
VER_MINOR = $(word 2,$(_VERSION))
VER_MICRO = $(word 3,$(_VERSION))
VERSION = $(VER_MAJOR).$(VER_MINOR).$(VER_MICRO)
VERSION_NUM = ($(VER_MAJOR) << 16) + ($(VER_MINOR) << 8) + $(VER_MICRO)
GENERATED = 'Generated by $(realpath Makefile.MSVC)'
#
# Where to copy nghttp2.dll + lib + headers to.
# Note: 'make install' is not in default targets. Do it explicitly.
#
VC_ROOT = $(realpath $(VCINSTALLDIR))
INSTALL_BIN = $(VC_ROOT)/bin
INSTALL_LIB = $(VC_ROOT)/lib
INSTALL_HDR = $(VC_ROOT)/include
#
# Build for DEBUG-model and RELEASE at the same time.
#
TARGETS = nghttp2.lib nghttp2.dll nghttp2_imp.lib \
nghttp2d.lib nghttp2d.dll nghttp2d_imp.lib
EXT_LIBS = $(ZLIB_ROOT)/zlib.lib ws2_32.lib
OBJ_DIR = MSVC_obj
NGHTTP2_PDB_R = $(OBJ_DIR)/nghttp2.pdb
NGHTTP2_PDB_D = $(OBJ_DIR)/nghttp2d.pdb
CC = cl
CFLAGS = -I./includes -I$(ZLIB_ROOT) -DHAVE_WINSOCK2_H -Dssize_t=long
CFLAGS_R = -nologo -MD -W3 -Zi -Fd./$(NGHTTP2_PDB_R)
CFLAGS_D = -nologo -MDd -W3 -Zi -Fd./$(NGHTTP2_PDB_D) \
-Ot -D_DEBUG -GF -RTCs -RTCu # -RTCc -GS
LDFLAGS = -nologo -machine:i386 -map -debug -incremental:no # -verbose
NGHTTP2_SRC = nghttp2_buf.c \
nghttp2_callbacks.c \
nghttp2_frame.c \
nghttp2_helper.c \
nghttp2_hd.c \
nghttp2_hd_huffman.c \
nghttp2_hd_huffman_data.c \
nghttp2_map.c \
nghttp2_npn.c \
nghttp2_option.c \
nghttp2_outbound_item.c \
nghttp2_priority_spec.c \
nghttp2_pq.c \
nghttp2_queue.c \
nghttp2_session.c \
nghttp2_stream.c \
nghttp2_submit.c \
nghttp2_version.c
NGHTTP2_OBJ_R = $(addprefix $(OBJ_DIR)/r_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
NGHTTP2_OBJ_D = $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
all: intro $(OBJ_DIR) $(TARGETS)
@echo 'Welcome to NgHTTP2 (release + debug).'
@echo 'Do a "make -f Makefile.MSVC install" at own risk!'
intro:
@echo 'Building NgHTTP (MSVC) ver. "$(VERSION)".'
test_ver:
@echo '$$(VERSION): "$(VERSION)".'
@echo '$$(_VERSION): "$(_VERSION)".'
@echo '$$(VER_MAJOR): "$(VER_MAJOR)".'
@echo '$$(VER_MINOR): "$(VER_MINOR)".'
@echo '$$(VER_MICRO): "$(VER_MICRO)".'
$(OBJ_DIR):
- mkdir $(OBJ_DIR)
install: includes/nghttp2/nghttp2.h includes/nghttp2/nghttp2ver.h \
nghttp2.dll nghttp2.lib nghttp2_imp.lib \
nghttp2d.dll nghttp2d.lib nghttp2d_imp.lib \
copy_headers_and_libs install_nghttp2_pyd_$(USE_CYTHON)
#
# This MUST be done before using the 'install_nghttp2_pyd_1' rule.
#
copy_headers_and_libs:
- mkdir $(INSTALL_HDR)/nghttp2
cp --update $(addprefix includes/nghttp2/, nghttp2.h nghttp2ver.h) $(INSTALL_HDR)/nghttp2
cp --update nghttp2.dll nghttp2d.dll $(NGHTTP2_PDB_R) $(NGHTTP2_PDB_D) $(INSTALL_BIN)
cp --update nghttp2.lib nghttp2d.lib nghttp2_imp.lib nghttp2d_imp.lib $(INSTALL_LIB)
@echo
nghttp2.lib: $(NGHTTP2_OBJ_R)
lib -nologo -out:$@ $^
@echo
nghttp2d.lib: $(NGHTTP2_OBJ_D)
lib -nologo -out:$@ $^
@echo
nghttp2.dll nghttp2_imp.lib: $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(OBJ_DIR)/r_nghttp2.def
link $(LDFLAGS) -dll -out:nghttp2.dll -implib:nghttp2_imp.lib -def:$(OBJ_DIR)/r_nghttp2.def \
$(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(EXT_LIBS)
@echo
nghttp2d.dll nghttp2d_imp.lib: $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(OBJ_DIR)/d_nghttp2.def
link $(LDFLAGS) -dll -out:nghttp2d.dll -implib:nghttp2d_imp.lib -def:$(OBJ_DIR)/d_nghttp2.def \
$(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(EXT_LIBS)
@echo
install_nghttp2_pyd_0: ;
install_nghttp2_pyd_1: $(addprefix ../python/, setup.py.in nghttp2.pyx)
cd ../python ; \
echo '# $(GENERATED). DO NOT EDIT.' > setup.py ; \
sed -e 's/@top_srcdir@/../' \
-e 's/@top_builddir@/../' \
-e 's/@PACKAGE_VERSION@/$(VERSION)/' setup.py.in >> setup.py ; \
cython -v nghttp2.pyx ; \
python setup.py install
clean_nghttp2_pyd_0: ;
clean_nghttp2_pyd_1:
cd ../python ; \
rm -f setup.py nghttp2.c ; \
rm -fR build/*
$(OBJ_DIR)/r_%.obj: %.c
$(CC) $(CFLAGS_R) $(CFLAGS) -Fo$@ -c $<
@echo
$(OBJ_DIR)/d_%.obj: %.c
$(CC) $(CFLAGS_D) $(CFLAGS) -Fo$@ -c $<
@echo
$(OBJ_DIR)/r_nghttp2.res: nghttp2.rc
rc -nologo -D_RELEASE -Fo $@ $<
@echo
$(OBJ_DIR)/d_nghttp2.res: nghttp2.rc
rc -nologo -D_DEBUG -Fo $@ $<
@echo
includes/nghttp2/nghttp2ver.h: includes/nghttp2/nghttp2ver.h.in
sed < includes/nghttp2/nghttp2ver.h.in \
-e 's/@PACKAGE_VERSION@/$(VERSION)/g' \
-e 's/@PACKAGE_VERSION_NUM@/($(VERSION_NUM))/g' > $@
touch --reference=includes/nghttp2/nghttp2ver.h.in $@
define RES_FILE
#include <winver.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION $(VER_MAJOR), $(VER_MINOR), $(VER_MICRO), 0
PRODUCTVERSION $(VER_MAJOR), $(VER_MINOR), $(VER_MICRO), 0
FILEFLAGSMASK 0x3fL
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
#ifdef _DEBUG
#define VER_STR "$(VERSION).0 (MSVC debug)"
#define DBG "d"
FILEFLAGS 0x1L
#else
#define VER_STR "$(VERSION).0 (MSVC release)"
#define DBG ""
FILEFLAGS 0x0L
#endif
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "http://tatsuhiro-t.github.io/nghttp2/"
VALUE "FileDescription", "nghttp2; HTTP/2 C library"
VALUE "FileVersion", VER_STR
VALUE "InternalName", "nghttp2" DBG
VALUE "LegalCopyright", "The MIT License"
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "nghttp2" DBG ".dll"
VALUE "ProductName", "NGHTTP2."
VALUE "ProductVersion", VER_STR
VALUE "PrivateBuild", "The privat build of <gvanem@yahoo.no>."
VALUE "SpecialBuild", ""
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
endef
export RES_FILE
nghttp2.rc: Makefile.MSVC
@echo 'Generating $@...'
@echo ' /* $(GENERATED). DO NOT EDIT.' > $@
@echo ' */' >> $@
@echo "$$RES_FILE" >> $@
$(OBJ_DIR)/r_nghttp2.def: Makefile.MSVC
@echo 'Generating $@...'
@echo '; $(GENERATED). DO NOT EDIT.' > $@
@echo ';' >> $@
@echo 'LIBRARY nghttp2.dll' >> $@
@echo 'EXPORTS' >> $@
nm $(NGHTTP2_OBJ_R) | grep ' T .*_nghttp2' | sed 's/^.* _/ /' >> $@
@echo 'NGHTTP2_STATIC_TABLE_LENGTH DATA' >> $@
$(OBJ_DIR)/d_nghttp2.def: Makefile.MSVC
@echo 'Generating $@...'
@echo '; $(GENERATED). DO NOT EDIT.' > $@
@echo ';' >> $@
@echo 'LIBRARY nghttp2d.dll' >> $@
@echo 'EXPORTS' >> $@
nm $(NGHTTP2_OBJ_D) | grep ' T .*_nghttp2' | sed 's/^.* _/ /' >> $@
@echo 'NGHTTP2_STATIC_TABLE_LENGTH DATA' >> $@
clean:
rm -f $(OBJ_DIR)/* nghttp2_imp.exp nghttp2_imp.exp \
nghttp2.map nghttp2d.map nghttp2.rc includes/nghttp2/nghttp2ver.h
@echo
vclean realclean: clean clean_nghttp2_pyd_$(USE_CYTHON)
rm -f $(TARGETS) nghttp2.pdb nghttp2d.pdb nghttp2_imp.exp nghttp2d_imp.exp .depend.MSVC
- rmdir $(OBJ_DIR)
#
# Use gcc to generated the dependencies. No MSVC specific args please!
#
REPLACE_R = 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/r_\1.obj: /'
REPLACE_D = 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/d_\1.obj: /'
depend: includes/nghttp2/nghttp2ver.h
@echo '# $(GENERATED). DO NOT EDIT.' > .depend.MSVC
gcc -MM $(CFLAGS) $(NGHTTP2_SRC) >> .depend.tmp
@echo '#' >> .depend.MSVC
@echo '# Release lib objects:' >> .depend.MSVC
sed -e $(REPLACE_R) .depend.tmp >> .depend.MSVC
@echo '#' >> .depend.MSVC
@echo '# Debug lib objects:' >> .depend.MSVC
sed -e $(REPLACE_D) .depend.tmp >> .depend.MSVC
rm -f .depend.tmp
-include .depend.MSVC

File diff suppressed because it is too large Load Diff

View File

@@ -45,7 +45,12 @@ int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial)
void nghttp2_buf_free(nghttp2_buf *buf)
{
if(buf == NULL) {
return;
}
free(buf->begin);
buf->begin = NULL;
}
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
@@ -75,16 +80,6 @@ int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
return 0;
}
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap)
{
return nghttp2_buf_reserve(buf, nghttp2_buf_pos_offset(buf) + new_rel_cap);
}
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap)
{
return nghttp2_buf_reserve(buf, nghttp2_buf_last_offset(buf) + new_rel_cap);
}
void nghttp2_buf_reset(nghttp2_buf *buf)
{
buf->pos = buf->last = buf->mark = buf->begin;
@@ -164,10 +159,41 @@ int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
return 0;
}
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length)
{
int rv;
nghttp2_buf_chain *chain;
if(chunk_length < bufs->offset) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
rv = buf_chain_new(&chain, chunk_length);
if(rv != 0) {
return rv;
}
nghttp2_bufs_free(bufs);
bufs->head = chain;
bufs->cur = bufs->head;
nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
bufs->chunk_length = chunk_length;
bufs->chunk_used = 1;
return 0;
}
void nghttp2_bufs_free(nghttp2_bufs *bufs)
{
nghttp2_buf_chain *chain, *next_chain;
if(bufs == NULL) {
return;
}
for(chain = bufs->head; chain;) {
next_chain = chain->next;
@@ -175,6 +201,8 @@ void nghttp2_bufs_free(nghttp2_bufs *bufs)
chain = next_chain;
}
bufs->head = NULL;
}
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len)
@@ -205,7 +233,12 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len)
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs)
{
if(bufs == NULL) {
return;
}
free(bufs->head);
bufs->head = NULL;
}
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs)
@@ -236,8 +269,8 @@ ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs)
static ssize_t bufs_avail(nghttp2_bufs *bufs)
{
return (ssize_t)nghttp2_buf_avail(&bufs->cur->buf) +
(bufs->chunk_length - bufs->offset) * (bufs->max_chunk - bufs->chunk_used);
return (ssize_t)(nghttp2_buf_avail(&bufs->cur->buf) +
(bufs->chunk_length - bufs->offset) * (bufs->max_chunk - bufs->chunk_used));
}
static int bufs_alloc_chain(nghttp2_bufs *bufs)

View File

@@ -107,22 +107,6 @@ void nghttp2_buf_free(nghttp2_buf *buf);
*/
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap);
/*
* This function behaves like nghttp2_buf_reserve(), but new capacity
* is calculated as nghttp2_buf_pos_offset(buf) + new_rel_cap. In
* other words, this function reserves memory at least |new_rel_cap|
* bytes from buf->pos.
*/
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap);
/*
* This function behaves like nghttp2_buf_reserve(), but new capacity
* is calculated as nghttp2_buf_last_offset(buf) + new_rel_cap. In
* other words, this function reserves memory at least |new_rel_cap|
* bytes from buf->last.
*/
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap);
/*
* Resets pos, last, mark member of |buf| to buf->begin.
*/
@@ -228,6 +212,22 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len);
*/
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs);
/*
* Reallocates internal buffer using |chunk_length|. The max_chunk,
* chunk_keep and offset do not change. After successful allocation
* of new buffer, previous buffers are deallocated without copying
* anything into new buffers. chunk_used is reset to 1.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_INVALID_ARGUMENT
* chunk_length < offset
*/
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length);
/*
* Appends the |data| of length |len| to the |bufs|. The write starts
* at bufs->cur->buf.last. A new buffers will be allocated to store

139
lib/nghttp2_callbacks.c Normal file
View File

@@ -0,0 +1,139 @@
/*
* 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.
*/
#include "nghttp2_callbacks.h"
#include <stdlib.h>
int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr)
{
*callbacks_ptr = calloc(1, sizeof(nghttp2_session_callbacks));
if(*callbacks_ptr == NULL) {
return NGHTTP2_ERR_NOMEM;
}
return 0;
}
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks)
{
free(callbacks);
}
void nghttp2_session_callbacks_set_send_callback
(nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback)
{
cbs->send_callback = send_callback;
}
void nghttp2_session_callbacks_set_recv_callback
(nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback)
{
cbs->recv_callback = recv_callback;
}
void nghttp2_session_callbacks_set_on_frame_recv_callback
(nghttp2_session_callbacks *cbs,
nghttp2_on_frame_recv_callback on_frame_recv_callback)
{
cbs->on_frame_recv_callback = on_frame_recv_callback;
}
void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
(nghttp2_session_callbacks *cbs,
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback)
{
cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
}
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback
(nghttp2_session_callbacks *cbs,
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback)
{
cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
}
void nghttp2_session_callbacks_set_before_frame_send_callback
(nghttp2_session_callbacks *cbs,
nghttp2_before_frame_send_callback before_frame_send_callback)
{
cbs->before_frame_send_callback = before_frame_send_callback;
}
void nghttp2_session_callbacks_set_on_frame_send_callback
(nghttp2_session_callbacks *cbs,
nghttp2_on_frame_send_callback on_frame_send_callback)
{
cbs->on_frame_send_callback = on_frame_send_callback;
}
void nghttp2_session_callbacks_set_on_frame_not_send_callback
(nghttp2_session_callbacks *cbs,
nghttp2_on_frame_not_send_callback on_frame_not_send_callback)
{
cbs->on_frame_not_send_callback = on_frame_not_send_callback;
}
void nghttp2_session_callbacks_set_on_stream_close_callback
(nghttp2_session_callbacks *cbs,
nghttp2_on_stream_close_callback on_stream_close_callback)
{
cbs->on_stream_close_callback = on_stream_close_callback;
}
void nghttp2_session_callbacks_set_on_begin_headers_callback
(nghttp2_session_callbacks *cbs,
nghttp2_on_begin_headers_callback on_begin_headers_callback)
{
cbs->on_begin_headers_callback = on_begin_headers_callback;
}
void nghttp2_session_callbacks_set_on_header_callback
(nghttp2_session_callbacks *cbs,
nghttp2_on_header_callback on_header_callback)
{
cbs->on_header_callback = on_header_callback;
}
void nghttp2_session_callbacks_set_select_padding_callback
(nghttp2_session_callbacks *cbs,
nghttp2_select_padding_callback select_padding_callback)
{
cbs->select_padding_callback = select_padding_callback;
}
void nghttp2_session_callbacks_set_data_source_read_length_callback
(nghttp2_session_callbacks *cbs,
nghttp2_data_source_read_length_callback data_source_read_length_callback)
{
cbs->read_length_callback = data_source_read_length_callback;
}
void nghttp2_session_callbacks_set_on_begin_frame_callback
(nghttp2_session_callbacks *cbs,
nghttp2_on_begin_frame_callback on_begin_frame_callback)
{
cbs->on_begin_frame_callback = on_begin_frame_callback;
}

111
lib/nghttp2_callbacks.h Normal file
View File

@@ -0,0 +1,111 @@
/*
* 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.
*/
#ifndef NGHTTP2_CALLBACKS_H
#define NGHTTP2_CALLBACKS_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
/*
* Callback functions.
*/
struct nghttp2_session_callbacks {
/**
* Callback function invoked when the session wants to send data to
* the remote peer. This callback is not necessary if the
* application uses solely `nghttp2_session_mem_send()` to serialize
* data to transmit.
*/
nghttp2_send_callback send_callback;
/**
* Callback function invoked when the session wants to receive data
* from the remote peer. This callback is not necessary if the
* application uses solely `nghttp2_session_mem_recv()` to process
* received data.
*/
nghttp2_recv_callback recv_callback;
/**
* Callback function invoked by `nghttp2_session_recv()` when a
* frame is received.
*/
nghttp2_on_frame_recv_callback on_frame_recv_callback;
/**
* Callback function invoked by `nghttp2_session_recv()` when an
* invalid non-DATA frame is received.
*/
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback;
/**
* Callback function invoked when a chunk of data in DATA frame is
* received.
*/
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback;
/**
* Callback function invoked before a non-DATA frame is sent.
*/
nghttp2_before_frame_send_callback before_frame_send_callback;
/**
* Callback function invoked after a frame is sent.
*/
nghttp2_on_frame_send_callback on_frame_send_callback;
/**
* The callback function invoked when a non-DATA frame is not sent
* because of an error.
*/
nghttp2_on_frame_not_send_callback on_frame_not_send_callback;
/**
* Callback function invoked when the stream is closed.
*/
nghttp2_on_stream_close_callback on_stream_close_callback;
/**
* Callback function invoked when the reception of header block in
* HEADERS or PUSH_PROMISE is started.
*/
nghttp2_on_begin_headers_callback on_begin_headers_callback;
/**
* Callback function invoked when a header name/value pair is
* received.
*/
nghttp2_on_header_callback on_header_callback;
/**
* Callback function invoked when the library asks application how
* many padding bytes are required for the transmission of the given
* frame.
*/
nghttp2_select_padding_callback select_padding_callback;
/**
* The callback function used to determine the length allowed in
* `nghttp2_data_source_read_callback()`
*/
nghttp2_data_source_read_length_callback read_length_callback;
/**
* Sets callback function invoked when a frame header is received.
*/
nghttp2_on_begin_frame_callback on_begin_frame_callback;
};
#endif /* NGHTTP2_CALLBACKS_H */

View File

@@ -33,35 +33,33 @@
#include "nghttp2_net.h"
#include "nghttp2_priority_spec.h"
int nghttp2_frame_is_data_frame(uint8_t *head)
{
return head[2] == 0;
}
void nghttp2_frame_pack_frame_hd(uint8_t* buf, const nghttp2_frame_hd *hd)
{
nghttp2_put_uint16be(&buf[0], hd->length);
buf[2]= hd->type;
buf[3] = hd->flags;
nghttp2_put_uint32be(&buf[4], hd->stream_id);
nghttp2_put_uint32be(&buf[0], (uint32_t)(hd->length << 8));
buf[3]= hd->type;
buf[4] = hd->flags;
nghttp2_put_uint32be(&buf[5], hd->stream_id);
/* ignore hd->reserved for now */
}
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf)
{
hd->length = nghttp2_get_uint16(&buf[0]) & NGHTTP2_FRAME_LENGTH_MASK;
hd->type = buf[2];
hd->flags = buf[3];
hd->stream_id = nghttp2_get_uint32(&buf[4]) & NGHTTP2_STREAM_ID_MASK;
hd->length = nghttp2_get_uint32(&buf[0]) >> 8;
hd->type = buf[3];
hd->flags = buf[4];
hd->stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK;
hd->reserved = 0;
}
static void frame_set_hd(nghttp2_frame_hd *hd, uint16_t length,
uint8_t type, uint8_t flags,
int32_t stream_id)
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length,
uint8_t type, uint8_t flags,
int32_t stream_id)
{
hd->length = length;
hd->type = type;
hd->flags = flags;
hd->stream_id = stream_id;
hd->reserved = 0;
}
void nghttp2_frame_headers_init(nghttp2_headers *frame,
@@ -70,7 +68,7 @@ void nghttp2_frame_headers_init(nghttp2_headers *frame,
const nghttp2_priority_spec *pri_spec,
nghttp2_nv *nva, size_t nvlen)
{
frame_set_hd(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id);
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id);
frame->padlen = 0;
frame->nva = nva;
frame->nvlen = nvlen;
@@ -91,8 +89,8 @@ void nghttp2_frame_headers_free(nghttp2_headers *frame)
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
const nghttp2_priority_spec *pri_spec)
{
frame_set_hd(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY,
NGHTTP2_FLAG_NONE, stream_id);
nghttp2_frame_hd_init(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY,
NGHTTP2_FLAG_NONE, stream_id);
frame->pri_spec = *pri_spec;
}
@@ -101,10 +99,10 @@ void nghttp2_frame_priority_free(nghttp2_priority *frame)
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame,
int32_t stream_id,
nghttp2_error_code error_code)
uint32_t error_code)
{
frame_set_hd(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE,
stream_id);
nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE,
stream_id);
frame->error_code = error_code;
}
@@ -115,8 +113,8 @@ void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame)
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
nghttp2_settings_entry *iv, size_t niv)
{
frame_set_hd(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
NGHTTP2_SETTINGS, flags, 0);
nghttp2_frame_hd_init(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
NGHTTP2_SETTINGS, flags, 0);
frame->niv = niv;
frame->iv = iv;
}
@@ -131,11 +129,12 @@ void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame,
int32_t promised_stream_id,
nghttp2_nv *nva, size_t nvlen)
{
frame_set_hd(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id);
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id);
frame->padlen = 0;
frame->nva = nva;
frame->nvlen = nvlen;
frame->promised_stream_id = promised_stream_id;
frame->reserved = 0;
}
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame)
@@ -146,7 +145,7 @@ void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame)
void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
const uint8_t *opaque_data)
{
frame_set_hd(&frame->hd, 8, NGHTTP2_PING, flags, 0);
nghttp2_frame_hd_init(&frame->hd, 8, NGHTTP2_PING, flags, 0);
if(opaque_data) {
memcpy(frame->opaque_data, opaque_data, sizeof(frame->opaque_data));
} else {
@@ -158,15 +157,16 @@ void nghttp2_frame_ping_free(nghttp2_ping *frame)
{}
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
nghttp2_error_code error_code,
uint32_t error_code,
uint8_t *opaque_data, size_t opaque_data_len)
{
frame_set_hd(&frame->hd, 8+opaque_data_len, NGHTTP2_GOAWAY,
NGHTTP2_FLAG_NONE, 0);
nghttp2_frame_hd_init(&frame->hd, 8+opaque_data_len, NGHTTP2_GOAWAY,
NGHTTP2_FLAG_NONE, 0);
frame->last_stream_id = last_stream_id;
frame->error_code = error_code;
frame->opaque_data = opaque_data;
frame->opaque_data_len = opaque_data_len;
frame->reserved = 0;
}
void nghttp2_frame_goaway_free(nghttp2_goaway *frame)
@@ -179,8 +179,10 @@ void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
int32_t stream_id,
int32_t window_size_increment)
{
frame_set_hd(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags, stream_id);
nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags,
stream_id);
frame->window_size_increment = window_size_increment;
frame->reserved = 0;
}
void nghttp2_frame_window_update_free(nghttp2_window_update *frame)
@@ -201,8 +203,8 @@ void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
payloadlen = NGHTTP2_ALTSVC_MINLEN + protocol_id_len + host_len + origin_len;
frame_set_hd(&frame->hd, payloadlen, NGHTTP2_EXT_ALTSVC, NGHTTP2_FLAG_NONE,
stream_id);
nghttp2_frame_hd_init(&frame->hd, payloadlen, NGHTTP2_EXT_ALTSVC,
NGHTTP2_FLAG_NONE, stream_id);
altsvc->max_age = max_age;
altsvc->port = port;
@@ -227,36 +229,20 @@ void nghttp2_frame_altsvc_free(nghttp2_extension *frame)
free(altsvc->protocol_id);
}
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata)
{
frame->hd = pdata->hd;
frame->padlen = pdata->padlen;
/* flags may have NGHTTP2_FLAG_END_STREAM or
NGHTTP2_FLAG_END_SEGMENT even if the sent chunk is not the end of
the stream */
if(!pdata->eof) {
frame->hd.flags &= ~(NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT);
}
}
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen)
{
return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0);
}
void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
uint8_t flags,
int32_t stream_id,
const nghttp2_data_provider *data_prd)
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
int32_t stream_id)
{
/* At this moment, the length of DATA frame is unknown */
frame_set_hd(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id);
frame->data_prd = *data_prd;
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id);
frame->padlen = 0;
frame->eof = 0;
}
void nghttp2_frame_private_data_free(nghttp2_private_data *frame)
void nghttp2_frame_data_free(nghttp2_data *frame)
{}
size_t nghttp2_frame_priority_len(uint8_t flags)
@@ -478,33 +464,11 @@ int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
return 0;
}
static nghttp2_error_code normalize_error_code(uint32_t error_code)
{
switch(error_code) {
case NGHTTP2_NO_ERROR:
case NGHTTP2_PROTOCOL_ERROR:
case NGHTTP2_INTERNAL_ERROR:
case NGHTTP2_FLOW_CONTROL_ERROR:
case NGHTTP2_SETTINGS_TIMEOUT:
case NGHTTP2_STREAM_CLOSED:
case NGHTTP2_FRAME_SIZE_ERROR:
case NGHTTP2_REFUSED_STREAM:
case NGHTTP2_CANCEL:
case NGHTTP2_COMPRESSION_ERROR:
case NGHTTP2_CONNECT_ERROR:
case NGHTTP2_ENHANCE_YOUR_CALM:
case NGHTTP2_INADEQUATE_SECURITY:
return error_code;
default:
return NGHTTP2_INTERNAL_ERROR;
}
}
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
const uint8_t *payload,
size_t payloadlen)
{
frame->error_code = normalize_error_code(nghttp2_get_uint32(payload));
frame->error_code = nghttp2_get_uint32(payload);
}
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame)
@@ -713,7 +677,7 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
size_t var_gift_payloadlen)
{
frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
frame->error_code = normalize_error_code(nghttp2_get_uint32(payload + 4));
frame->error_code = nghttp2_get_uint32(payload + 4);
frame->opaque_data = var_gift_payload;
frame->opaque_data_len = var_gift_payloadlen;
@@ -1037,8 +1001,14 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
return 0;
}
break;
default:
return 0;
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
if(iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
return 0;
}
break;
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
break;
}
}
return 1;
@@ -1047,6 +1017,7 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
static void frame_set_pad(nghttp2_buf *buf, size_t padlen)
{
size_t trail_padlen;
size_t newlen;
DEBUGF(fprintf(stderr, "send: padlen=%zu, shift left 1 bytes\n", padlen));
@@ -1054,9 +1025,10 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen)
--buf->pos;
buf->pos[3] |= NGHTTP2_FLAG_PADDED;
buf->pos[4] |= NGHTTP2_FLAG_PADDED;
nghttp2_put_uint16be(buf->pos, nghttp2_get_uint16(buf->pos) + padlen);
newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen;
nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3]));
trail_padlen = padlen - 1;
buf->pos[NGHTTP2_FRAME_HDLEN] = trail_padlen;
@@ -1087,12 +1059,12 @@ int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | |Frame header | Frame payload... :
* +-+---------------+---------------------------------------------+
* | |Frame header | Frame payload... :
* +-+---------------+---------------------------------------------+
* | |Frame header | Frame payload... :
* +-+---------------+---------------------------------------------+
* | |Frame header | Frame payload... :
* +-+-----------------+-------------------------------------------+
* | |Frame header | Frame payload... :
* +-+-----------------+-------------------------------------------+
* | |Frame header | Frame payload... :
* +-+-----------------+-------------------------------------------+
*
* We arranged padding so that it is included in the first frame
* completely. For padded frame, we are going to adjust buf->pos of

View File

@@ -33,7 +33,6 @@
#include "nghttp2_hd.h"
#include "nghttp2_buf.h"
#define NGHTTP2_FRAME_LENGTH_MASK ((1 << 14) - 1)
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
@@ -41,9 +40,12 @@
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
/* The number of bytes of frame header. */
#define NGHTTP2_FRAME_HDLEN 8
#define NGHTTP2_FRAME_HDLEN 9
#define NGHTTP2_MAX_PAYLOADLEN 16383
#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1)
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
#define NGHTTP2_MAX_PAYLOADLEN 16384
/* The one frame buffer length for tranmission. We may use several of
them to support CONTINUATION. To account for Pad Length field, we
allocate extra 1 byte, which saves extra large memcopying. */
@@ -53,11 +55,12 @@
/* Number of inbound buffer */
#define NGHTTP2_FRAMEBUF_MAX_NUM 5
/* The maximum length of DATA frame payload. */
#define NGHTTP2_DATA_PAYLOADLEN 4096
/* The default length of DATA frame payload. This should be small enough
* for the data payload and the header to fit into 1 TLS record */
#define NGHTTP2_DATA_PAYLOADLEN ((NGHTTP2_MAX_FRAME_SIZE_MIN) - (NGHTTP2_FRAME_HDLEN))
/* Maximum headers payload length, calculated in compressed form.
This applies to both transmission and reception. */
This applies to transmission only. */
#define NGHTTP2_MAX_HEADERSLEN 65536
/* The number of bytes for each SETTINGS entry */
@@ -77,50 +80,26 @@
NGHTTP2_ALTSVC_FIXED_PARTLEN + Host-Len. */
#define NGHTTP2_ALTSVC_MINLEN 8
/* Category of frames. */
typedef enum {
/* non-DATA frame */
NGHTTP2_CAT_CTRL,
/* DATA frame */
NGHTTP2_CAT_DATA
} nghttp2_frame_category;
/* Maximum length of padding in bytes. */
#define NGHTTP2_MAX_PADLEN 256
/* Union of extension frame payload */
typedef union {
nghttp2_ext_altsvc altsvc;
} nghttp2_ext_frame_payload;
/**
* @struct
*
* The DATA frame used in the library privately. It has the following
* members:
*/
typedef struct {
nghttp2_frame_hd hd;
/**
* The data to be sent for this DATA frame.
*/
nghttp2_data_provider data_prd;
/**
* The number of bytes added as padding. This includes Pad Length
* field (1 byte).
*/
size_t padlen;
/**
* The flag to indicate whether EOF was reached or not. Initially
* |eof| is 0. It becomes 1 after all data were read. This is used
* exclusively by nghttp2 library and not in the spec.
*/
uint8_t eof;
} nghttp2_private_data;
int nghttp2_frame_is_data_frame(uint8_t *head);
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf);
/**
* Initializes frame header |hd| with given parameters. Reserved bit
* is set to 0.
*/
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length,
uint8_t type, uint8_t flags,
int32_t stream_id);
/**
* Returns the number of priority field depending on the |flags|. If
* |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor
@@ -471,7 +450,7 @@ void nghttp2_frame_priority_free(nghttp2_priority *frame);
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame,
int32_t stream_id,
nghttp2_error_code error_code);
uint32_t error_code);
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
@@ -513,7 +492,7 @@ void nghttp2_frame_ping_free(nghttp2_ping *frame);
* free it. If the |opaque_data_len| is 0, opaque_data could be NULL.
*/
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
nghttp2_error_code error_code,
uint32_t error_code,
uint8_t *opaque_data, size_t opaque_data_len);
void nghttp2_frame_goaway_free(nghttp2_goaway *frame);
@@ -545,8 +524,6 @@ void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
*/
void nghttp2_frame_altsvc_free(nghttp2_extension *frame);
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
/*
* Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does
@@ -554,12 +531,10 @@ void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
*/
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
uint8_t flags,
int32_t stream_id,
const nghttp2_data_provider *data_prd);
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
int32_t stream_id);
void nghttp2_frame_private_data_free(nghttp2_private_data *frame);
void nghttp2_frame_data_free(nghttp2_data *frame);
/*
* Makes copy of |iv| and return the copy. The |niv| is the number of

File diff suppressed because it is too large Load Diff

View File

@@ -47,10 +47,8 @@
encoder only uses the memory up to this value. */
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
typedef enum {
NGHTTP2_HD_ROLE_DEFLATE,
NGHTTP2_HD_ROLE_INFLATE
} nghttp2_hd_role;
/* Exported for unit test */
extern const size_t NGHTTP2_STATIC_TABLE_LENGTH;
typedef enum {
NGHTTP2_HD_FLAG_NONE = 0,
@@ -58,18 +56,12 @@ typedef enum {
NGHTTP2_HD_FLAG_NAME_ALLOC = 1,
/* Indicates value was dynamically allocated and must be freed */
NGHTTP2_HD_FLAG_VALUE_ALLOC = 1 << 1,
/* Indicates that the entry is in the reference set */
NGHTTP2_HD_FLAG_REFSET = 1 << 2,
/* Indicates that the entry is emitted in the current header
processing. */
NGHTTP2_HD_FLAG_EMIT = 1 << 3,
NGHTTP2_HD_FLAG_IMPLICIT_EMIT = 1 << 4,
/* Indicates that the name was gifted to the entry and no copying
necessary. */
NGHTTP2_HD_FLAG_NAME_GIFT = 1 << 5,
NGHTTP2_HD_FLAG_NAME_GIFT = 1 << 2,
/* Indicates that the value was gifted to the entry and no copying
necessary. */
NGHTTP2_HD_FLAG_VALUE_GIFT = 1 << 6
NGHTTP2_HD_FLAG_VALUE_GIFT = 1 << 3
} nghttp2_hd_flags;
typedef struct {
@@ -81,6 +73,11 @@ typedef struct {
uint8_t flags;
} nghttp2_hd_entry;
typedef struct {
nghttp2_hd_entry ent;
size_t index;
} nghttp2_hd_static_entry;
typedef struct {
nghttp2_hd_entry **buffer;
size_t mask;
@@ -97,7 +94,6 @@ typedef enum {
typedef enum {
NGHTTP2_HD_STATE_OPCODE,
NGHTTP2_HD_STATE_CLEAR_REFSET,
NGHTTP2_HD_STATE_READ_TABLE_SIZE,
NGHTTP2_HD_STATE_READ_INDEX,
NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
@@ -119,8 +115,6 @@ typedef struct {
size_t hd_table_bufsize;
/* The effective header table size. */
size_t hd_table_bufsize_max;
/* Role of this context; deflate or infalte */
nghttp2_hd_role role;
/* If inflate/deflate error occurred, this value is set to 1 and
further invocation of inflate/deflate will fail with
NGHTTP2_ERR_HEADER_COMP. */
@@ -131,9 +125,8 @@ struct nghttp2_hd_deflater {
nghttp2_hd_context ctx;
/* The upper limit of the header table size the deflater accepts. */
size_t deflate_hd_table_bufsize_max;
/* Set to this nonzero to clear reference set on each deflation each
time. */
uint8_t no_refset;
/* Minimum header table size notified in the next context update */
size_t min_hd_table_bufsize_max;
/* If nonzero, send header table size using encoding context update
in the next deflate process */
uint8_t notify_table_size_change;
@@ -152,16 +145,10 @@ struct nghttp2_hd_inflater {
/* Pointer to the name/value pair buffer which is used in the
current header emission. */
uint8_t *nv_keep;
/* Pointers to the name/value pair which is referred as indexed
name. This entry must be in header table. */
nghttp2_hd_entry *ent_name;
/* The number of bytes to read */
size_t left;
/* The index in indexed repr or indexed name */
size_t index;
/* The index of header table to toggle off the entry from reference
set at the end of decompression. */
size_t end_headers_index;
/* The length of new name encoded in literal. For huffman encoded
string, this is the length after it is decoded. */
size_t newnamelen;
@@ -186,7 +173,9 @@ struct nghttp2_hd_inflater {
* set in the |flags|, the content pointed by the |name| with length
* |namelen| is copied. Likewise, if NGHTTP2_HD_FLAG_VALUE_ALLOC bit
* set in the |flags|, the content pointed by the |value| with length
* |valuelen| is copied.
* |valuelen| is copied. The |name_hash| and |value_hash| are hash
* value for |name| and |value| respectively. The hash function is
* defined in nghttp2_hd.c.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -196,7 +185,8 @@ struct nghttp2_hd_inflater {
*/
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags,
uint8_t *name, size_t namelen,
uint8_t *value, size_t valuelen);
uint8_t *value, size_t valuelen,
uint32_t name_hash, uint32_t value_hash);
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);

View File

@@ -24,6 +24,8 @@
*/
#include "nghttp2_hd_huffman.h"
/* Generated by mkhufftbl.py */
const nghttp2_huff_sym huff_sym_table[] = {
{ 13, 0x1ff8u },
{ 23, 0x7fffd8u },

View File

@@ -55,23 +55,6 @@ uint32_t nghttp2_get_uint32(const uint8_t *data)
return ntohl(n);
}
int nghttp2_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t min_length)
{
if(min_length > *buflen_ptr) {
uint8_t *temp;
min_length = (min_length+4095)/4096*4096;
temp = realloc(*buf_ptr, min_length);
if(temp == NULL) {
return NGHTTP2_ERR_NOMEM;
} else {
*buf_ptr = temp;
*buflen_ptr = min_length;
}
}
return 0;
}
void* nghttp2_memdup(const void* src, size_t n)
{
void* dest;
@@ -88,16 +71,108 @@ void* nghttp2_memdup(const void* src, size_t n)
return dest;
}
/* Generated by gendowncasetbl.py */
static const int DOWNCASE_TBL[] = {
0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */,
4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */,
8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */,
12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */,
16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */,
20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */,
24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */,
28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */,
32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */,
36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */,
40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */,
44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */,
48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */,
52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */,
60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */,
64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */,
100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */,
104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */,
108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */,
112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */,
116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */,
120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */,
92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */,
96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */,
100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */,
124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */,
128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */,
132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */,
136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */,
140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */,
144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */,
148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */,
152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */,
156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */,
160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */,
164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */,
168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */,
172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */,
176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */,
180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */,
184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */,
188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */,
192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */,
196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */,
200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */,
204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */,
208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */,
212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */,
216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */,
220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */,
224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */,
228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */,
232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */,
236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */,
240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */,
244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */,
248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */,
252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */,
};
void nghttp2_downcase(uint8_t *s, size_t len)
{
size_t i;
for(i = 0; i < len; ++i) {
if('A' <= s[i] && s[i] <= 'Z') {
s[i] += 'a'-'A';
}
s[i] = DOWNCASE_TBL[s[i]];
}
}
/*
* local_window_size
* ^ *
* | * recv_window_size
* | * * ^
* | * * |
* 0+++++++++
* | * * \
* | * * | This rage is hidden in flow control. But it must be
* v * * / kept in order to restore it when window size is enlarged.
* recv_reduction
* (+ for negative direction)
*
* recv_window_size could be negative if we decrease
* local_window_size more than recv_window_size:
*
* local_window_size
* ^ *
* | *
* | *
* 0++++++++
* | * ^ recv_window_size (negative)
* | * |
* v * *
* recv_reduction
*/
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
int32_t *recv_window_size_ptr,
int32_t *recv_reduction_ptr,
@@ -123,10 +198,11 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
if(*recv_window_size_ptr < 0) {
*recv_window_size_ptr += recv_reduction_diff;
} else {
/* If *recv_window_size_ptr > 0, then those bytes are
considered to be backed to the remote peer (by
WINDOW_UPDATE with the adjusted *delta_ptr), so it is
effectively 0 now. */
/* If *recv_window_size_ptr > 0, then those bytes are going to
be backed to the remote peer (by WINDOW_UPDATE with the
adjusted *delta_ptr), so it is effectively 0 now. We set
to *recv_reduction_diff, because caller does not take into
account it in *delta_ptr. */
*recv_window_size_ptr = recv_reduction_diff;
}
/* recv_reduction_diff must be paied from *delta_ptr, since it
@@ -225,6 +301,8 @@ const char* nghttp2_strerror(int error_code)
return "Out of memory";
case NGHTTP2_ERR_CALLBACK_FAILURE:
return "The user callback function failed";
case NGHTTP2_ERR_BAD_PREFACE:
return "Received bad connection preface";
default:
return "Unknown error code";
}
@@ -235,6 +313,7 @@ void nghttp2_free(void *ptr)
free(ptr);
}
/* Generated by gennmchartbl.py */
static int VALID_HD_NAME_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
@@ -323,8 +402,9 @@ int nghttp2_check_header_name(const uint8_t *name, size_t len)
return 1;
}
/* Generated by genvchartbl.py */
static int VALID_HD_VALUE_CHARS[] = {
1 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,

View File

@@ -58,25 +58,6 @@ uint16_t nghttp2_get_uint16(const uint8_t *data);
*/
uint32_t nghttp2_get_uint32(const uint8_t *data);
/*
* Ensures that buffer |*buf_ptr| with |*buflen_ptr| length has at
* least |min_length| bytes. If |min_length| > |*buflen_ptr|,
* allocates new buffer having at least |min_length| bytes and assigns
* its pointer to |*buf_ptr| and allocated number of bytes to
* |*buflen_ptr|. The memory pointed by |*buf_ptr| previously may
* change. No memory copy is done between old and new buffer.
* |*buf_ptr| and |*buflen_ptr| are only updated iff this function
* succeeds.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t min_length);
/*
* Allocates |n| bytes of memory and copy the memory region pointed by
* |src| with the length |n| bytes into it. Returns the allocated memory.

View File

@@ -26,7 +26,7 @@
#include <string.h>
#define INITIAL_TABLE_LENGTH 16
#define INITIAL_TABLE_LENGTH 256
int nghttp2_map_init(nghttp2_map *map)
{
@@ -138,6 +138,7 @@ static int resize(nghttp2_map *map, size_t new_tablelen)
free(map->table);
map->tablelen = new_tablelen;
map->table = new_table;
return 0;
}

View File

@@ -40,18 +40,10 @@ void nghttp2_option_del(nghttp2_option *option)
free(option);
}
void nghttp2_option_set_no_auto_stream_window_update(nghttp2_option *option,
int val)
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val)
{
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE;
option->no_auto_stream_window_update = val;
}
void nghttp2_option_set_no_auto_connection_window_update
(nghttp2_option *option, int val)
{
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE;
option->no_auto_connection_window_update = val;
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE;
option->no_auto_window_update = val;
}
void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
@@ -60,3 +52,10 @@ void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
option->opt_set_mask |= NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS;
option->peer_max_concurrent_streams = val;
}
void nghttp2_option_set_recv_client_preface
(nghttp2_option *option, int val)
{
option->opt_set_mask |= NGHTTP2_OPT_RECV_CLIENT_PREFACE;
option->recv_client_preface = val;
}

View File

@@ -37,22 +37,12 @@
typedef enum {
/**
* This option prevents the library from sending WINDOW_UPDATE for a
* stream automatically. If this option is set to nonzero, the
* library won't send WINDOW_UPDATE for a stream and the application
* is responsible for sending WINDOW_UPDATE using
* `nghttp2_submit_window_update`. By default, this option is set to
* zero.
* connection automatically. If this option is set to nonzero, the
* library won't send WINDOW_UPDATE for DATA until application calls
* nghttp2_session_consume() to indicate the amount of consumed
* DATA. By default, this option is set to zero.
*/
NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE = 1,
/**
* This option prevents the library from sending WINDOW_UPDATE for a
* connection automatically. If this option is set to nonzero, the
* library won't send WINDOW_UPDATE for a connection and the
* application is responsible for sending WINDOW_UPDATE with stream
* ID 0 using `nghttp2_submit_window_update`. By default, this
* option is set to zero.
*/
NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1,
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1,
/**
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
* remote endpoint as if it is received in SETTINGS frame. Without
@@ -66,7 +56,8 @@ typedef enum {
* will be overwritten if the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
*/
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 2
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
NGHTTP2_OPT_RECV_CLIENT_PREFACE = 1 << 2,
} nghttp2_option_flag;
/**
@@ -83,13 +74,13 @@ struct nghttp2_option {
*/
uint32_t peer_max_concurrent_streams;
/**
* NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE
* NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
*/
uint8_t no_auto_stream_window_update;
uint8_t no_auto_window_update;
/**
* NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE
* NGHTTP2_OPT_RECV_CLIENT_PREFACE
*/
uint8_t no_auto_connection_window_update;
uint8_t recv_client_preface;
};
#endif /* NGHTTP2_OPTION_H */

View File

@@ -28,53 +28,45 @@
void nghttp2_outbound_item_free(nghttp2_outbound_item *item)
{
nghttp2_frame *frame;
if(item == NULL) {
return;
}
if(item->frame_cat == NGHTTP2_CAT_CTRL) {
nghttp2_frame *frame;
frame = nghttp2_outbound_item_get_ctrl_frame(item);
switch(frame->hd.type) {
case NGHTTP2_HEADERS:
nghttp2_frame_headers_free(&frame->headers);
if(item->aux_data) {
free(((nghttp2_headers_aux_data*)item->aux_data)->data_prd);
}
break;
case NGHTTP2_PRIORITY:
nghttp2_frame_priority_free(&frame->priority);
break;
case NGHTTP2_RST_STREAM:
nghttp2_frame_rst_stream_free(&frame->rst_stream);
break;
case NGHTTP2_SETTINGS:
nghttp2_frame_settings_free(&frame->settings);
break;
case NGHTTP2_PUSH_PROMISE:
nghttp2_frame_push_promise_free(&frame->push_promise);
break;
case NGHTTP2_PING:
nghttp2_frame_ping_free(&frame->ping);
break;
case NGHTTP2_GOAWAY:
nghttp2_frame_goaway_free(&frame->goaway);
break;
case NGHTTP2_WINDOW_UPDATE:
nghttp2_frame_window_update_free(&frame->window_update);
break;
case NGHTTP2_EXT_ALTSVC:
nghttp2_frame_altsvc_free(&frame->ext);
free(frame->ext.payload);
break;
}
} else if(item->frame_cat == NGHTTP2_CAT_DATA) {
nghttp2_private_data *data_frame;
data_frame = nghttp2_outbound_item_get_data_frame(item);
nghttp2_frame_private_data_free(data_frame);
} else {
/* Unreachable */
assert(0);
frame = &item->frame;
switch(frame->hd.type) {
case NGHTTP2_DATA:
nghttp2_frame_data_free(&frame->data);
break;
case NGHTTP2_HEADERS:
nghttp2_frame_headers_free(&frame->headers);
break;
case NGHTTP2_PRIORITY:
nghttp2_frame_priority_free(&frame->priority);
break;
case NGHTTP2_RST_STREAM:
nghttp2_frame_rst_stream_free(&frame->rst_stream);
break;
case NGHTTP2_SETTINGS:
nghttp2_frame_settings_free(&frame->settings);
break;
case NGHTTP2_PUSH_PROMISE:
nghttp2_frame_push_promise_free(&frame->push_promise);
break;
case NGHTTP2_PING:
nghttp2_frame_ping_free(&frame->ping);
break;
case NGHTTP2_GOAWAY:
nghttp2_frame_goaway_free(&frame->goaway);
break;
case NGHTTP2_WINDOW_UPDATE:
nghttp2_frame_window_update_free(&frame->window_update);
break;
case NGHTTP2_EXT_ALTSVC:
nghttp2_frame_altsvc_free(&frame->ext);
free(frame->ext.payload);
break;
}
free(item->frame);
free(item->aux_data);
}

View File

@@ -39,21 +39,46 @@
/* Highest weight for PING */
#define NGHTTP2_OB_PING_WEIGHT 302
/* struct used for HEADERS and PUSH_PROMISE frame */
typedef struct {
nghttp2_data_provider *data_prd;
nghttp2_data_provider data_prd;
void *stream_user_data;
} nghttp2_headers_aux_data;
/* struct used for DATA frame */
typedef struct {
/**
* The data to be sent for this DATA frame.
*/
nghttp2_data_provider data_prd;
/**
* The flags of DATA frame. We use separate flags here and
* nghttp2_data frame. The latter contains flags actually sent to
* peer. This |flags| may contain NGHTTP2_FLAG_END_STREAM and only
* when |eof| becomes nonzero, flags in nghttp2_data has
* NGHTTP2_FLAG_END_STREAM set.
*/
uint8_t flags;
/**
* The flag to indicate whether EOF was reached or not. Initially
* |eof| is 0. It becomes 1 after all data were read.
*/
uint8_t eof;
} nghttp2_data_aux_data;
/* Additional data which cannot be stored in nghttp2_frame struct */
typedef union {
nghttp2_data_aux_data data;
nghttp2_headers_aux_data headers;
} nghttp2_aux_data;
typedef struct {
nghttp2_frame frame;
nghttp2_aux_data aux_data;
int64_t seq;
/* Reset count of weight. See comment for last_cycle in
nghttp2_session.h */
uint64_t cycle;
void *frame;
void *aux_data;
/* Type of |frame|. NGHTTP2_CTRL: nghttp2_frame*, NGHTTP2_DATA:
nghttp2_private_data* */
nghttp2_frame_category frame_cat;
/* The priority used in priority comparion. Larger is served
ealier. */
int32_t weight;
@@ -67,11 +92,4 @@ typedef struct {
*/
void nghttp2_outbound_item_free(nghttp2_outbound_item *item);
/* Macros to cast nghttp2_outbound_item.frame to the proper type. */
#define nghttp2_outbound_item_get_ctrl_frame(ITEM) ((nghttp2_frame*)ITEM->frame)
#define nghttp2_outbound_item_get_ctrl_frame_type(ITEM) \
(((nghttp2_frame*)ITEM->frame)->hd.type)
#define nghttp2_outbound_item_get_data_frame(ITEM) \
((nghttp2_private_data*)ITEM->frame)
#endif /* NGHTTP2_OUTBOUND_ITEM_H */

File diff suppressed because it is too large Load Diff

View File

@@ -38,13 +38,14 @@
#include "nghttp2_outbound_item.h"
#include "nghttp2_int.h"
#include "nghttp2_buf.h"
#include "nghttp2_callbacks.h"
/*
* Option flags.
*/
typedef enum {
NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE = 1 << 0,
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE = 1 << 1,
} nghttp2_optmask;
typedef enum {
@@ -65,6 +66,8 @@ typedef struct {
/* Internal state when receiving incoming frame */
typedef enum {
/* Receiving frame header */
NGHTTP2_IB_READ_CLIENT_PREFACE,
NGHTTP2_IB_READ_FIRST_SETTINGS,
NGHTTP2_IB_READ_HEAD,
NGHTTP2_IB_READ_NBYTE,
NGHTTP2_IB_READ_HEADER_BLOCK,
@@ -81,7 +84,7 @@ typedef enum {
NGHTTP2_IB_IGN_DATA
} nghttp2_inbound_state;
#define NGHTTP2_INBOUND_NUM_IV 5
#define NGHTTP2_INBOUND_NUM_IV 7
typedef struct {
nghttp2_frame frame;
@@ -105,11 +108,11 @@ typedef struct {
size_t payloadleft;
/* padding length for the current frame */
size_t padlen;
/* Sum of payload of (HEADERS | PUSH_PROMISE) + possible
CONTINUATION received so far. */
size_t headers_payload_length;
nghttp2_inbound_state state;
uint8_t raw_sbuf[8];
/* Small buffer. Currently the largest contiguous chunk to buffer
is frame header. We buffer part of payload, but they are smaller
than frame header. */
uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
} nghttp2_inbound_frame;
typedef struct {
@@ -117,6 +120,8 @@ typedef struct {
uint32_t enable_push;
uint32_t max_concurrent_streams;
uint32_t initial_window_size;
uint32_t max_frame_size;
uint32_t max_header_list_size;
} nghttp2_settings_storage;
typedef enum {
@@ -132,10 +137,13 @@ typedef enum {
struct nghttp2_session {
nghttp2_map /* <nghttp2_stream*> */ streams;
nghttp2_stream_roots roots;
/* Queue for outbound frames other than stream-creating HEADERS */
/* Queue for outbound frames other than stream-creating HEADERS and
DATA */
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq;
/* Queue for outbound stream-creating HEADERS frame */
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_ss_pq;
/* QUeue for DATA frame */
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_da_pq;
nghttp2_active_outbound_item aob;
nghttp2_inbound_frame iframe;
nghttp2_hd_deflater hd_deflater;
@@ -206,15 +214,10 @@ struct nghttp2_session {
WINDOW_UPDATE. This could be negative after submitting negative
value to WINDOW_UPDATE. */
int32_t recv_window_size;
/* The number of bytes in ignored DATA frame received without
connection-level WINDOW_UPDATE. Since we do not call
on_data_chunk_recv_callback for ignored DATA chunk, if
nghttp2_option_set_no_auto_connection_window_update is used,
application may not have a chance to send connection
WINDOW_UPDATE. To fix this, we accumulate those received bytes,
and if it exceeds certain number, we automatically send
connection-level WINDOW_UPDATE. */
int32_t recv_ign_window_size;
/* The number of bytes consumed by the application and now is
subject to WINDOW_UPDATE. This is only used when auto
WINDOW_UPDATE is turned off. */
int32_t consumed_size;
/* The amount of recv_window_size cut using submitting negative
value to WINDOW_UPDATE */
int32_t recv_reduction;
@@ -257,24 +260,28 @@ int nghttp2_session_is_my_stream_id(nghttp2_session *session,
int32_t stream_id);
/*
* Adds frame |frame| to the outbound queue in |session|. The
* |frame_cat| must be either NGHTTP2_CTRL or NGHTTP2_DATA. If the
* |frame_cat| is NGHTTP2_CTRL, the |frame| must be a pointer to
* nghttp2_frame. If the |frame_cat| is NGHTTP2_DATA, it must be a
* pointer to nghttp2_private_data. |aux_data| is a pointer to the arbitrary
* data. Its interpretation is defined per the type of the frame. When
* this function succeeds, it takes ownership of |frame| and
* |aux_data|, so caller must not free them on success.
* Initializes |item|. No memory allocation is done in this function.
* Don't call nghttp2_outbound_item_free() until frame member is
* initialized.
*/
void nghttp2_session_outbound_item_init(nghttp2_session* session,
nghttp2_outbound_item *item);
/*
* Adds |item| to the outbound queue in |session|. When this function
* succeeds, it takes ownership of |item|. So caller must not free it
* on success.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_STREAM_CLOSED
* Stream already closed (DATA frame only)
*/
int nghttp2_session_add_frame(nghttp2_session *session,
nghttp2_frame_category frame_cat,
void *abs_frame, void *aux_data);
int nghttp2_session_add_item(nghttp2_session *session,
nghttp2_outbound_item *item);
/*
* Adds RST_STREAM frame for the stream |stream_id| with the error
@@ -293,7 +300,7 @@ int nghttp2_session_add_frame(nghttp2_session *session,
*/
int nghttp2_session_add_rst_stream(nghttp2_session *session,
int32_t stream_id,
nghttp2_error_code error_code);
uint32_t error_code);
/*
* Adds PING frame. This is a convenient functin built on top of
@@ -327,7 +334,7 @@ int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
*/
int nghttp2_session_add_goaway(nghttp2_session *session,
int32_t last_stream_id,
nghttp2_error_code error_code,
uint32_t error_code,
const uint8_t *opaque_data,
size_t opaque_data_len);
@@ -399,7 +406,7 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
* The callback function failed.
*/
int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
nghttp2_error_code error_code);
uint32_t error_code);
/*
* Deletes |stream| from memory. After this function returns, stream
@@ -644,13 +651,8 @@ nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session,
/*
* Packs DATA frame |frame| in wire frame format and stores it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|. It packs header in first 8 bytes starting
* |*bufoff_ptr| offset. The |*bufoff_ptr| is calculated based on
* usage of padding. Remaining bytes are the DATA apyload and are
* filled using |frame->data_prd|. The length of payload is at most
* |datamax| bytes.
* |bufs|. Payload will be read using |aux_data->data_prd|. The
* length of payload is at most |datamax| bytes.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -667,7 +669,8 @@ nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session,
int nghttp2_session_pack_data(nghttp2_session *session,
nghttp2_bufs *bufs,
size_t datamax,
nghttp2_private_data *frame);
nghttp2_frame *frame,
nghttp2_data_aux_data *aux_data);
/*
* Returns top of outbound frame queue. This function returns NULL if
@@ -742,6 +745,6 @@ int nghttp2_session_reprioritize_stream
* The |reason| is too long.
*/
int nghttp2_session_terminate_session_with_reason
(nghttp2_session *session, nghttp2_error_code error_code, const char *reason);
(nghttp2_session *session, uint32_t error_code, const char *reason);
#endif /* NGHTTP2_SESSION_H */

View File

@@ -48,6 +48,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->remote_window_size = remote_initial_window_size;
stream->local_window_size = local_initial_window_size;
stream->recv_window_size = 0;
stream->consumed_size = 0;
stream->recv_reduction = 0;
stream->blocked_sent = 0;
@@ -64,6 +65,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->effective_weight = stream->weight;
stream->sum_dep_weight = 0;
stream->sum_norest_weight = 0;
stream->sum_top_weight = 0;
stream->roots = roots;
stream->root_prev = NULL;
@@ -72,12 +74,10 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
void nghttp2_stream_free(nghttp2_stream *stream)
{
if(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
nghttp2_outbound_item_free(stream->data_item);
free(stream->data_item);
}
/* We don't free stream->data_item otherwise. */
/* We don't free stream->data_item. If it is assigned to aob, then
active_outbound_item_reset() will delete it. If it is queued,
then it is deleted when pq is deleted in nghttp2_session_del().
Otherwise, nghttp2_session_del() will delete it. */
}
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag)
@@ -86,13 +86,19 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag)
}
static int stream_push_data(nghttp2_stream *stream, nghttp2_pq *pq,
uint64_t cycle)
uint64_t cycle, nghttp2_outbound_item *active_item)
{
int rv;
assert(stream->data_item);
assert(stream->data_item->queued == 0);
/* If stream->data_item is now sent, don't push it to the queue.
Otherwise, we may push same item twice. */
if(active_item == stream->data_item) {
return 0;
}
if(stream->data_item->weight > stream->effective_weight) {
stream->data_item->weight = stream->effective_weight;
}
@@ -158,6 +164,20 @@ int32_t nghttp2_stream_dep_distributed_effective_weight
return nghttp2_max(1, weight);
}
static int32_t stream_dep_distributed_top_effective_weight
(nghttp2_stream *stream, int32_t weight)
{
if(stream->sum_top_weight == 0) {
return stream->effective_weight;
}
weight = stream->effective_weight * weight / stream->sum_top_weight;
return nghttp2_max(1, weight);
}
static void stream_update_dep_set_rest(nghttp2_stream *stream);
/* Updates effective_weight of descendant streams in subtree of
|stream|. We assume that stream->effective_weight is already set
right. */
@@ -166,9 +186,10 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream)
nghttp2_stream *si;
DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight "
"stream(%p)=%d, weight=%d, sum_norest_weight=%d\n",
"stream(%p)=%d, weight=%d, sum_norest_weight=%d, "
"sum_top_weight=%d\n",
stream, stream->stream_id, stream->weight,
stream->sum_norest_weight));
stream->sum_norest_weight, stream->sum_top_weight));
/* stream->sum_norest_weight == 0 means there is no
NGHTTP2_STREAM_DPRI_TOP under stream */
@@ -177,13 +198,47 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream)
return;
}
/* If there is no direct descendant whose dpri is
NGHTTP2_STREAM_DPRI_TOP, indirect descendants have the chance to
send data, so recursively set weight for descendants. */
if(stream->sum_top_weight == 0) {
for(si = stream->dep_next; si; si = si->sib_next) {
if(si->dpri != NGHTTP2_STREAM_DPRI_REST) {
si->effective_weight = nghttp2_stream_dep_distributed_effective_weight
(stream, si->weight);
}
stream_update_dep_effective_weight(si);
}
return;
}
/* If there is at least one direct descendant whose dpri is
NGHTTP2_STREAM_DPRI_TOP, we won't give a chance to indirect
descendants, since closed or blocked stream's weight is
distributed among its siblings */
for(si = stream->dep_next; si; si = si->sib_next) {
if(si->dpri != NGHTTP2_STREAM_DPRI_REST) {
si->effective_weight = nghttp2_stream_dep_distributed_effective_weight
if(si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
si->effective_weight = stream_dep_distributed_top_effective_weight
(stream, si->weight);
DEBUGF(fprintf(stderr, "stream: stream=%d top eweight=%d\n",
si->stream_id, si->effective_weight));
continue;
}
stream_update_dep_effective_weight(si);
if(si->dpri == NGHTTP2_STREAM_DPRI_NO_DATA) {
DEBUGF(fprintf(stderr, "stream: stream=%d no_data, ignored\n",
si->stream_id));
/* Since we marked NGHTTP2_STREAM_DPRI_TOP under si, we make
them NGHTTP2_STREAM_DPRI_REST again. */
stream_update_dep_set_rest(si->dep_next);
} else {
DEBUGF(fprintf(stderr, "stream: stream=%d rest, ignored\n",
si->stream_id));
}
}
}
@@ -193,6 +248,8 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream)
return;
}
DEBUGF(fprintf(stderr, "stream: stream=%d is rest\n", stream->stream_id));
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
return;
}
@@ -211,7 +268,33 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream)
/*
* Performs dfs starting |stream|, search stream which can become
* NGHTTP2_STREAM_DPRI_TOP and queues its data_item.
* NGHTTP2_STREAM_DPRI_TOP and set its dpri.
*/
static void stream_update_dep_set_top(nghttp2_stream *stream)
{
nghttp2_stream *si;
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return;
}
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
DEBUGF(fprintf(stderr, "stream: stream=%d data is top\n",
stream->stream_id));
stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
return;
}
for(si = stream->dep_next; si; si = si->sib_next) {
stream_update_dep_set_top(si);
}
}
/*
* Performs dfs starting |stream|, and dueue stream whose dpri is
* NGHTTP2_STREAM_DPRI_TOP and has not been queued yet.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -219,35 +302,33 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream)
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
static int stream_update_dep_set_top(nghttp2_stream *stream, nghttp2_pq *pq,
uint64_t cycle)
static int stream_update_dep_queue_top(nghttp2_stream *stream, nghttp2_pq *pq,
uint64_t cycle,
nghttp2_outbound_item *active_item)
{
int rv;
nghttp2_stream *si;
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
return 0;
}
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
DEBUGF(fprintf(stderr, "stream: stream=%d data is top\n",
stream->stream_id));
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
if(!stream->data_item->queued) {
rv = stream_push_data(stream, pq, cycle);
DEBUGF(fprintf(stderr, "stream: stream=%d enqueue\n",
stream->stream_id));
rv = stream_push_data(stream, pq, cycle, active_item);
if(rv != 0) {
return rv;
}
}
stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
return 0;
}
for(si = stream->dep_next; si; si = si->sib_next) {
rv = stream_update_dep_set_top(si, pq, cycle);
rv = stream_update_dep_queue_top(si, pq, cycle, active_item);
if(rv != 0) {
return rv;
@@ -258,14 +339,18 @@ static int stream_update_dep_set_top(nghttp2_stream *stream, nghttp2_pq *pq,
}
/*
* Updates stream->sum_norest_weight recursively. We have to gather
* effective sum of weight of descendants. If stream->dpri ==
* NGHTTP2_STREAM_DPRI_NO_DATA, we have to go deeper and check that
* any of its descendants has dpri value of NGHTTP2_STREAM_DPRI_TOP.
* If so, we have to add weight of its direct descendants to
* stream->sum_norest_weight. To make this work, this function
* returns 1 if any of its descendants has dpri value of
* NGHTTP2_STREAM_DPRI_TOP, otherwise 0.
* Updates stream->sum_norest_weight and stream->sum_top_weight
* recursively. We have to gather effective sum of weight of
* descendants. If stream->dpri == NGHTTP2_STREAM_DPRI_NO_DATA, we
* have to go deeper and check that any of its descendants has dpri
* value of NGHTTP2_STREAM_DPRI_TOP. If so, we have to add weight of
* its direct descendants to stream->sum_norest_weight. To make this
* work, this function returns 1 if any of its descendants has dpri
* value of NGHTTP2_STREAM_DPRI_TOP, otherwise 0.
*
* Calculating stream->sum_top-weight is very simple compared to
* stream->sum_norest_weight. It just adds up the weight of direct
* descendants whose dpri is NGHTTP2_STREAM_DPRI_TOP.
*/
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream)
{
@@ -273,6 +358,7 @@ static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream)
int rv;
stream->sum_norest_weight = 0;
stream->sum_top_weight = 0;
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return 1;
@@ -290,15 +376,19 @@ static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream)
rv = 1;
stream->sum_norest_weight += si->weight;
}
if(si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
stream->sum_top_weight += si->weight;
}
}
return rv;
}
static int stream_update_dep_on_attach_data(nghttp2_stream *stream,
nghttp2_pq *pq, uint64_t cycle)
nghttp2_pq *pq, uint64_t cycle,
nghttp2_outbound_item *active_item)
{
int rv;
nghttp2_stream *root_stream;
stream->dpri = NGHTTP2_STREAM_DPRI_REST;
@@ -309,44 +399,37 @@ static int stream_update_dep_on_attach_data(nghttp2_stream *stream,
DEBUGF(fprintf(stderr, "root=%p, stream=%p\n", root_stream, stream));
rv = stream_update_dep_set_top(root_stream, pq, cycle);
if(rv != 0) {
return rv;
}
stream_update_dep_set_top(root_stream);
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
return 0;
return stream_update_dep_queue_top(root_stream, pq, cycle, active_item);
}
static int stream_update_dep_on_detach_data(nghttp2_stream *stream,
nghttp2_pq *pq, uint64_t cycle)
nghttp2_pq *pq, uint64_t cycle,
nghttp2_outbound_item *active_item)
{
int rv;
nghttp2_stream *root_stream;
stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA;
root_stream = nghttp2_stream_get_dep_root(stream);
rv = stream_update_dep_set_top(root_stream, pq, cycle);
if(rv != 0) {
return rv;
}
stream_update_dep_set_top(root_stream);
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
return 0;
return stream_update_dep_queue_top(root_stream, pq, cycle, active_item);
}
int nghttp2_stream_attach_data(nghttp2_stream *stream,
nghttp2_outbound_item *data_item,
nghttp2_pq *pq,
uint64_t cycle)
uint64_t cycle,
nghttp2_outbound_item *active_item)
{
assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0);
assert(stream->data_item == NULL);
@@ -356,11 +439,12 @@ int nghttp2_stream_attach_data(nghttp2_stream *stream,
stream->data_item = data_item;
return stream_update_dep_on_attach_data(stream, pq, cycle);
return stream_update_dep_on_attach_data(stream, pq, cycle, active_item);
}
int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq,
uint64_t cycle)
uint64_t cycle,
nghttp2_outbound_item *active_item)
{
DEBUGF(fprintf(stderr, "stream: stream=%d detach data=%p\n",
stream->stream_id, stream->data_item));
@@ -368,11 +452,12 @@ int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq,
stream->data_item = NULL;
stream->flags &= ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL;
return stream_update_dep_on_detach_data(stream, pq, cycle);
return stream_update_dep_on_detach_data(stream, pq, cycle, active_item);
}
int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags,
nghttp2_pq *pq, uint64_t cycle)
nghttp2_pq *pq, uint64_t cycle,
nghttp2_outbound_item *active_item)
{
assert(stream->data_item);
@@ -381,20 +466,25 @@ int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags,
stream->flags |= flags;
return stream_update_dep_on_detach_data(stream, pq, cycle);
return stream_update_dep_on_detach_data(stream, pq, cycle, active_item);
}
int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream,
nghttp2_pq *pq, uint64_t cycle)
int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream, uint8_t flags,
nghttp2_pq *pq, uint64_t cycle,
nghttp2_outbound_item *active_item)
{
assert(stream->data_item);
DEBUGF(fprintf(stderr, "stream: stream=%d resume data=%p\n",
stream->stream_id, stream->data_item));
DEBUGF(fprintf(stderr, "stream: stream=%d resume data=%p flags=%02x\n",
stream->stream_id, stream->data_item, flags));
stream->flags &= ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL;
stream->flags &= ~flags;
return stream_update_dep_on_attach_data(stream, pq, cycle);
if(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
return 0;
}
return stream_update_dep_on_attach_data(stream, pq, cycle, active_item);
}
int nghttp2_stream_check_deferred_data(nghttp2_stream *stream)
@@ -524,10 +614,111 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
++stream->roots->num_streams;
}
static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream)
{
dep_stream->dep_next = stream;
stream->dep_prev = dep_stream;
}
static void link_sib(nghttp2_stream *prev_stream, nghttp2_stream *stream)
{
prev_stream->sib_next = stream;
stream->sib_prev = prev_stream;
}
static void insert_link_dep(nghttp2_stream *dep_stream,
nghttp2_stream *stream)
{
nghttp2_stream *sib_next;
assert(stream->sib_prev == NULL);
sib_next = dep_stream->dep_next;
link_sib(stream, sib_next);
sib_next->dep_prev = NULL;
link_dep(dep_stream, stream);
}
static void unlink_sib(nghttp2_stream *stream)
{
nghttp2_stream *prev, *next, *dep_next;
prev = stream->sib_prev;
dep_next = stream->dep_next;
assert(prev);
if(dep_next) {
/*
* prev--stream(--sib_next--...)
* |
* dep_next
*/
dep_next->dep_prev = NULL;
link_sib(prev, dep_next);
if(stream->sib_next) {
link_sib(stream_last_sib(dep_next), stream->sib_next);
}
} else {
/*
* prev--stream(--sib_next--...)
*/
next = stream->sib_next;
prev->sib_next = next;
if(next) {
next->sib_prev = prev;
}
}
}
static void unlink_dep(nghttp2_stream *stream)
{
nghttp2_stream *prev, *next, *dep_next;
prev = stream->dep_prev;
dep_next = stream->dep_next;
assert(prev);
if(dep_next) {
/*
* prev
* |
* stream(--sib_next--...)
* |
* dep_next
*/
link_dep(prev, dep_next);
if(stream->sib_next) {
link_sib(stream_last_sib(dep_next), stream->sib_next);
}
} else if(stream->sib_next) {
/*
* prev
* |
* stream--sib_next
*/
next = stream->sib_next;
next->sib_prev = NULL;
link_dep(prev, next);
} else {
prev->dep_next = NULL;
}
}
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
nghttp2_stream *stream)
{
nghttp2_stream *last_sib;
nghttp2_stream *root_stream;
assert(stream->data_item == NULL);
@@ -542,12 +733,9 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
dep_stream->sum_dep_weight += stream->weight;
if(dep_stream->dep_next == NULL) {
dep_stream->dep_next = stream;
stream->dep_prev = dep_stream;
link_dep(dep_stream, stream);
} else {
last_sib = stream_last_sib(dep_stream->dep_next);
last_sib->sib_next = stream;
stream->sib_prev = last_sib;
insert_link_dep(dep_stream, stream);
}
stream_update_dep_sum_norest_weight(root_stream);
@@ -558,7 +746,7 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
void nghttp2_stream_dep_remove(nghttp2_stream *stream)
{
nghttp2_stream *prev, *next, *dep_next, *dep_prev, *si, *root_stream;
nghttp2_stream *prev, *next, *dep_prev, *si, *root_stream;
int32_t sum_dep_weight_delta;
root_stream = NULL;
@@ -586,46 +774,12 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
}
if(stream->sib_prev) {
prev = stream->sib_prev;
dep_next = stream->dep_next;
if(dep_next) {
dep_next->dep_prev = NULL;
prev->sib_next = dep_next;
dep_next->sib_prev = prev;
} else {
next = stream->sib_next;
prev->sib_next = next;
if(next) {
next->sib_prev = prev;
}
}
unlink_sib(stream);
} else if(stream->dep_prev) {
prev = stream->dep_prev;
dep_next = stream->dep_next;
if(dep_next) {
prev->dep_next = dep_next;
dep_next->dep_prev = prev;
} else if(stream->sib_next) {
next = stream->sib_next;
prev->dep_next = next;
next->dep_prev = prev;
next->sib_prev = NULL;
} else {
prev->dep_next = NULL;
dep_next = NULL;
}
unlink_dep(stream);
} else {
nghttp2_stream_roots_remove(stream->roots, stream);
dep_next = NULL;
/* stream is a root of tree. Removing stream makes its
descendants a root of its own subtree. */
@@ -645,14 +799,6 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
}
}
if(dep_next && stream->sib_next) {
prev = stream_last_sib(dep_next);
next = stream->sib_next;
prev->sib_next = next;
next->sib_prev = prev;
}
if(root_stream) {
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
@@ -672,13 +818,13 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream,
nghttp2_pq *pq,
uint64_t cycle)
uint64_t cycle,
nghttp2_outbound_item *active_item)
{
nghttp2_stream *last_sib;
nghttp2_stream *dep_next;
nghttp2_stream *root_stream;
size_t delta_substreams;
int rv;
DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d "
"stream(%p)=%d\n",
@@ -700,23 +846,19 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
stream_update_dep_set_rest(dep_next);
dep_stream->dep_next = stream;
stream->dep_prev = dep_stream;
link_dep(dep_stream, stream);
if(stream->dep_next) {
last_sib = stream_last_sib(stream->dep_next);
last_sib->sib_next = dep_next;
dep_next->sib_prev = last_sib;
link_sib(last_sib, dep_next);
dep_next->dep_prev = NULL;
} else {
stream->dep_next = dep_next;
dep_next->dep_prev = stream;
link_dep(stream, dep_next);
}
} else {
dep_stream->dep_next = stream;
stream->dep_prev = dep_stream;
link_dep(dep_stream, stream);
assert(dep_stream->sum_dep_weight == 0);
dep_stream->sum_dep_weight = stream->weight;
@@ -724,26 +866,21 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
root_stream = stream_update_dep_length(dep_stream, delta_substreams);
rv = stream_update_dep_set_top(root_stream, pq, cycle);
if(rv != 0) {
return rv;
}
stream_update_dep_set_top(root_stream);
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
return 0;
return stream_update_dep_queue_top(root_stream, pq, cycle, active_item);
}
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream,
nghttp2_pq *pq,
uint64_t cycle)
uint64_t cycle,
nghttp2_outbound_item *active_item)
{
nghttp2_stream *last_sib;
nghttp2_stream *root_stream;
int rv;
DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d "
"stream(%p)=%d\n",
@@ -755,13 +892,9 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
if(dep_stream->dep_next) {
dep_stream->sum_dep_weight += stream->weight;
last_sib = stream_last_sib(dep_stream->dep_next);
last_sib->sib_next = stream;
stream->sib_prev = last_sib;
insert_link_dep(dep_stream, stream);
} else {
dep_stream->dep_next = stream;
stream->dep_prev = dep_stream;
link_dep(dep_stream, stream);
assert(dep_stream->sum_dep_weight == 0);
dep_stream->sum_dep_weight = stream->weight;
@@ -769,16 +902,12 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
root_stream = stream_update_dep_length(dep_stream, stream->num_substreams);
rv = stream_update_dep_set_top(root_stream, pq, cycle);
if(rv != 0) {
return rv;
}
stream_update_dep_set_top(root_stream);
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
return 0;
return stream_update_dep_queue_top(root_stream, pq, cycle, active_item);
}
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
@@ -833,10 +962,9 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
}
int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq,
uint64_t cycle)
uint64_t cycle,
nghttp2_outbound_item *active_item)
{
int rv;
DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n",
stream, stream->stream_id));
@@ -846,20 +974,17 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq,
stream->effective_weight = stream->weight;
rv = stream_update_dep_set_top(stream, pq, cycle);
if(rv != 0) {
return rv;
}
stream_update_dep_set_top(stream);
stream_update_dep_sum_norest_weight(stream);
stream_update_dep_effective_weight(stream);
return 0;
return stream_update_dep_queue_top(stream, pq, cycle, active_item);
}
int nghttp2_stream_dep_all_your_stream_are_belong_to_us
(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle)
(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle,
nghttp2_outbound_item *active_item)
{
nghttp2_stream *first, *si;
@@ -893,28 +1018,28 @@ int nghttp2_stream_dep_all_your_stream_are_belong_to_us
stream->sum_dep_weight += si->weight;
stream->num_substreams += si->num_substreams;
si->sib_prev = prev;
prev->sib_next = si;
link_sib(prev, si);
prev = si;
}
if(stream->dep_next) {
nghttp2_stream *last_sib;
nghttp2_stream *sib_next;
last_sib = stream_last_sib(stream->dep_next);
sib_next = stream->dep_next;
last_sib->sib_next = first;
first->sib_prev = last_sib;
sib_next->dep_prev = NULL;
link_sib(first, sib_next);
link_dep(stream, prev);
} else {
stream->dep_next = first;
first->dep_prev = stream;
link_dep(stream, first);
}
}
nghttp2_stream_roots_remove_all(stream->roots);
return nghttp2_stream_dep_make_root(stream, pq, cycle);
return nghttp2_stream_dep_make_root(stream, pq, cycle, active_item);
}
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream)

View File

@@ -151,6 +151,10 @@ struct nghttp2_stream {
WINDOW_UPDATE. This could be negative after submitting negative
value to WINDOW_UPDATE */
int32_t recv_window_size;
/* The number of bytes consumed by the application and now is
subject to WINDOW_UPDATE. This is only used when auto
WINDOW_UPDATE is turned off. */
int32_t consumed_size;
/* The amount of recv_window_size cut using submitting negative
value to WINDOW_UPDATE */
int32_t recv_reduction;
@@ -168,6 +172,9 @@ struct nghttp2_stream {
descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this
value to calculate effective weight. */
int32_t sum_norest_weight;
/* sum of weight of direct descendants whose dpri value is
NGHTTP2_STREAM_DPRI_TOP */
int32_t sum_top_weight;
nghttp2_stream_state state;
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
uint8_t flags;
@@ -209,16 +216,20 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
* Out of memory
*/
int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags,
nghttp2_pq *pq, uint64_t cycle);
nghttp2_pq *pq, uint64_t cycle,
nghttp2_outbound_item *active_item);
/*
* Detaches deferred data in this stream and it is back to active
* state. The flags NGHTTP2_STREAM_FLAG_DEFERRED_USER and
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL are cleared if they are
* set.
* Put back deferred data in this stream to active state. The |flags|
* are one or more of bitwise OR of the following values:
* NGHTTP2_STREAM_FLAG_DEFERRED_USER and
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are
* cleared if they are set. So even if this function is called, if
* one of flag is still set, data does not become active.
*/
int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream,
nghttp2_pq *pq, uint64_t cycle);
int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream, uint8_t flags,
nghttp2_pq *pq, uint64_t cycle,
nghttp2_outbound_item *active_item);
/*
* Returns nonzero if data item is deferred by whatever reason.
@@ -330,7 +341,8 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream);
int nghttp2_stream_attach_data(nghttp2_stream *stream,
nghttp2_outbound_item *data_item,
nghttp2_pq *pq,
uint64_t cycle);
uint64_t cycle,
nghttp2_outbound_item *active_item);
/*
* Detaches |stream->data_item|. Updates dpri members in this
@@ -344,7 +356,8 @@ int nghttp2_stream_attach_data(nghttp2_stream *stream,
* Out of memory
*/
int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq,
uint64_t cycle);
uint64_t cycle,
nghttp2_outbound_item *active_item);
/*
@@ -360,7 +373,8 @@ int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq,
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream,
nghttp2_pq *pq,
uint64_t cycle);
uint64_t cycle,
nghttp2_outbound_item *active_item);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
@@ -375,7 +389,8 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream,
nghttp2_pq *pq,
uint64_t cycle);
uint64_t cycle,
nghttp2_outbound_item *active_item);
/*
* Removes subtree whose root stream is |stream|. Removing subtree
@@ -401,7 +416,8 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
* Out of memory
*/
int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq,
uint64_t cycle);
uint64_t cycle,
nghttp2_outbound_item *active_item);
/*
* Makes the |stream| as root and all existing root streams become
@@ -414,7 +430,8 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq,
* Out of memory
*/
int nghttp2_stream_dep_all_your_stream_are_belong_to_us
(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle);
(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle,
nghttp2_outbound_item *active_item);
/*
* Returns nonzero if |stream| is in any dependency tree.

View File

@@ -47,9 +47,8 @@ static int32_t submit_headers_shared
{
int rv;
uint8_t flags_copy;
nghttp2_outbound_item *item = NULL;
nghttp2_frame *frame = NULL;
nghttp2_data_provider *data_prd_copy = NULL;
nghttp2_headers_aux_data *aux_data = NULL;
nghttp2_headers_category hcat;
if(stream_id == 0) {
@@ -57,33 +56,22 @@ static int32_t submit_headers_shared
goto fail;
}
if(data_prd != NULL && data_prd->read_callback != NULL) {
data_prd_copy = malloc(sizeof(nghttp2_data_provider));
if(data_prd_copy == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto fail;
}
*data_prd_copy = *data_prd;
}
if(data_prd || stream_user_data) {
aux_data = malloc(sizeof(nghttp2_headers_aux_data));
if(aux_data == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto fail;
}
aux_data->data_prd = data_prd_copy;
aux_data->stream_user_data = stream_user_data;
}
frame = malloc(sizeof(nghttp2_frame));
if(frame == NULL) {
item = malloc(sizeof(nghttp2_outbound_item));
if(item == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto fail;
}
nghttp2_session_outbound_item_init(session, item);
if(data_prd != NULL && data_prd->read_callback != NULL) {
item->aux_data.headers.data_prd = *data_prd;
}
item->aux_data.headers.stream_user_data = stream_user_data;
flags_copy =
(flags & (NGHTTP2_FLAG_END_STREAM |
NGHTTP2_FLAG_END_SEGMENT |
NGHTTP2_FLAG_PRIORITY)) |
(flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) |
NGHTTP2_FLAG_END_HEADERS;
if(stream_id == -1) {
@@ -101,12 +89,12 @@ static int32_t submit_headers_shared
hcat = NGHTTP2_HCAT_HEADERS;
}
frame = &item->frame;
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id,
hcat, pri_spec, nva_copy, nvlen);
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame,
aux_data);
rv = nghttp2_session_add_item(session, item);
if(rv != 0) {
nghttp2_frame_headers_free(&frame->headers);
@@ -123,9 +111,8 @@ static int32_t submit_headers_shared
/* nghttp2_frame_headers_init() takes ownership of nva_copy. */
nghttp2_nv_array_del(nva_copy);
fail2:
free(frame);
free(aux_data);
free(data_prd_copy);
free(item);
return rv;
}
@@ -199,6 +186,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
const nghttp2_priority_spec *pri_spec)
{
int rv;
nghttp2_outbound_item *item;
nghttp2_frame *frame;
nghttp2_priority_spec copy_pri_spec;
@@ -214,19 +202,23 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
adjust_priority_spec_weight(&copy_pri_spec);
frame = malloc(sizeof(nghttp2_frame));
item = malloc(sizeof(nghttp2_outbound_item));
if(frame == NULL) {
if(item == NULL) {
return NGHTTP2_ERR_NOMEM;
}
nghttp2_session_outbound_item_init(session, item);
frame = &item->frame;
nghttp2_frame_priority_init(&frame->priority, stream_id, &copy_pri_spec);
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
rv = nghttp2_session_add_item(session, item);
if(rv != 0) {
nghttp2_frame_priority_free(&frame->priority);
free(frame);
free(item);
return rv;
}
@@ -236,7 +228,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
nghttp2_error_code error_code)
uint32_t error_code)
{
if(stream_id == 0) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
@@ -247,7 +239,7 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
int32_t last_stream_id,
nghttp2_error_code error_code,
uint32_t error_code,
const uint8_t *opaque_data, size_t opaque_data_len)
{
return nghttp2_session_add_goaway(session, last_stream_id,
@@ -265,10 +257,10 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
const nghttp2_nv *nva, size_t nvlen,
void *promised_stream_user_data)
{
nghttp2_outbound_item *item;
nghttp2_frame *frame;
nghttp2_nv *nva_copy;
uint8_t flags_copy;
nghttp2_headers_aux_data *aux_data = NULL;
int32_t promised_stream_id;
int rv;
@@ -280,36 +272,30 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
return NGHTTP2_ERR_PROTO;
}
frame = malloc(sizeof(nghttp2_frame));
if(frame == NULL) {
/* All 32bit signed stream IDs are spent. */
if(session->next_stream_id > INT32_MAX) {
return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
}
item = malloc(sizeof(nghttp2_outbound_item));
if(item == NULL) {
return NGHTTP2_ERR_NOMEM;
}
if(promised_stream_user_data) {
aux_data = malloc(sizeof(nghttp2_headers_aux_data));
if(aux_data == NULL) {
free(frame);
return NGHTTP2_ERR_NOMEM;
}
aux_data->data_prd = NULL;
aux_data->stream_user_data = promised_stream_user_data;
}
nghttp2_session_outbound_item_init(session, item);
item->aux_data.headers.stream_user_data = promised_stream_user_data;
frame = &item->frame;
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen);
if(rv < 0) {
free(aux_data);
free(frame);
free(item);
return rv;
}
flags_copy = NGHTTP2_FLAG_END_HEADERS;
/* All 32bit signed stream IDs are spent. */
if(session->next_stream_id > INT32_MAX) {
free(aux_data);
free(frame);
return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
}
promised_stream_id = session->next_stream_id;
session->next_stream_id += 2;
@@ -317,12 +303,11 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
stream_id, promised_stream_id,
nva_copy, nvlen);
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, aux_data);
rv = nghttp2_session_add_item(session, item);
if(rv != 0) {
nghttp2_frame_push_promise_free(&frame->push_promise);
free(aux_data);
free(frame);
free(item);
return rv;
}
@@ -335,7 +320,7 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
int32_t window_size_increment)
{
int rv;
nghttp2_stream *stream;
nghttp2_stream *stream = 0;
if(window_size_increment == 0) {
return 0;
}
@@ -348,27 +333,30 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
if(rv != 0) {
return rv;
}
/* recv_ign_window_size keeps track of ignored DATA bytes before
any connection-level WINDOW_UPDATE therefore, we can reset it
here. */
session->recv_ign_window_size = 0;
} else {
stream = nghttp2_session_get_stream(session, stream_id);
if(stream) {
rv = nghttp2_adjust_local_window_size(&stream->local_window_size,
&stream->recv_window_size,
&stream->recv_reduction,
&window_size_increment);
if(rv != 0) {
return rv;
}
} else {
if(!stream) {
return 0;
}
rv = nghttp2_adjust_local_window_size(&stream->local_window_size,
&stream->recv_window_size,
&stream->recv_reduction,
&window_size_increment);
if(rv != 0) {
return rv;
}
}
if(window_size_increment > 0) {
if(stream_id == 0) {
session->consumed_size =
nghttp2_max(0, session->consumed_size - window_size_increment);
} else {
stream->consumed_size =
nghttp2_max(0, stream->consumed_size - window_size_increment);
}
return nghttp2_session_add_window_update(session, flags, stream_id,
window_size_increment);
}
@@ -385,6 +373,7 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
int rv;
size_t varlen;
uint8_t *var, *varp;
nghttp2_outbound_item *item;
nghttp2_frame *frame;
nghttp2_ext_altsvc *altsvc;
uint8_t *copy_protocol_id, *copy_host, *copy_origin;
@@ -439,25 +428,28 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
copy_origin = varp;
}
frame = malloc(sizeof(nghttp2_frame));
item = malloc(sizeof(nghttp2_outbound_item));
if(frame == NULL) {
if(item == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto frame_alloc_fail;
}
nghttp2_session_outbound_item_init(session, item);
frame = &item->frame;
frame->ext.payload = altsvc;
nghttp2_frame_altsvc_init(&frame->ext, stream_id, max_age, port,
copy_protocol_id, protocol_id_len,
copy_host, host_len, copy_origin, origin_len);
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
rv = nghttp2_session_add_item(session, item);
if(rv != 0) {
nghttp2_frame_altsvc_free(&frame->ext);
free(frame);
free(item);
free(altsvc);
return rv;
@@ -534,23 +526,35 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
const nghttp2_data_provider *data_prd)
{
int rv;
nghttp2_private_data *data_frame;
uint8_t nflags = flags & (NGHTTP2_FLAG_END_STREAM |
NGHTTP2_FLAG_END_SEGMENT);
nghttp2_outbound_item *item;
nghttp2_frame *frame;
nghttp2_data_aux_data *aux_data;
uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM;
if(stream_id == 0) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
data_frame = malloc(sizeof(nghttp2_private_data));
if(data_frame == NULL) {
item = malloc(sizeof(nghttp2_outbound_item));
if(item == NULL) {
return NGHTTP2_ERR_NOMEM;
}
nghttp2_frame_private_data_init(data_frame, nflags, stream_id, data_prd);
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_DATA, data_frame, NULL);
nghttp2_session_outbound_item_init(session, item);
frame = &item->frame;
aux_data = &item->aux_data.data;
aux_data->data_prd = *data_prd;
aux_data->eof = 0;
aux_data->flags = nflags;
/* flags are sent on transmission */
nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id);
rv = nghttp2_session_add_item(session, item);
if(rv != 0) {
nghttp2_frame_private_data_free(data_frame);
free(data_frame);
nghttp2_frame_data_free(&frame->data);
free(item);
return rv;
}
return 0;

110
m4/ax_boost_asio.m4 Normal file
View File

@@ -0,0 +1,110 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_boost_asio.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_ASIO
#
# DESCRIPTION
#
# Test for Asio library from the Boost C++ libraries. The macro requires a
# preceding call to AX_BOOST_BASE. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_ASIO_LIB)
#
# And sets:
#
# HAVE_BOOST_ASIO
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
# Copyright (c) 2008 Pete Greenwell <pete@mu.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 16
AC_DEFUN([AX_BOOST_ASIO],
[
AC_ARG_WITH([boost-asio],
AS_HELP_STRING([--with-boost-asio@<:@=special-lib@:>@],
[use the ASIO library from boost - it is possible to specify a certain library for the linker
e.g. --with-boost-asio=boost_system-gcc41-mt-1_34 ]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_asio_lib=""
else
want_boost="yes"
ax_boost_user_asio_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK(whether the Boost::ASIO library is available,
ax_cv_boost_asio,
[AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @%:@include <boost/asio.hpp>
]],
[[
boost::asio::io_service io;
boost::system::error_code timer_result;
boost::asio::deadline_timer t(io);
t.cancel();
io.run_one();
return 0;
]])],
ax_cv_boost_asio=yes, ax_cv_boost_asio=no)
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_asio" = "xyes"; then
AC_DEFINE(HAVE_BOOST_ASIO,,[define if the Boost::ASIO library is available])
BN=boost_system
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
if test "x$ax_boost_user_asio_lib" = "x"; then
for ax_lib in `ls $BOOSTLIBDIR/libboost_system*.so* $BOOSTLIBDIR/libboost_system*.dylib* $BOOSTLIBDIR/libboost_system*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_system.*\)\.so.*$;\1;' -e 's;^lib\(boost_system.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_system.*\)\.a.*$;\1;' ` ; do
AC_CHECK_LIB($ax_lib, main, [BOOST_ASIO_LIB="-l$ax_lib" AC_SUBST(BOOST_ASIO_LIB) link_thread="yes" break],
[link_thread="no"])
done
else
for ax_lib in $ax_boost_user_asio_lib $BN-$ax_boost_user_asio_lib; do
AC_CHECK_LIB($ax_lib, main,
[BOOST_ASIO_LIB="-l$ax_lib" AC_SUBST(BOOST_ASIO_LIB) link_asio="yes" break],
[link_asio="no"])
done
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_asio" = "xno"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])

275
m4/ax_boost_base.m4 Normal file
View File

@@ -0,0 +1,275 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_boost_base.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# DESCRIPTION
#
# Test for the Boost C++ libraries of a particular version (or newer)
#
# If no path to the installed boost library is given the macro searchs
# under /usr, /usr/local, /opt and /opt/local and evaluates the
# $BOOST_ROOT environment variable. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
#
# And sets:
#
# HAVE_BOOST
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
# Copyright (c) 2009 Peter Adolphs
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 25
AC_DEFUN([AX_BOOST_BASE],
[
AC_ARG_WITH([boost],
[AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
[use Boost library from a standard location (ARG=yes),
from the specified location (ARG=<path>),
or disable it (ARG=no)
@<:@ARG=yes@:>@ ])],
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ac_boost_path=""
else
want_boost="yes"
ac_boost_path="$withval"
fi
],
[want_boost="yes"])
AC_ARG_WITH([boost-libdir],
AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
[Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]),
[
if test -d "$withval"
then
ac_boost_lib_path="$withval"
else
AC_MSG_ERROR(--with-boost-libdir expected directory name)
fi
],
[ac_boost_lib_path=""]
)
if test "x$want_boost" = "xyes"; then
boost_lib_version_req=ifelse([$1], ,1.20.0,$1)
boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'`
boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'`
boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
if test "x$boost_lib_version_req_sub_minor" = "x" ; then
boost_lib_version_req_sub_minor="0"
fi
WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor`
AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req)
succeeded=no
dnl On 64-bit systems check for system libraries in both lib64 and lib.
dnl The former is specified by FHS, but e.g. Debian does not adhere to
dnl this (as it rises problems for generic multi-arch support).
dnl The last entry in the list is chosen by default when no libraries
dnl are found, e.g. when only header-only libraries are installed!
libsubdirs="lib"
ax_arch=`uname -m`
case $ax_arch in
x86_64)
libsubdirs="lib64 libx32 lib lib64"
;;
ppc64|s390x|sparc64|aarch64|ppc64le)
libsubdirs="lib64 lib lib64 ppc64le"
;;
esac
dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
dnl them priority over the other paths since, if libs are found there, they
dnl are almost assuredly the ones desired.
AC_REQUIRE([AC_CANONICAL_HOST])
libsubdirs="lib/${host_cpu}-${host_os} $libsubdirs"
case ${host_cpu} in
i?86)
libsubdirs="lib/i386-${host_os} $libsubdirs"
;;
esac
dnl first we check the system location for boost libraries
dnl this location ist chosen if boost libraries are installed with the --layout=system option
dnl or if you install boost with RPM
if test "$ac_boost_path" != ""; then
BOOST_CPPFLAGS="-I$ac_boost_path/include"
for ac_boost_path_tmp in $libsubdirs; do
if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then
BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp"
break
fi
done
elif test "$cross_compiling" != yes; then
for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then
for libsubdir in $libsubdirs ; do
if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir"
BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
break;
fi
done
fi
dnl overwrite ld flags if we have required special directory with
dnl --with-boost-libdir parameter
if test "$ac_boost_lib_path" != ""; then
BOOST_LDFLAGS="-L$ac_boost_lib_path"
fi
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_REQUIRE([AC_PROG_CXX])
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@%:@include <boost/version.hpp>
]], [[
#if BOOST_VERSION >= $WANT_BOOST_VERSION
// Everything is okay
#else
# error Boost version is too old
#endif
]])],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
dnl if we found no boost with system layout we search for boost libraries
dnl built and installed without the --layout=system option or for a staged(not installed) version
if test "x$succeeded" != "xyes"; then
_version=0
if test "$ac_boost_path" != ""; then
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "$V_CHECK" = "1" ; then
_version=$_version_tmp
fi
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
done
fi
else
if test "$cross_compiling" != yes; then
for ac_boost_path in /usr /usr/local /opt /opt/local ; do
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "$V_CHECK" = "1" ; then
_version=$_version_tmp
best_path=$ac_boost_path
fi
done
fi
done
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
if test "$ac_boost_lib_path" = ""; then
for libsubdir in $libsubdirs ; do
if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
BOOST_LDFLAGS="-L$best_path/$libsubdir"
fi
fi
if test "x$BOOST_ROOT" != "x"; then
for libsubdir in $libsubdirs ; do
if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then
version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
V_CHECK=`expr $stage_version_shorten \>\= $_version`
if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
BOOST_CPPFLAGS="-I$BOOST_ROOT"
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
fi
fi
fi
fi
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@%:@include <boost/version.hpp>
]], [[
#if BOOST_VERSION >= $WANT_BOOST_VERSION
// Everything is okay
#else
# error Boost version is too old
#endif
]])],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
fi
if test "$succeeded" != "yes" ; then
if test "$_version" = "0" ; then
AC_MSG_NOTICE([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
else
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
fi
# execute ACTION-IF-NOT-FOUND (if present):
ifelse([$3], , :, [$3])
else
AC_SUBST(BOOST_CPPFLAGS)
AC_SUBST(BOOST_LDFLAGS)
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
# execute ACTION-IF-FOUND (if present):
ifelse([$2], , :, [$2])
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])

120
m4/ax_boost_system.m4 Normal file
View File

@@ -0,0 +1,120 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_boost_system.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_SYSTEM
#
# DESCRIPTION
#
# Test for System library from the Boost C++ libraries. The macro requires
# a preceding call to AX_BOOST_BASE. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_SYSTEM_LIB)
#
# And sets:
#
# HAVE_BOOST_SYSTEM
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
# Copyright (c) 2008 Michael Tindal
# Copyright (c) 2008 Daniel Casimiro <dan.casimiro@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 17
AC_DEFUN([AX_BOOST_SYSTEM],
[
AC_ARG_WITH([boost-system],
AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@],
[use the System library from boost - it is possible to specify a certain library for the linker
e.g. --with-boost-system=boost_system-gcc-mt ]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_system_lib=""
else
want_boost="yes"
ax_boost_user_system_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_BUILD])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK(whether the Boost::System library is available,
ax_cv_boost_system,
[AC_LANG_PUSH([C++])
CXXFLAGS_SAVE=$CXXFLAGS
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/system/error_code.hpp>]],
[[boost::system::system_category]])],
ax_cv_boost_system=yes, ax_cv_boost_system=no)
CXXFLAGS=$CXXFLAGS_SAVE
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_system" = "xyes"; then
AC_SUBST(BOOST_CPPFLAGS)
AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
LDFLAGS_SAVE=$LDFLAGS
if test "x$ax_boost_user_system_lib" = "x"; then
for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
if test "x$link_system" != "xyes"; then
for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
fi
else
for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_system" = "xno"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])

149
m4/ax_boost_thread.m4 Normal file
View File

@@ -0,0 +1,149 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_boost_thread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_THREAD
#
# DESCRIPTION
#
# Test for Thread library from the Boost C++ libraries. The macro requires
# a preceding call to AX_BOOST_BASE. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_THREAD_LIB)
#
# And sets:
#
# HAVE_BOOST_THREAD
#
# LICENSE
#
# Copyright (c) 2009 Thomas Porschberg <thomas@randspringer.de>
# Copyright (c) 2009 Michael Tindal
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 27
AC_DEFUN([AX_BOOST_THREAD],
[
AC_ARG_WITH([boost-thread],
AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@],
[use the Thread library from boost - it is possible to specify a certain library for the linker
e.g. --with-boost-thread=boost_thread-gcc-mt ]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_thread_lib=""
else
want_boost="yes"
ax_boost_user_thread_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_BUILD])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK(whether the Boost::Thread library is available,
ax_cv_boost_thread,
[AC_LANG_PUSH([C++])
CXXFLAGS_SAVE=$CXXFLAGS
if test "x$host_os" = "xsolaris" ; then
CXXFLAGS="-pthreads $CXXFLAGS"
elif test "x$host_os" = "xmingw32" ; then
CXXFLAGS="-mthreads $CXXFLAGS"
else
CXXFLAGS="-pthread $CXXFLAGS"
fi
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/thread/thread.hpp>]],
[[boost::thread_group thrds;
return 0;]])],
ax_cv_boost_thread=yes, ax_cv_boost_thread=no)
CXXFLAGS=$CXXFLAGS_SAVE
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_thread" = "xyes"; then
if test "x$host_os" = "xsolaris" ; then
BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS"
elif test "x$host_os" = "xmingw32" ; then
BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS"
else
BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS"
fi
AC_SUBST(BOOST_CPPFLAGS)
AC_DEFINE(HAVE_BOOST_THREAD,,[define if the Boost::Thread library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
LDFLAGS_SAVE=$LDFLAGS
case "x$host_os" in
*bsd* )
LDFLAGS="-pthread $LDFLAGS"
break;
;;
esac
if test "x$ax_boost_user_thread_lib" = "x"; then
for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
[link_thread="no"])
done
if test "x$link_thread" != "xyes"; then
for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
[link_thread="no"])
done
fi
else
for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do
AC_CHECK_LIB($ax_lib, exit,
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
[link_thread="no"])
done
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_thread" = "xno"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
else
case "x$host_os" in
*bsd* )
BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS"
break;
;;
esac
fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])

104
m4/ax_have_epoll.m4 Normal file
View File

@@ -0,0 +1,104 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_have_epoll.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_HAVE_EPOLL([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# AX_HAVE_EPOLL_PWAIT([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# DESCRIPTION
#
# This macro determines whether the system supports the epoll I/O event
# interface. A neat usage example would be:
#
# AX_HAVE_EPOLL(
# [AX_CONFIG_FEATURE_ENABLE(epoll)],
# [AX_CONFIG_FEATURE_DISABLE(epoll)])
# AX_CONFIG_FEATURE(
# [epoll], [This platform supports epoll(7)],
# [HAVE_EPOLL], [This platform supports epoll(7).])
#
# The epoll interface was added to the Linux kernel in version 2.5.45, and
# the macro verifies that a kernel newer than this is installed. This
# check is somewhat unreliable if <linux/version.h> doesn't match the
# running kernel, but it is necessary regardless, because glibc comes with
# stubs for the epoll_create(), epoll_wait(), etc. that allow programs to
# compile and link even if the kernel is too old; the problem would then
# be detected only at runtime.
#
# Linux kernel version 2.6.19 adds the epoll_pwait() call in addition to
# epoll_wait(). The availability of that function can be tested with the
# second macro. Generally speaking, it is safe to assume that
# AX_HAVE_EPOLL would succeed if AX_HAVE_EPOLL_PWAIT has, but not the
# other way round.
#
# LICENSE
#
# Copyright (c) 2008 Peter Simons <simons@cryp.to>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
AC_DEFUN([AX_HAVE_EPOLL], [dnl
ax_have_epoll_cppflags="${CPPFLAGS}"
AC_CHECK_HEADER([linux/version.h], [CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"])
AC_MSG_CHECKING([for Linux epoll(7) interface])
AC_CACHE_VAL([ax_cv_have_epoll], [dnl
AC_LINK_IFELSE([dnl
AC_LANG_PROGRAM([dnl
#include <sys/epoll.h>
#ifdef HAVE_LINUX_VERSION_H
# include <linux/version.h>
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
# error linux kernel version is too old to have epoll
# endif
#endif
], [dnl
int fd, rc;
struct epoll_event ev;
fd = epoll_create(128);
rc = epoll_wait(fd, &ev, 1, 0);])],
[ax_cv_have_epoll=yes],
[ax_cv_have_epoll=no])])
CPPFLAGS="${ax_have_epoll_cppflags}"
AS_IF([test "${ax_cv_have_epoll}" = "yes"],
[AC_MSG_RESULT([yes])
$1],[AC_MSG_RESULT([no])
$2])
])dnl
AC_DEFUN([AX_HAVE_EPOLL_PWAIT], [dnl
ax_have_epoll_cppflags="${CPPFLAGS}"
AC_CHECK_HEADER([linux/version.h],
[CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"])
AC_MSG_CHECKING([for Linux epoll(7) interface with signals extension])
AC_CACHE_VAL([ax_cv_have_epoll_pwait], [dnl
AC_LINK_IFELSE([dnl
AC_LANG_PROGRAM([dnl
#ifdef HAVE_LINUX_VERSION_H
# include <linux/version.h>
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
# error linux kernel version is too old to have epoll_pwait
# endif
#endif
#include <sys/epoll.h>
#include <signal.h>
], [dnl
int fd, rc;
struct epoll_event ev;
fd = epoll_create(128);
rc = epoll_wait(fd, &ev, 1, 0);
rc = epoll_pwait(fd, &ev, 1, 0, (sigset_t const *)(0));])],
[ax_cv_have_epoll_pwait=yes],
[ax_cv_have_epoll_pwait=no])])
CPPFLAGS="${ax_have_epoll_cppflags}"
AS_IF([test "${ax_cv_have_epoll_pwait}" = "yes"],
[AC_MSG_RESULT([yes])
$1],[AC_MSG_RESULT([no])
$2])
])dnl

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This script reads man page from stdin and converts it to rst
# document and outputs to stdout.
from __future__ import unicode_literals
import sys
import re
@@ -8,6 +12,9 @@ def man2rst(f):
expect_arg = False
in_arg = False
sys.stdout.write('.. DO NOT MODIFY THIS FILE! '
'It was generated by man2rst.py\n\n')
for line in f:
line = line.rstrip()
@@ -106,6 +113,7 @@ def process_text(text):
text = re.sub(r'\\fB(.*?)\\fR', '\\1', text)
text = re.sub(r'\\-', '-', text)
text = re.sub(r'\*', '\\*', text)
text = re.sub(r'\\&', '', text)
return text

View File

@@ -1,4 +1,14 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This script read cipher suite list csv file [1] and prints out ECDHE
# or DHE with AEAD ciphers only. The output is used by
# src/shrpx_ssl.cc.
#
# [1] http://www.iana.org/assignments/tls-parameters/tls-parameters-4.csv
# [2] http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
from __future__ import unicode_literals
import re
import sys
import csv

View File

@@ -1,4 +1,13 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This script reads Huffman Code table [1] and generates symbol table
# and decoding tables in C language. The resulting code is used in
# lib/nghttp2_hd_huffman.h and lib/nghttp2_hd_huffman_data.c
#
# [1] http://http2.github.io/http2-spec/compression.html
from __future__ import unicode_literals
import re
import sys

View File

@@ -1,4 +1,13 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This scripts reads static table entries [1] and generates
# nghttp2_hd_static_entry table. This table is used in
# lib/nghttp2_hd.c.
#
# [1] http://http2.github.io/http2-spec/compression.html
from __future__ import unicode_literals
import re, sys
def hash(s):
@@ -13,8 +22,27 @@ for line in sys.stdin:
val = m.group(3).strip() if m.group(3) else ''
entries.append((hash(m.group(2)), int(m.group(1)), m.group(2), val))
print 'static nghttp2_hd_entry static_table[] = {'
entries.sort()
print '/* Sorted by hash(name) and its table index */'
print 'static nghttp2_hd_static_entry static_table[] = {'
for ent in entries:
print 'MAKE_ENT("{}", "{}", {}u, {}u),'\
.format(ent[2], ent[3], ent[0], hash(ent[3]))
print 'MAKE_STATIC_ENT({}, "{}", "{}", {}u, {}u),'\
.format(ent[1] - 1, ent[2], ent[3], ent[0], hash(ent[3]))
print '};'
print ''
print '/* Index to the position in static_table */'
print 'const size_t static_table_index[] = {'
for i in range(len(entries)):
for j, ent in enumerate(entries):
if ent[1] - 1 == i:
sys.stdout.write('{: <2d},'.format(j))
break
if (i + 1) % 16 == 0:
sys.stdout.write('\n')
else:
sys.stdout.write(' ')
print '};'

109
python/calcratio.py Executable file
View File

@@ -0,0 +1,109 @@
#!/usr/bin/env python
#
# This script takes directories which contain the hpack-test-case json
# files, and calculates the compression ratio in each file and outputs
# the result in table formatted in rst.
#
# The each directory contains the result of various HPACK compressor.
#
# The table is laid out so that we can see that how input header set
# in one json file is compressed in each compressor.
#
# For hpack-test-case, see https://github.com/Jxck/hpack-test-case
#
import sys, json, os, re
class Stat:
def __init__(self, complen, srclen):
self.complen = complen
self.srclen = srclen
def compute_stat(jsdata):
complen = 0
srclen = 0
for item in jsdata['cases']:
complen += len(item['wire']) // 2
srclen += \
sum([len(list(x.keys())[0]) + len(list(x.values())[0]) \
for x in item['headers']])
return Stat(complen, srclen)
def format_result(r):
return '{:.02f} ({}/{}) '.format(r.complen/r.srclen, r.complen, r.srclen)
if __name__ == '__main__':
entries = [(os.path.basename(re.sub(r'/+$', '', p)), p) \
for p in sys.argv[1:]]
maxnamelen = 0
maxstorynamelen = 0
res = {}
stories = set()
for name, ent in entries:
files = [p for p in os.listdir(ent) if p.endswith('.json')]
res[name] = {}
maxnamelen = max(maxnamelen, len(name))
for fn in files:
stories.add(fn)
maxstorynamelen = max(maxstorynamelen, len(fn))
with open(os.path.join(ent, fn)) as f:
input = f.read()
rv = compute_stat(json.loads(input))
res[name][fn] = rv
maxnamelen = max(maxnamelen, len(format_result(rv)))
stories = list(stories)
stories.sort()
storynameformat = '{{:{}}} '.format(maxstorynamelen)
nameformat = '{{:{}}} '.format(maxnamelen)
sys.stdout.write('''\
hpack-test-case compression ratio
=================================
The each cell has ``X (Y/Z)`` format:
X
Y / Z
Y
number of bytes after compression
Z
number of bytes before compression
''')
def write_border():
sys.stdout.write('='*maxstorynamelen)
sys.stdout.write(' ')
for _ in entries:
sys.stdout.write('='*maxnamelen)
sys.stdout.write(' ')
sys.stdout.write('\n')
write_border()
sys.stdout.write(storynameformat.format('story'))
for name, _ in entries:
sys.stdout.write(nameformat.format(name))
sys.stdout.write('\n')
write_border()
for story in stories:
sys.stdout.write(storynameformat.format(story))
srclen = -1
for name, _ in entries:
stats = res[name]
if story not in stats:
sys.stdout.write(nameformat.format('N/A'))
continue
if srclen == -1:
srclen = stats[story].srclen
elif srclen != stats[story].srclen:
raise Exception('Bad srclen')
sys.stdout.write(nameformat.format(format_result(stats[story])))
sys.stdout.write('\n')
write_border()

View File

@@ -102,7 +102,7 @@ cdef extern from 'nghttp2/nghttp2.h':
ctypedef struct nghttp2_rst_stream:
nghttp2_frame_hd hd
nghttp2_error_code error_code
uint32_t error_code
ctypedef struct nghttp2_push_promise:
@@ -114,7 +114,7 @@ cdef extern from 'nghttp2/nghttp2.h':
ctypedef struct nghttp2_goaway:
nghttp2_frame_hd hd
int32_t last_stream_id
nghttp2_error_code error_code
uint32_t error_code
uint8_t *opaque_data
size_t opaque_data_len
@@ -142,7 +142,7 @@ cdef extern from 'nghttp2/nghttp2.h':
ctypedef int (*nghttp2_on_stream_close_callback)\
(nghttp2_session *session, int32_t stream_id,
nghttp2_error_code error_code, void *user_data)
uint32_t error_code, void *user_data)
ctypedef int (*nghttp2_on_begin_headers_callback)\
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
@@ -163,15 +163,47 @@ cdef extern from 'nghttp2/nghttp2.h':
int lib_error_code, void *user_data)
ctypedef struct nghttp2_session_callbacks:
nghttp2_send_callback send_callback
nghttp2_on_frame_recv_callback on_frame_recv_callback
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback
nghttp2_before_frame_send_callback before_frame_send_callback
nghttp2_on_frame_send_callback on_frame_send_callback
nghttp2_on_frame_not_send_callback on_frame_not_send_callback
nghttp2_on_stream_close_callback on_stream_close_callback
nghttp2_on_begin_headers_callback on_begin_headers_callback
nghttp2_on_header_callback on_header_callback
pass
int nghttp2_session_callbacks_new(
nghttp2_session_callbacks **callbacks_ptr)
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks)
void nghttp2_session_callbacks_set_send_callback(
nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback)
void nghttp2_session_callbacks_set_on_frame_recv_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_frame_recv_callback on_frame_recv_callback)
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback)
void nghttp2_session_callbacks_set_before_frame_send_callback(
nghttp2_session_callbacks *cbs,
nghttp2_before_frame_send_callback before_frame_send_callback)
void nghttp2_session_callbacks_set_on_frame_send_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_frame_send_callback on_frame_send_callback)
void nghttp2_session_callbacks_set_on_frame_not_send_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_frame_not_send_callback on_frame_not_send_callback)
void nghttp2_session_callbacks_set_on_stream_close_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_stream_close_callback on_stream_close_callback)
void nghttp2_session_callbacks_set_on_begin_headers_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_begin_headers_callback on_begin_headers_callback)
void nghttp2_session_callbacks_set_on_header_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_header_callback on_header_callback)
int nghttp2_session_client_new(nghttp2_session **session_ptr,
const nghttp2_session_callbacks *callbacks,
@@ -233,7 +265,7 @@ cdef extern from 'nghttp2/nghttp2.h':
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
nghttp2_error_code error_code)
uint32_t error_code)
void* nghttp2_session_get_stream_user_data(nghttp2_session *session,
uint32_t stream_id)
@@ -243,7 +275,7 @@ cdef extern from 'nghttp2/nghttp2.h':
void *stream_user_data)
int nghttp2_session_terminate_session(nghttp2_session *session,
nghttp2_error_code error_code)
uint32_t error_code)
const char* nghttp2_strerror(int lib_error_code)
@@ -252,9 +284,6 @@ cdef extern from 'nghttp2/nghttp2.h':
void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater)
void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater,
uint8_t no_refset)
int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
size_t hd_table_bufsize_max)
@@ -291,9 +320,6 @@ cdef extern from 'nghttp2_hd.h':
# This is macro
int NGHTTP2_HD_ENTRY_OVERHEAD
ctypedef enum nghttp2_hd_flags:
NGHTTP2_HD_FLAG_REFSET
ctypedef enum nghttp2_hd_inflate_flag:
NGHTTP2_HD_INFLATE_EMIT
NGHTTP2_HD_INFLATE_FINAL

View File

@@ -27,8 +27,6 @@ def testsuite(testdata):
expected_hdrs = [(list(x.keys())[0],
list(x.values())[0]) for x in item['headers']]
hdrs.sort()
expected_hdrs.sort()
if hdrs != expected_hdrs:
if 'seqno' in item:
seqno = item['seqno']
@@ -53,7 +51,7 @@ if __name__ == '__main__':
testdata = json.loads(input)
if 'draft' not in testdata or testdata['draft'] != 8:
if 'draft' not in testdata or testdata['draft'] != 9:
sys.stderr.write('Not supported\n')
continue

View File

@@ -16,7 +16,7 @@ import nghttp2
def testsuite(testdata, filename, outdir, table_size, deflate_table_size,
simulate_table_size_change):
res = {
'draft':8,
'draft':9,
'description': '''\
Encoded by nghttp2. The basic encoding strategy is described in \
http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html \

View File

@@ -33,12 +33,11 @@ HD_ENTRY_OVERHEAD = cnghttp2.NGHTTP2_HD_ENTRY_OVERHEAD
class HDTableEntry:
def __init__(self, name, namelen, value, valuelen, ref):
def __init__(self, name, namelen, value, valuelen):
self.name = name
self.namelen = namelen
self.value = value
self.valuelen = valuelen
self.ref = ref
def space(self):
return self.namelen + self.valuelen + HD_ENTRY_OVERHEAD
@@ -52,8 +51,7 @@ cdef _get_hd_table(cnghttp2.nghttp2_hd_context *ctx):
k = _get_pybytes(entry.nv.name, entry.nv.namelen)
v = _get_pybytes(entry.nv.value, entry.nv.valuelen)
res.append(HDTableEntry(k, entry.nv.namelen,
v, entry.nv.valuelen,
(entry.flags & cnghttp2.NGHTTP2_HD_FLAG_REFSET) != 0))
v, entry.nv.valuelen))
return res
cdef _get_pybytes(uint8_t *b, uint16_t blen):
@@ -143,15 +141,6 @@ cdef class HDDeflater:
return res
def set_no_refset(self, no_refset):
'''Tells the compressor not to use reference set if |no_refset| is
nonzero. If |no_refset| is nonzero, on each invocation of
deflate(), compressor first emits index=0 to clear up
reference set.
'''
cnghttp2.nghttp2_hd_deflate_set_no_refset(self._deflater, no_refset)
def change_table_size(self, hd_table_bufsize_max):
'''Changes header table size to |hd_table_bufsize_max| byte.
@@ -243,16 +232,14 @@ def print_hd_table(hdtable):
function does not work if header name/value cannot be decoded using
UTF-8 encoding.
s=N means the entry occupies N bytes in header table. if r=y, then
the entry is in the reference set.
s=N means the entry occupies N bytes in header table.
'''
idx = 0
for entry in hdtable:
idx += 1
print('[{}] (s={}) (r={}) {}: {}'\
print('[{}] (s={}) {}: {}'\
.format(idx, entry.space(),
'y' if entry.ref else 'n',
entry.name.decode('utf-8'),
entry.value.decode('utf-8')))
@@ -443,7 +430,7 @@ cdef int server_on_frame_not_send(cnghttp2.nghttp2_session *session,
cdef int server_on_stream_close(cnghttp2.nghttp2_session *session,
int32_t stream_id,
cnghttp2.nghttp2_error_code error_code,
uint32_t error_code,
void *user_data):
cdef http2 = <_HTTP2SessionCore>user_data
@@ -492,7 +479,7 @@ cdef class _HTTP2SessionCore:
cdef settings_timer
def __cinit__(self, transport, handler_class):
cdef cnghttp2.nghttp2_session_callbacks callbacks
cdef cnghttp2.nghttp2_session_callbacks *callbacks
cdef cnghttp2.nghttp2_settings_entry iv[2]
cdef int rv
@@ -503,17 +490,32 @@ cdef class _HTTP2SessionCore:
self.handlers = set()
self.settings_timer = None
memset(&callbacks, 0, sizeof(callbacks))
callbacks.on_header_callback = server_on_header
callbacks.on_begin_headers_callback = server_on_begin_headers
callbacks.on_frame_recv_callback = server_on_frame_recv
callbacks.on_stream_close_callback = server_on_stream_close
callbacks.on_frame_send_callback = server_on_frame_send
callbacks.on_frame_not_send_callback = server_on_frame_not_send
callbacks.on_data_chunk_recv_callback = server_on_data_chunk_recv
rv = cnghttp2.nghttp2_session_callbacks_new(&callbacks)
rv = cnghttp2.nghttp2_session_server_new(&self.session, &callbacks,
if rv != 0:
raise Exception('nghttp2_session_callbacks_new failed: {}'.format\
(_strerror(rv)))
cnghttp2.nghttp2_session_callbacks_set_on_header_callback(
callbacks, server_on_header)
cnghttp2.nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, server_on_begin_headers)
cnghttp2.nghttp2_session_callbacks_set_on_frame_recv_callback(
callbacks, server_on_frame_recv)
cnghttp2.nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, server_on_stream_close)
cnghttp2.nghttp2_session_callbacks_set_on_frame_send_callback(
callbacks, server_on_frame_send)
cnghttp2.nghttp2_session_callbacks_set_on_frame_not_send_callback(
callbacks, server_on_frame_not_send)
cnghttp2.nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
callbacks, server_on_data_chunk_recv)
rv = cnghttp2.nghttp2_session_server_new(&self.session, callbacks,
<void*>self)
cnghttp2.nghttp2_session_callbacks_del(callbacks)
if rv != 0:
raise Exception('nghttp2_session_server_new failed: {}'.format\
(_strerror(rv)))

View File

@@ -34,6 +34,7 @@ setup(
name = 'python-nghttp2',
description = 'Python HTTP/2 library on top of nghttp2',
author = 'Tatsuhiro Tsujikawa',
version = '@PACKAGE_VERSION@',
author_email = 'tatsuhiro.t@gmail.com',
url = 'http://tatsuhiro-t.github.io/nghttp2/',
keywords = [],

View File

@@ -43,7 +43,7 @@
#include <event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/bufferevent_ssl.h>
#ifdef __cplusplus
extern "C" {
@@ -58,6 +58,7 @@ extern "C" {
#include "app_helper.h"
#include "http2.h"
#include "util.h"
#include "libevent_util.h"
#include "ssl.h"
#ifndef O_BINARY
@@ -68,6 +69,7 @@ namespace nghttp2 {
namespace {
const std::string STATUS_200 = "200";
const std::string STATUS_301 = "301";
const std::string STATUS_304 = "304";
const std::string STATUS_400 = "400";
const std::string STATUS_404 = "404";
@@ -94,9 +96,9 @@ namespace {
void append_nv(Stream *stream, const std::vector<nghttp2_nv>& nva)
{
for(auto& nv : nva) {
http2::split_add_header(stream->headers,
nv.name, nv.namelen, nv.value, nv.valuelen,
nv.flags & NGHTTP2_NV_FLAG_NO_INDEX);
http2::add_header(stream->headers,
nv.name, nv.namelen, nv.value, nv.valuelen,
nv.flags & NGHTTP2_NV_FLAG_NO_INDEX);
}
}
} // namespace
@@ -104,6 +106,7 @@ void append_nv(Stream *stream, const std::vector<nghttp2_nv>& nva)
Config::Config()
: stream_read_timeout{60, 0},
stream_write_timeout{60, 0},
session_option(nullptr),
data_ptr(nullptr),
padding(0),
num_worker(1),
@@ -115,7 +118,15 @@ Config::Config()
no_tls(false),
error_gzip(false),
early_response(false)
{}
{
nghttp2_option_new(&session_option);
nghttp2_option_set_recv_client_preface(session_option, 1);
}
Config::~Config()
{
nghttp2_option_del(session_option);
}
Stream::Stream(Http2Handler *handler, int32_t stream_id)
: handler(handler),
@@ -213,19 +224,29 @@ void remove_stream_write_timeout(Stream *stream)
}
} // namespace
namespace {
void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config);
} // namespace
class Sessions {
public:
Sessions(event_base *evbase, const Config *config, SSL_CTX *ssl_ctx)
: evbase_(evbase),
config_(config),
ssl_ctx_(ssl_ctx),
callbacks_(nullptr),
next_session_id_(1)
{}
{
nghttp2_session_callbacks_new(&callbacks_);
fill_callback(callbacks_, config_);
}
~Sessions()
{
for(auto handler : handlers_) {
delete handler;
}
nghttp2_session_callbacks_del(callbacks_);
}
void add_handler(Http2Handler *handler)
{
@@ -269,6 +290,10 @@ public:
}
return session_id;
}
const nghttp2_session_callbacks* get_callbacks() const
{
return callbacks_;
}
void accept_connection(int fd)
{
int val = 1;
@@ -297,6 +322,7 @@ private:
event_base *evbase_;
const Config *config_;
SSL_CTX *ssl_ctx_;
nghttp2_session_callbacks *callbacks_;
int64_t next_session_id_;
};
@@ -311,36 +337,20 @@ void on_session_closed(Http2Handler *hd, int64_t session_id)
}
} // namespace
namespace {
void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config);
} // namespace
Http2Handler::Http2Handler(Sessions *sessions,
int fd, SSL *ssl, int64_t session_id)
: session_id_(session_id),
session_(nullptr),
sessions_(sessions),
ssl_(ssl),
rev_(nullptr),
wev_(nullptr),
bev_(nullptr),
settings_timerev_(nullptr),
pending_data_(nullptr),
pending_datalen_(0),
left_connhd_len_(NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN),
fd_(fd)
{
nghttp2_buf_wrap_init(&sendbuf_, sendbufarray_, sizeof(sendbufarray_));
}
{}
Http2Handler::~Http2Handler()
{
on_session_closed(this, session_id_);
if(rev_) {
event_free(rev_);
}
if(wev_) {
event_free(wev_);
}
if(settings_timerev_) {
event_free(settings_timerev_);
}
@@ -349,6 +359,10 @@ Http2Handler::~Http2Handler()
SSL_set_shutdown(ssl_, SSL_RECEIVED_SHUTDOWN);
SSL_shutdown(ssl_);
}
if(bev_) {
bufferevent_disable(bev_, EV_READ | EV_WRITE);
bufferevent_free(bev_);
}
if(ssl_) {
SSL_free(ssl_);
}
@@ -362,329 +376,93 @@ void Http2Handler::remove_self()
}
namespace {
void rev_cb(evutil_socket_t fd, short what, void *arg)
void readcb(bufferevent *bev, void *arg)
{
int rv;
auto handler = static_cast<Http2Handler*>(arg);
if(what & EV_READ) {
rv = handler->on_read();
if(rv == -1) {
delete_handler(handler);
}
rv = handler->on_read();
if(rv == -1) {
delete_handler(handler);
}
}
} // namespace
namespace {
void wev_cb(evutil_socket_t fd, short what, void *arg)
void writecb(bufferevent *bev, void *arg)
{
int rv;
auto handler = static_cast<Http2Handler*>(arg);
if(what & EV_WRITE) {
rv = handler->on_write();
if(rv == -1) {
delete_handler(handler);
}
rv = handler->on_write();
if(rv == -1) {
delete_handler(handler);
}
}
} // namespace
int Http2Handler::handle_ssl_temporal_error(int err)
{
auto sslerr = SSL_get_error(ssl_, err);
switch(sslerr) {
case SSL_ERROR_WANT_READ:
event_add(rev_, nullptr);
return 1;
case SSL_ERROR_WANT_WRITE:
event_add(wev_, nullptr);
return 1;
}
return -1;
}
int Http2Handler::tls_write(const uint8_t *data, size_t datalen)
{
int rv;
size_t max_avail;
// OpenSSL sends at most 16K bytes
max_avail = ssl_ ?
std::min((ssize_t)16384, nghttp2_buf_avail(&sendbuf_)) :
nghttp2_buf_avail(&sendbuf_);
if(max_avail < datalen) {
if(nghttp2_buf_len(&sendbuf_) > 0) {
rv = tls_write_pending();
if(rv == -1) {
return -1;
}
if(rv == 1) {
pending_data_ = data;
pending_datalen_ = datalen;
return 1;
}
}
assert(nghttp2_buf_avail(&sendbuf_) >= (ssize_t)datalen);
}
//std::cerr << "DBG: copy " << datalen << " bytes" << std::endl;
sendbuf_.last = nghttp2_cpymem(sendbuf_.last, data, datalen);
return 0;
}
int Http2Handler::tls_write_pending()
{
int rv;
if(nghttp2_buf_len(&sendbuf_) == 0) {
return 0;
}
for(;;) {
if(ssl_) {
ERR_clear_error();
rv = SSL_write(ssl_, sendbuf_.pos, nghttp2_buf_len(&sendbuf_));
if(rv == 0) {
return -1;
}
if(rv < 0) {
return handle_ssl_temporal_error(rv);
}
} else {
while((rv = write(fd_, sendbuf_.pos, nghttp2_buf_len(&sendbuf_))) &&
rv == -1 && errno == EINTR);
if(rv == 0) {
continue;
}
if(rv < 0) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
event_add(wev_, nullptr);
return 1;
}
return -1;
}
}
sendbuf_.pos += rv;
if(nghttp2_buf_len(&sendbuf_) == 0) {
nghttp2_buf_reset(&sendbuf_);
if(pending_data_) {
assert(nghttp2_buf_avail(&sendbuf_) >= (ssize_t)pending_datalen_);
sendbuf_.last = nghttp2_cpymem(sendbuf_.last,
pending_data_, pending_datalen_);
pending_data_ = nullptr;
pending_datalen_ = 0;
continue;
}
return 0;
}
}
}
namespace {
void tls_handshake_cb(evutil_socket_t fd, short what, void *arg)
void eventcb(bufferevent *bev, short events, void *arg)
{
int rv;
auto handler = static_cast<Http2Handler*>(arg);
if(what & (EV_READ | EV_WRITE)) {
rv = handler->tls_handshake();
if(rv == -1) {
delete_handler(handler);
return;
if(events & (BEV_EVENT_EOF | BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT)) {
delete_handler(handler);
return;
}
if(events & BEV_EVENT_CONNECTED) {
if(handler->get_sessions()->get_config()->verbose) {
std::cerr << "SSL/TLS handshake completed" << std::endl;
}
if(rv == 1) {
if(handler->verify_npn_result() != 0) {
delete_handler(handler);
return;
}
rv = handler->on_connect();
if(rv != 0) {
if(handler->on_connect() != 0) {
delete_handler(handler);
return;
}
}
}
} // namespace
int Http2Handler::tls_handshake()
{
int rv;
ERR_clear_error();
rv = SSL_accept(ssl_);
if(rv == 0) {
return -1;
}
if(rv < 0) {
auto sslerr = SSL_get_error(ssl_, rv);
switch(sslerr) {
case SSL_ERROR_NONE:
case SSL_ERROR_WANT_X509_LOOKUP:
case SSL_ERROR_ZERO_RETURN:
break;
case SSL_ERROR_WANT_READ:
event_add(rev_, nullptr);
return 1;
case SSL_ERROR_WANT_WRITE:
event_add(wev_, nullptr);
return 1;
}
}
if(sessions_->get_config()->verbose) {
std::cerr << "SSL/TLS handshake completed" << std::endl;
}
if(verify_npn_result() != 0) {
return -1;
}
event_del(rev_);
event_del(wev_);
event_assign(rev_, sessions_->get_evbase(), fd_, EV_READ, rev_cb, this);
event_assign(wev_, sessions_->get_evbase(), fd_, EV_WRITE, wev_cb, this);
return 0;
}
int Http2Handler::setup_bev()
{
auto evbase = sessions_->get_evbase();
if(ssl_) {
rev_ = event_new(sessions_->get_evbase(), fd_, EV_READ, tls_handshake_cb,
this);
wev_ = event_new(sessions_->get_evbase(), fd_, EV_WRITE, tls_handshake_cb,
this);
bev_ = bufferevent_openssl_socket_new(evbase, fd_, ssl_,
BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_DEFER_CALLBACKS);
} else {
rev_ = event_new(sessions_->get_evbase(), fd_, EV_READ, rev_cb, this);
wev_ = event_new(sessions_->get_evbase(), fd_, EV_WRITE, wev_cb, this);
bev_ = bufferevent_socket_new(evbase, fd_, BEV_OPT_DEFER_CALLBACKS);
}
event_add(rev_, nullptr);
// TODO set up timeout here
bufferevent_enable(bev_, EV_READ);
bufferevent_setcb(bev_, readcb, writecb, eventcb, this);
return 0;
}
int Http2Handler::wait_events()
{
int active = 0;
if(nghttp2_session_want_read(session_)) {
event_add(rev_, nullptr);
active = 1;
}
if(nghttp2_session_want_write(session_)) {
event_add(wev_, nullptr);
active = 1;
}
if(pending_datalen_ > 0) {
active = 1;
}
return active ? 0 : -1;
}
int Http2Handler::on_read()
int Http2Handler::send()
{
int rv;
uint8_t buf[16384];
uint8_t *bufp;
size_t nread;
if(ssl_) {
ERR_clear_error();
rv = SSL_read(ssl_, buf, sizeof(buf));
if(rv == 0) {
return -1;
}
if(rv < 0) {
return handle_ssl_temporal_error(rv);
}
} else {
while((rv = read(fd_, buf, sizeof(buf))) && rv == -1 && errno == EINTR);
if(rv == 0) {
return -1;
}
if(rv < 0) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
event_add(rev_, nullptr);
return 1;
}
return -1;
}
}
nread = rv;
bufp = buf;
if(left_connhd_len_ > 0) {
auto len = std::min(left_connhd_len_, nread);
const char *conhead = NGHTTP2_CLIENT_CONNECTION_PREFACE;
if(memcmp(conhead + NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN -
left_connhd_len_, bufp, len) != 0) {
return -1;
}
left_connhd_len_ -= len;
nread -= len;
if(nread == 0) {
wait_events();
return 0;
}
bufp += len;
}
rv = nghttp2_session_mem_recv(session_, bufp, nread);
if(rv < 0) {
std::cerr << "nghttp2_session_mem_recv() returned error: "
<< nghttp2_strerror(rv) << std::endl;
return -1;
}
return wait_events();
}
int Http2Handler::on_write()
{
int rv;
//std::cerr << "DBG: on_write" << std::endl;
rv = tls_write_pending();
if(rv != 0) {
return rv;
}
auto output = bufferevent_get_output(bev_);
util::EvbufferBuffer evbbuf(output, buf, sizeof(buf));
for(;;) {
const uint8_t *data;
// Check buffer length and break if it is large enough.
if(evbuffer_get_length(output) + evbbuf.get_buflen() >= 65536) {
break;
}
const uint8_t *data;
auto datalen = nghttp2_session_mem_send(session_, &data);
if(datalen < 0) {
@@ -692,24 +470,65 @@ int Http2Handler::on_write()
<< nghttp2_strerror(datalen) << std::endl;
return -1;
}
if(datalen == 0) {
break;
}
rv = tls_write(data, datalen);
rv = evbbuf.add(data, datalen);
if(rv != 0) {
return rv;
std::cerr << "evbuffer_add() failed" << std::endl;
return -1;
}
}
rv = tls_write_pending();
rv = evbbuf.flush();
if(rv != 0) {
return rv;
std::cerr << "evbuffer_add() failed" << std::endl;
return -1;
}
return wait_events();
if(nghttp2_session_want_read(session_) == 0 &&
nghttp2_session_want_write(session_) == 0 &&
evbuffer_get_length(output) == 0) {
return -1;
}
return 0;
}
int Http2Handler::on_read()
{
int rv;
auto input = bufferevent_get_input(bev_);
for(;;) {
auto len = evbuffer_get_contiguous_space(input);
if(len == 0) {
break;
}
auto data = evbuffer_pullup(input, len);
rv = nghttp2_session_mem_recv(session_, data, len);
if(rv < 0) {
std::cerr << "nghttp2_session_mem_recv() returned error: "
<< nghttp2_strerror(rv) << std::endl;
return -1;
}
if(evbuffer_drain(input, len) == -1) {
std::cerr << "evbuffer_drain() failed" << std::endl;
}
}
return send();
}
int Http2Handler::on_write()
{
return send();
}
namespace {
@@ -724,9 +543,9 @@ void settings_timeout_cb(evutil_socket_t fd, short what, void *arg)
int Http2Handler::on_connect()
{
int r;
nghttp2_session_callbacks callbacks;
fill_callback(callbacks, sessions_->get_config());
r = nghttp2_session_server_new(&session_, &callbacks, this);
r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
sessions_->get_config()->session_option);
if(r != 0) {
return r;
}
@@ -814,7 +633,7 @@ int Http2Handler::submit_file_response(const std::string& status,
int Http2Handler::submit_response
(const std::string& status,
int32_t stream_id,
const std::vector<std::pair<std::string, std::string>>& headers,
const Headers& headers,
nghttp2_data_provider *data_prd)
{
std::string date_str = util::http_date(time(0));
@@ -823,8 +642,8 @@ int Http2Handler::submit_response
http2::make_nv_ls("server", NGHTTPD_SERVER),
http2::make_nv_ls("date", date_str)
};
for(size_t i = 0; i < headers.size(); ++i) {
nva.push_back(http2::make_nv(headers[i].first, headers[i].second, false));
for(auto& nv : headers) {
nva.push_back(http2::make_nv(nv.name, nv.value, nv.no_index));
}
int r = nghttp2_submit_response(session_, stream_id, nva.data(), nva.size(),
data_prd);
@@ -843,10 +662,19 @@ int Http2Handler::submit_response(const std::string& status,
data_prd);
}
int Http2Handler::submit_non_final_response(const std::string& status,
int32_t stream_id)
{
auto nva = std::vector<nghttp2_nv>{
http2::make_nv_ls(":status", status)
};
return nghttp2_submit_headers(session_, NGHTTP2_FLAG_NONE, stream_id,
nullptr, nva.data(), nva.size(), nullptr);
}
int Http2Handler::submit_push_promise(Stream *stream,
const std::string& push_path)
{
std::string authority;
auto itr = std::lower_bound(std::begin(stream->headers),
std::end(stream->headers),
Header(":authority", ""));
@@ -877,14 +705,13 @@ int Http2Handler::submit_push_promise(Stream *stream,
auto promised_stream = util::make_unique<Stream>(this, promised_stream_id);
append_nv(promised_stream.get(), http2::sort_nva(nva.data(), nva.size()));
append_nv(promised_stream.get(), nva);
add_stream(promised_stream_id, std::move(promised_stream));
return 0;
}
int Http2Handler::submit_rst_stream(Stream *stream,
nghttp2_error_code error_code)
int Http2Handler::submit_rst_stream(Stream *stream, uint32_t error_code)
{
remove_stream_read_timeout(stream);
remove_stream_write_timeout(stream);
@@ -928,16 +755,6 @@ const Config* Http2Handler::get_config() const
return sessions_->get_config();
}
size_t Http2Handler::get_left_connhd_len() const
{
return left_connhd_len_;
}
void Http2Handler::set_left_connhd_len(size_t left)
{
left_connhd_len_ = left;
}
void Http2Handler::remove_settings_timer()
{
if(settings_timerev_) {
@@ -947,7 +764,7 @@ void Http2Handler::remove_settings_timer()
}
}
void Http2Handler::terminate_session(nghttp2_error_code error_code)
void Http2Handler::terminate_session(uint32_t error_code)
{
nghttp2_session_terminate_session(session_, error_code);
}
@@ -986,18 +803,6 @@ ssize_t file_read_callback
return nread;
}
namespace {
bool check_url(const std::string& url)
{
// We don't like '\' in url.
return !url.empty() && url[0] == '/' &&
url.find('\\') == std::string::npos &&
url.find("/../") == std::string::npos &&
url.find("/./") == std::string::npos &&
!util::endsWith(url, "/..") && !util::endsWith(url, "/.");
}
} // namespace
namespace {
void prepare_status_response(Stream *stream, Http2Handler *hd,
const std::string& status)
@@ -1020,7 +825,7 @@ void prepare_status_response(Stream *stream, Http2Handler *hd,
body += "</address>";
body += "</body></html>";
std::vector<std::pair<std::string, std::string>> headers;
Headers headers;
if(hd->get_config()->error_gzip) {
gzFile write_fd = gzdopen(pipefd[1], "w");
gzwrite(write_fd, body.c_str(), body.size());
@@ -1047,13 +852,35 @@ void prepare_status_response(Stream *stream, Http2Handler *hd,
}
} // namespace
namespace {
void prepare_redirect_response(Stream *stream, Http2Handler *hd,
const std::string& path,
const std::string& status)
{
auto scheme = http2::get_unique_header(stream->headers, ":scheme");
auto authority = http2::get_unique_header(stream->headers, ":authority");
if(!authority) {
authority = http2::get_unique_header(stream->headers, ":host");
}
auto redirect_url = scheme->value;
redirect_url += "://";
redirect_url += authority->value;
redirect_url += path;
auto headers = Headers{{"location", redirect_url}};
hd->submit_response(status, stream->stream_id, headers, nullptr);
}
} // namespace
namespace {
void prepare_response(Stream *stream, Http2Handler *hd, bool allow_push = true)
{
int rv;
auto url = (*std::lower_bound(std::begin(stream->headers),
std::end(stream->headers),
Header(":path", ""))).value;
auto reqpath = (*std::lower_bound(std::begin(stream->headers),
std::end(stream->headers),
Header(":path", ""))).value;
auto ims = std::lower_bound(std::begin(stream->headers),
std::end(stream->headers),
Header("if-modified-since", ""));
@@ -1065,17 +892,21 @@ void prepare_response(Stream *stream, Http2Handler *hd, bool allow_push = true)
last_mod_found = true;
last_mod = util::parse_http_date((*ims).value);
}
auto query_pos = url.find("?");
auto query_pos = reqpath.find("?");
std::string url;
if(query_pos != std::string::npos) {
// Do not response to this request to allow clients to test timeouts.
if(url.find("nghttpd_do_not_respond_to_req=yes",
query_pos) != std::string::npos) {
if(reqpath.find("nghttpd_do_not_respond_to_req=yes",
query_pos) != std::string::npos) {
return;
}
url = url.substr(0, query_pos);
url = reqpath.substr(0, query_pos);
} else {
url = reqpath;
}
url = util::percentDecode(url.begin(), url.end());
if(!check_url(url)) {
if(!util::check_path(url)) {
prepare_status_response(stream, hd, STATUS_404);
return;
}
@@ -1109,6 +940,20 @@ void prepare_response(Stream *stream, Http2Handler *hd, bool allow_push = true)
return;
}
if(buf.st_mode & S_IFDIR) {
close(file);
if(query_pos == std::string::npos) {
reqpath += "/";
} else {
reqpath.insert(query_pos, "/");
}
prepare_redirect_response(stream, hd, reqpath, STATUS_301);
return;
}
stream->file = file;
nghttp2_data_provider data_prd;
@@ -1158,8 +1003,20 @@ int on_header_callback(nghttp2_session *session,
if(!http2::check_nv(name, namelen, value, valuelen)) {
return 0;
}
http2::split_add_header(stream->headers, name, namelen, value, valuelen,
flags & NGHTTP2_NV_FLAG_NO_INDEX);
if(namelen > 0 && name[0] == ':') {
if((!stream->headers.empty() &&
stream->headers.back().name.c_str()[0] != ':') ||
!http2::check_http2_request_pseudo_header(name, namelen)) {
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
NGHTTP2_PROTOCOL_ERROR);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
}
http2::add_header(stream->headers, name, namelen, value, valuelen,
flags & NGHTTP2_NV_FLAG_NO_INDEX);
return 0;
}
} // namespace
@@ -1247,7 +1104,7 @@ int hd_on_frame_recv_callback
if(frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
http2::normalize_headers(stream->headers);
if(!http2::check_http2_headers(stream->headers)) {
if(!http2::check_http2_request_headers(stream->headers)) {
hd->submit_rst_stream(stream, NGHTTP2_PROTOCOL_ERROR);
return 0;
}
@@ -1266,6 +1123,12 @@ int hd_on_frame_recv_callback
return 0;
}
auto expect100 = http2::get_header(stream->headers, "expect");
if(expect100 && util::strieq("100-continue", expect100->value.c_str())) {
hd->submit_non_final_response("100", frame->hd.stream_id);
}
if(hd->get_config()->early_response) {
prepare_response(stream, hd);
}
@@ -1322,8 +1185,9 @@ int hd_on_frame_send_callback
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
remove_stream_write_timeout(stream);
} else if(nghttp2_session_get_stream_remote_window_size
(session, frame->hd.stream_id) == 0) {
} else if(std::min(nghttp2_session_get_stream_remote_window_size
(session, frame->hd.stream_id),
nghttp2_session_get_remote_window_size(session)) <= 0) {
// If stream is blocked by flow control, enable write timeout.
add_stream_read_timeout_if_pending(stream);
add_stream_write_timeout(stream);
@@ -1392,7 +1256,7 @@ int on_data_chunk_recv_callback
namespace {
int on_stream_close_callback
(nghttp2_session *session, int32_t stream_id, nghttp2_error_code error_code,
(nghttp2_session *session, int32_t stream_id, uint32_t error_code,
void *user_data)
{
auto hd = static_cast<Http2Handler*>(user_data);
@@ -1408,23 +1272,34 @@ int on_stream_close_callback
} // namespace
namespace {
void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config)
void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config)
{
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_frame_recv_callback = hd_on_frame_recv_callback;
callbacks.on_frame_send_callback = hd_on_frame_send_callback;
nghttp2_session_callbacks_set_on_stream_close_callback
(callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback
(callbacks, hd_on_frame_recv_callback);
nghttp2_session_callbacks_set_on_frame_send_callback
(callbacks, hd_on_frame_send_callback);
if(config->verbose) {
callbacks.on_invalid_frame_recv_callback =
verbose_on_invalid_frame_recv_callback;
callbacks.on_unknown_frame_recv_callback =
verbose_on_unknown_frame_recv_callback;
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
(callbacks, verbose_on_invalid_frame_recv_callback);
}
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
(callbacks, on_data_chunk_recv_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);
if(config->padding) {
callbacks.select_padding_callback = select_padding_callback;
nghttp2_session_callbacks_set_select_padding_callback
(callbacks, select_padding_callback);
}
}
} // namespace
@@ -1440,7 +1315,9 @@ void worker_readcb(bufferevent *bev, void *arg)
auto input = bufferevent_get_input(bev);
while(evbuffer_get_length(input) >= sizeof(ClientInfo)) {
ClientInfo client;
evbuffer_remove(input, &client, sizeof(client));
if(evbuffer_remove(input, &client, sizeof(client)) == -1) {
std::cerr << "evbuffer_remove() failed" << std::endl;
}
sessions->accept_connection(client.fd);
}
}
@@ -1676,14 +1553,14 @@ int HttpServer::run()
}
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION |
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
SSL_OP_SINGLE_ECDH_USE |
SSL_OP_NO_TICKET |
SSL_OP_CIPHER_SERVER_PREFERENCE);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST);

View File

@@ -40,6 +40,7 @@
#include <openssl/ssl.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <nghttp2/nghttp2.h>
@@ -66,6 +67,7 @@ struct Config {
std::string dh_param_file;
timeval stream_read_timeout;
timeval stream_write_timeout;
nghttp2_option *session_option;
void *data_ptr;
size_t padding;
size_t num_worker;
@@ -78,6 +80,7 @@ struct Config {
bool error_gzip;
bool early_response;
Config();
~Config();
};
class Http2Handler;
@@ -103,12 +106,11 @@ public:
void remove_self();
int setup_bev();
int send();
int on_read();
int on_write();
int on_connect();
int verify_npn_result();
int sendcb(const uint8_t *data, size_t len);
int recvcb(uint8_t *buf, size_t len);
int submit_file_response(const std::string& status,
Stream *stream,
@@ -123,12 +125,14 @@ public:
int submit_response
(const std::string& status,
int32_t stream_id,
const std::vector<std::pair<std::string, std::string>>& headers,
const Headers& headers,
nghttp2_data_provider *data_prd);
int submit_non_final_response(const std::string& status, int32_t stream_id);
int submit_push_promise(Stream *stream, const std::string& push_path);
int submit_rst_stream(Stream *stream, nghttp2_error_code error_code);
int submit_rst_stream(Stream *stream, uint32_t error_code);
void add_stream(int32_t stream_id, std::unique_ptr<Stream> stream);
void remove_stream(int32_t stream_id);
@@ -136,30 +140,17 @@ public:
int64_t session_id() const;
Sessions* get_sessions() const;
const Config* get_config() const;
size_t get_left_connhd_len() const;
void set_left_connhd_len(size_t left);
void remove_settings_timer();
void terminate_session(nghttp2_error_code error_code);
int tls_handshake();
void terminate_session(uint32_t error_code);
private:
int handle_ssl_temporal_error(int err);
int tls_write(const uint8_t *data, size_t datalen);
int tls_write_pending();
int wait_events();
std::map<int32_t, std::unique_ptr<Stream>> id2stream_;
nghttp2_buf sendbuf_;
int64_t session_id_;
nghttp2_session *session_;
Sessions *sessions_;
SSL* ssl_;
event *rev_, *wev_;
SSL *ssl_;
bufferevent *bev_;
event *settings_timerev_;
const uint8_t *pending_data_;
size_t pending_datalen_;
size_t left_connhd_len_;
int fd_;
uint8_t sendbufarray_[65536];
};
class HttpServer {

View File

@@ -20,6 +20,7 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = includes
bin_PROGRAMS =
check_PROGRAMS =
@@ -30,6 +31,7 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/lib/includes \
-I$(top_builddir)/lib/includes \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/src/includes \
-I$(top_srcdir)/third-party \
@LIBSPDYLAY_CFLAGS@ \
@XML_CPPFLAGS@ \
@@ -39,13 +41,13 @@ AM_CPPFLAGS = \
@ZLIB_CFLAGS@ \
@DEFS@
AM_LDFLAGS = \
@JEMALLOC_LIBS@ \
@LIBSPDYLAY_LIBS@ \
@XML_LIBS@ \
@LIBEVENT_OPENSSL_LIBS@ \
@OPENSSL_LIBS@ \
@JANSSON_LIBS@ \
@ZLIB_LIBS@ \
@JEMALLOC_LIBS@ \
@SRC_LIBS@
LDADD = \
@@ -56,8 +58,10 @@ if ENABLE_APP
bin_PROGRAMS += nghttp nghttpd nghttpx
HELPER_OBJECTS = util.cc http2.cc timegm.c app_helper.cc nghttp2_gzip.c
HELPER_HFILES = util.h http2.h timegm.h app_helper.h nghttp2_config.h \
HELPER_OBJECTS = util.cc libevent_util.cc \
http2.cc timegm.c app_helper.cc nghttp2_gzip.c
HELPER_HFILES = util.h libevent_util.h \
http2.h timegm.h app_helper.h nghttp2_config.h \
nghttp2_gzip.h
HTML_PARSER_OBJECTS =
@@ -74,11 +78,10 @@ nghttpd_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttpd.cc \
ssl.cc ssl.h \
HttpServer.cc HttpServer.h
if ENABLE_H2LOAD
bin_PROGRAMS += h2load
h2load_SOURCES = util.cc util.h http2.cc http2.h h2load.cc h2load.h \
h2load_SOURCES = util.cc util.h libevent_util.cc libevent_util.h \
http2.cc http2.h h2load.cc h2load.h \
timegm.c timegm.h \
ssl.cc ssl.h \
h2load_session.h \
@@ -88,10 +91,9 @@ if HAVE_SPDYLAY
h2load_SOURCES += h2load_spdy_session.cc h2load_spdy_session.h
endif # HAVE_SPDYLAY
endif # ENABLE_H2LOAD
NGHTTPX_SRCS = \
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \
libevent_util.cc libevent_util.h \
app_helper.cc app_helper.h \
ssl.cc ssl.h \
shrpx_config.cc shrpx_config.h \
@@ -113,7 +115,9 @@ NGHTTPX_SRCS = \
shrpx_ssl.cc shrpx_ssl.h \
shrpx_thread_event_receiver.cc shrpx_thread_event_receiver.h \
shrpx_worker.cc shrpx_worker.h \
shrpx_worker_config.cc shrpx_worker_config.h
shrpx_worker_config.cc shrpx_worker_config.h \
shrpx_connect_blocker.cc shrpx_connect_blocker.h \
shrpx_downstream_connection_pool.cc shrpx_downstream_connection_pool.h
if HAVE_SPDYLAY
NGHTTPX_SRCS += shrpx_spdy_upstream.cc shrpx_spdy_upstream.h
@@ -158,3 +162,33 @@ inflatehd_SOURCES = inflatehd.cc $(HPACK_TOOLS_COMMON_SRCS)
deflatehd_SOURCES = deflatehd.cc $(HPACK_TOOLS_COMMON_SRCS)
endif # ENABLE_HPACK_TOOLS
if ENABLE_ASIO_LIB
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libnghttp2_asio.pc
DISTCLEANFILES = $(pkgconfig_DATA)
lib_LTLIBRARIES = libnghttp2_asio.la
libnghttp2_asio_la_SOURCES = \
asio_connection.h \
asio_server.cc asio_server.h \
asio_io_service_pool.cc asio_io_service_pool.h \
asio_http2_handler.cc asio_http2_handler.h \
asio_http2_impl.cc asio_http2_impl.h \
util.cc util.h http2.cc http2.h \
ssl.cc ssl.h
libnghttp2_asio_la_CPPFLAGS= ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
libnghttp2_asio_la_LDFLAGS = \
${BOOST_LDFLAGS} \
${BOOST_ASIO_LIB} \
${BOOST_THREAD_LIB} \
${BOOST_SYSTEM_LIB} \
@OPENSSL_LIBS@ \
-no-undefined \
-version-info 0:0:0
libnghttp2_asio_la_LIBADD = $(top_builddir)/lib/libnghttp2.la
endif # ENABLE_ASIO_LIB

View File

@@ -52,7 +52,7 @@
namespace nghttp2 {
namespace {
const char* strstatus(nghttp2_error_code error_code)
const char* strstatus(uint32_t error_code)
{
switch(error_code) {
case NGHTTP2_NO_ERROR:
@@ -81,6 +81,8 @@ const char* strstatus(nghttp2_error_code error_code)
return "ENHANCE_YOUR_CALM";
case NGHTTP2_INADEQUATE_SECURITY:
return "INADEQUATE_SECURITY";
case NGHTTP2_HTTP_1_1_REQUIRED:
return "HTTP_1_1_REQUIRED";
default:
return "UNKNOWN";
}
@@ -99,6 +101,10 @@ const char* strsettingsid(int32_t id)
return "SETTINGS_MAX_CONCURRENT_STREAMS";
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
return "SETTINGS_INITIAL_WINDOW_SIZE";
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
return "SETTINGS_MAX_FRAME_SIZE";
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
return "SETTINGS_MAX_HEADER_LIST_SIZE";
default:
return "UNKNOWN";
}
@@ -187,10 +193,11 @@ void print_nv(nghttp2_nv *nv)
namespace {
void print_nv(nghttp2_nv *nva, size_t nvlen)
{
for(auto& nv : http2::sort_nva(nva, nvlen)) {
auto end = nva + nvlen;
for(; nva != end; ++nva) {
print_frame_attr_indent();
print_nv(&nv);
print_nv(nva);
}
}
} // namelen
@@ -221,12 +228,6 @@ void print_flags(const nghttp2_frame_hd& hd)
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
s += "END_STREAM";
}
if(hd.flags & NGHTTP2_FLAG_END_SEGMENT) {
if(!s.empty()) {
s += " | ";
}
s += "END_SEGMENT";
}
if(hd.flags & NGHTTP2_FLAG_PADDED) {
if(!s.empty()) {
s += " | ";
@@ -238,12 +239,6 @@ void print_flags(const nghttp2_frame_hd& hd)
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
s += "END_STREAM";
}
if(hd.flags & NGHTTP2_FLAG_END_SEGMENT) {
if(!s.empty()) {
s += " | ";
}
s += "END_SEGMENT";
}
if(hd.flags & NGHTTP2_FLAG_END_HEADERS) {
if(!s.empty()) {
s += " | ";
@@ -448,18 +443,17 @@ int verbose_on_header_callback(nghttp2_session *session,
uint8_t flags,
void *user_data)
{
nghttp2_nv nva = {
nghttp2_nv nv = {
const_cast<uint8_t*>(name), const_cast<uint8_t*>(value),
namelen, valuelen
};
for(auto& nv : http2::sort_nva(&nva, 1)) {
print_timer();
fprintf(outfile, " (stream_id=%d, noind=%d) ", frame->hd.stream_id,
(flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0);
print_timer();
fprintf(outfile, " recv (stream_id=%d, noind=%d) ", frame->hd.stream_id,
(flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0);
print_nv(&nv);
}
print_nv(&nv);
fflush(outfile);
return 0;
}
@@ -476,7 +470,7 @@ int verbose_on_frame_recv_callback
int verbose_on_invalid_frame_recv_callback
(nghttp2_session *session, const nghttp2_frame *frame,
nghttp2_error_code error_code, void *user_data)
uint32_t error_code, void *user_data)
{
print_timer();
fprintf(outfile, " [INVALID; status=%s] recv ", strstatus(error_code));
@@ -485,33 +479,6 @@ int verbose_on_invalid_frame_recv_callback
return 0;
}
namespace {
void dump_header(const uint8_t *head, size_t headlen)
{
size_t i;
print_frame_attr_indent();
fprintf(outfile, "Header dump: ");
for(i = 0; i < headlen; ++i) {
fprintf(outfile, "%02X ", head[i]);
}
fprintf(outfile, "\n");
}
} // namespace
int verbose_on_unknown_frame_recv_callback(nghttp2_session *session,
const uint8_t *head,
size_t headlen,
const uint8_t *payload,
size_t payloadlen,
void *user_data)
{
print_timer();
fprintf(outfile, " recv unknown frame\n");
dump_header(head, headlen);
fflush(outfile);
return 0;
}
int verbose_on_frame_send_callback
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
{
@@ -522,6 +489,23 @@ int verbose_on_frame_send_callback
return 0;
}
int verbose_on_data_chunk_recv_callback
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
const uint8_t *data, size_t len, void *user_data)
{
print_timer();
auto srecv = nghttp2_session_get_stream_effective_recv_data_length
(session, stream_id);
auto crecv = nghttp2_session_get_effective_recv_data_length(session);
fprintf(outfile,
" recv (stream_id=%d, length=%zu, srecv=%d, crecv=%d) DATA\n",
stream_id, len, srecv, crecv);
fflush(outfile);
return 0;
}
namespace {
std::chrono::steady_clock::time_point base_tv;
} // namespace

View File

@@ -51,18 +51,15 @@ int verbose_on_frame_recv_callback
int verbose_on_invalid_frame_recv_callback
(nghttp2_session *session, const nghttp2_frame *frame,
nghttp2_error_code error_code, void *user_data);
int verbose_on_unknown_frame_recv_callback(nghttp2_session *session,
const uint8_t *head,
size_t headlen,
const uint8_t *payload,
size_t payloadlen,
void *user_data);
uint32_t error_code, void *user_data);
int verbose_on_frame_send_callback
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data);
int verbose_on_data_chunk_recv_callback
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
const uint8_t *data, size_t len, void *user_data);
// Returns difference between |a| and |b| in milliseconds, assuming
// |a| is more recent than |b|.
template<typename TimePoint>

193
src/asio_connection.h Normal file
View File

@@ -0,0 +1,193 @@
/*
* 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:
//
// connection.hpp
// ~~~~~~~~~~~~~~
//
// 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)
//
#ifndef HTTP_SERVER2_CONNECTION_HPP
#define HTTP_SERVER2_CONNECTION_HPP
#include "nghttp2_config.h"
#include <memory>
#include <boost/asio.hpp>
#include <boost/noncopyable.hpp>
#include <boost/array.hpp>
#include <nghttp2/asio_http2.h>
#include "asio_http2_handler.h"
#include "util.h"
namespace nghttp2 {
namespace asio_http2 {
namespace server {
/// Represents a single connection from a client.
template<typename socket_type>
class connection
: public std::enable_shared_from_this<connection<socket_type>>,
private boost::noncopyable
{
public:
/// Construct a connection with the given io_service.
template<typename... SocketArgs>
explicit connection(request_cb cb,
boost::asio::io_service& task_io_service,
SocketArgs&&... args)
: socket_(std::forward<SocketArgs>(args)...),
request_cb_(std::move(cb)),
task_io_service_(task_io_service),
writing_(false)
{}
/// Start the first asynchronous operation for the connection.
void start()
{
handler_ = std::make_shared<http2_handler>
(socket_.get_io_service(),
task_io_service_,
[this]()
{
do_write();
},
request_cb_);
if(handler_->start() != 0) {
return;
}
do_read();
}
socket_type& socket()
{
return socket_;
}
void do_read()
{
auto self = this->shared_from_this();
socket_.async_read_some
(boost::asio::buffer(buffer_),
[this, self](const boost::system::error_code& e,
std::size_t bytes_transferred)
{
if (!e) {
if(handler_->on_read(buffer_, bytes_transferred) != 0) {
return;
}
do_write();
if(!writing_ && handler_->should_stop()) {
return;
}
do_read();
}
// If an error occurs then no new asynchronous operations are
// started. This means that all shared_ptr references to the
// connection object will disappear and the object will be
// destroyed automatically after this handler returns. The
// connection class's destructor closes the socket.
});
}
void do_write()
{
auto self = this->shared_from_this();
if(writing_) {
return;
}
int rv;
std::size_t nwrite;
rv = handler_->on_write(outbuf_, nwrite);
if(rv != 0) {
return;
}
if(nwrite == 0) {
return;
}
writing_ = true;
boost::asio::async_write
(socket_, boost::asio::buffer(outbuf_, nwrite),
[this, self](const boost::system::error_code& e,
std::size_t)
{
if(!e) {
writing_ = false;
do_write();
}
});
// No new asynchronous operations are started. This means that all
// shared_ptr references to the connection object will disappear and
// the object will be destroyed automatically after this handler
// returns. The connection class's destructor closes the socket.
}
private:
socket_type socket_;
request_cb request_cb_;
boost::asio::io_service& task_io_service_;
std::shared_ptr<http2_handler> handler_;
/// Buffer for incoming data.
boost::array<uint8_t, 8192> buffer_;
boost::array<uint8_t, 16394> outbuf_;
bool writing_;
};
} // namespace server
} // namespace asio_http2
} // namespace nghttp2
#endif // HTTP_SERVER2_CONNECTION_HPP

958
src/asio_http2_handler.cc Normal file
View File

@@ -0,0 +1,958 @@
/*
* 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.
*/
#include "asio_http2_handler.h"
#include <iostream>
#include "http2.h"
#include "util.h"
namespace nghttp2 {
namespace asio_http2 {
channel::channel()
: impl_(util::make_unique<channel_impl>())
{}
void channel::post(void_cb cb)
{
impl_->post(std::move(cb));
}
channel_impl& channel::impl()
{
return *impl_;
}
channel_impl::channel_impl()
: strand_(nullptr)
{}
void channel_impl::post(void_cb cb)
{
strand_->post(std::move(cb));
}
void channel_impl::strand(boost::asio::io_service::strand *strand)
{
strand_ = strand;
}
namespace server {
extern std::shared_ptr<std::string> cached_date;
request::request()
: impl_(util::make_unique<request_impl>())
{}
const std::vector<header>& request::headers() const
{
return impl_->headers();
}
const std::string& request::method() const
{
return impl_->method();
}
const std::string& request::scheme() const
{
return impl_->scheme();
}
const std::string& request::authority() const
{
return impl_->authority();
}
const std::string& request::host() const
{
return impl_->host();
}
const std::string& request::path() const
{
return impl_->path();
}
bool request::push(std::string method, std::string path,
std::vector<header> headers)
{
return impl_->push(std::move(method), std::move(path), std::move(headers));
}
bool request::pushed() const
{
return impl_->pushed();
}
bool request::closed() const
{
return impl_->closed();
}
void request::on_data(data_cb cb)
{
return impl_->on_data(std::move(cb));
}
void request::on_end(void_cb cb)
{
return impl_->on_end(std::move(cb));
}
bool request::run_task(thread_cb start)
{
return impl_->run_task(std::move(start));
}
request_impl& request::impl()
{
return *impl_;
}
response::response()
: impl_(util::make_unique<response_impl>())
{}
void response::write_head(unsigned int status_code,
std::vector<header> headers)
{
impl_->write_head(status_code, std::move(headers));
}
void response::end(std::string data)
{
impl_->end(std::move(data));
}
void response::end(read_cb cb)
{
impl_->end(std::move(cb));
}
void response::resume()
{
impl_->resume();
}
unsigned int response::status_code() const
{
return impl_->status_code();
}
bool response::started() const
{
return impl_->started();
}
response_impl& response::impl()
{
return *impl_;
}
request_impl::request_impl()
: pushed_(false)
{}
const std::vector<header>& request_impl::headers() const
{
return headers_;
}
const std::string& request_impl::method() const
{
return method_;
}
const std::string& request_impl::scheme() const
{
return scheme_;
}
const std::string& request_impl::authority() const
{
return authority_;
}
const std::string& request_impl::host() const
{
return host_;
}
const std::string& request_impl::path() const
{
return path_;
}
void request_impl::set_header(std::vector<header> headers)
{
headers_ = std::move(headers);
}
void request_impl::add_header(std::string name, std::string value)
{
headers_.push_back(header{std::move(name), std::move(value)});
}
void request_impl::method(std::string arg)
{
method_ = std::move(arg);
}
void request_impl::scheme(std::string arg)
{
scheme_ = std::move(arg);
}
void request_impl::authority(std::string arg)
{
authority_ = std::move(arg);
}
void request_impl::host(std::string arg)
{
host_ = std::move(arg);
}
void request_impl::path(std::string arg)
{
path_ = std::move(arg);
}
bool request_impl::push(std::string method, std::string path,
std::vector<header> headers)
{
if(closed()) {
return false;
}
auto handler = handler_.lock();
auto stream = stream_.lock();
auto rv = handler->push_promise
(*stream, std::move(method), std::move(path), std::move(headers));
return rv == 0;
}
bool request_impl::pushed() const
{
return pushed_;
}
void request_impl::pushed(bool f)
{
pushed_ = f;
}
bool request_impl::closed() const
{
return handler_.expired() || stream_.expired();
}
void request_impl::on_data(data_cb cb)
{
on_data_cb_ = std::move(cb);
}
void request_impl::on_end(void_cb cb)
{
on_end_cb_ = std::move(cb);
}
bool request_impl::run_task(thread_cb start)
{
if(closed()) {
return false;
}
auto handler = handler_.lock();
return handler->run_task(std::move(start));
}
void request_impl::handler(std::weak_ptr<http2_handler> h)
{
handler_ = std::move(h);
}
void request_impl::stream(std::weak_ptr<http2_stream> s)
{
stream_ = std::move(s);
}
void request_impl::call_on_data(const uint8_t *data, std::size_t len)
{
if(on_data_cb_) {
on_data_cb_(data, len);
}
}
void request_impl::call_on_end()
{
if(on_end_cb_) {
on_end_cb_();
}
}
response_impl::response_impl()
: status_code_(200),
started_(false)
{}
unsigned int response_impl::status_code() const
{
return status_code_;
}
void response_impl::write_head(unsigned int status_code,
std::vector<header> headers)
{
status_code_ = status_code;
headers_ = std::move(headers);
}
void response_impl::end(std::string data)
{
if(started_) {
return;
}
auto strio = std::make_shared<std::pair<std::string, size_t>>
(std::move(data), data.size());
auto read_cb = [strio](uint8_t *buf, size_t len)
{
auto nread = std::min(len, strio->second);
memcpy(buf, strio->first.c_str(), nread);
strio->second -= nread;
if(strio->second == 0) {
return std::make_pair(nread, true);
}
return std::make_pair(nread, false);
};
end(std::move(read_cb));
}
void response_impl::end(read_cb cb)
{
if(started_ || closed()) {
return;
}
read_cb_ = std::move(cb);
started_ = true;
auto handler = handler_.lock();
auto stream = stream_.lock();
if(handler->start_response(*stream) != 0) {
handler->stream_error(stream->get_stream_id(), NGHTTP2_INTERNAL_ERROR);
return;
}
if(!handler->inside_callback()) {
handler->initiate_write();
}
}
bool response_impl::closed() const
{
return handler_.expired() || stream_.expired();
}
void response_impl::resume()
{
if(closed()) {
return;
}
auto handler = handler_.lock();
auto stream = stream_.lock();
handler->resume(*stream);
if(!handler->inside_callback()) {
handler->initiate_write();
}
}
bool response_impl::started() const
{
return started_;
}
const std::vector<header>& response_impl::headers() const
{
return headers_;
}
void response_impl::handler(std::weak_ptr<http2_handler> h)
{
handler_ = std::move(h);
}
void response_impl::stream(std::weak_ptr<http2_stream> s)
{
stream_ = std::move(s);
}
std::pair<ssize_t, bool> response_impl::call_read
(uint8_t *data, std::size_t len)
{
if(read_cb_) {
return read_cb_(data, len);
}
return std::make_pair(0, true);
}
http2_stream::http2_stream(int32_t stream_id)
: request_(std::make_shared<request>()),
response_(std::make_shared<response>()),
stream_id_(stream_id)
{}
int32_t http2_stream::get_stream_id() const
{
return stream_id_;
}
const std::shared_ptr<request>& http2_stream::get_request()
{
return request_;
}
const std::shared_ptr<response>& http2_stream::get_response()
{
return response_;
}
namespace {
int stream_error(nghttp2_session *session, int32_t stream_id,
uint32_t error_code)
{
return nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, stream_id,
error_code);
}
} // namespace
namespace {
int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
auto handler = static_cast<http2_handler*>(user_data);
if(frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
handler->create_stream(frame->hd.stream_id);
return 0;
}
} // namespace
namespace {
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)
{
auto handler = static_cast<http2_handler*>(user_data);
auto stream_id = frame->hd.stream_id;
if(frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
auto stream = handler->find_stream(stream_id);
if(!stream) {
return 0;
}
if(!nghttp2_check_header_name(name, namelen) ||
!nghttp2_check_header_value(value, valuelen)) {
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
auto& req = stream->get_request()->impl();
if(name[0] == ':' && !req.headers().empty()) {
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if(util::streq(":method", name, namelen)) {
if(!req.method().empty()) {
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
req.method(std::string(value, value + valuelen));
} else if(util::streq(":scheme", name, namelen)) {
if(!req.scheme().empty()) {
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
req.scheme(std::string(value, value + valuelen));
} else if(util::streq(":authority", name, namelen)) {
if(!req.authority().empty()) {
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
req.authority(std::string(value, value + valuelen));
} else if(util::streq(":path", name, namelen)) {
if(!req.path().empty()) {
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
req.path(std::string(value, value + valuelen));
} else {
if(name[0] == ':') {
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if(util::streq("host", name, namelen)) {
req.host(std::string(value, value + valuelen));
}
req.add_header(std::string(name, name + namelen),
std::string(value, value + valuelen));
}
return 0;
}
} // namespace
namespace {
int on_frame_recv_callback
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
{
auto handler = static_cast<http2_handler*>(user_data);
auto stream = handler->find_stream(frame->hd.stream_id);
switch(frame->hd.type) {
case NGHTTP2_DATA:
if(!stream) {
break;
}
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream->get_request()->impl().call_on_end();
}
break;
case NGHTTP2_HEADERS: {
if(!stream || frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
break;
}
auto& req = stream->get_request()->impl();
if(req.method().empty() || req.scheme().empty() || req.path().empty() ||
(req.authority().empty() && req.host().empty())) {
stream_error(session, frame->hd.stream_id, NGHTTP2_PROTOCOL_ERROR);
return 0;
}
if(req.host().empty()) {
req.host(req.authority());
}
handler->call_on_request(*stream);
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream->get_request()->impl().call_on_end();
}
break;
}
}
return 0;
}
} // namespace
namespace {
int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
const uint8_t *data, size_t len,
void *user_data)
{
auto handler = static_cast<http2_handler*>(user_data);
auto stream = handler->find_stream(stream_id);
if(!stream) {
return 0;
}
stream->get_request()->impl().call_on_data(data, len);
return 0;
}
} // namespace
namespace {
int on_stream_close_callback
(nghttp2_session *session, int32_t stream_id, uint32_t error_code,
void *user_data)
{
auto handler = static_cast<http2_handler*>(user_data);
handler->close_stream(stream_id);
return 0;
}
} // namespace
namespace {
int on_frame_send_callback
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
{
auto handler = static_cast<http2_handler*>(user_data);
if(frame->hd.type != NGHTTP2_PUSH_PROMISE) {
return 0;
}
auto stream = handler->find_stream(frame->push_promise.promised_stream_id);
if(!stream) {
return 0;
}
handler->call_on_request(*stream);
return 0;
}
} // namespace
namespace {
int on_frame_not_send_callback
(nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code,
void *user_data)
{
if(frame->hd.type != NGHTTP2_HEADERS) {
return 0;
}
// Issue RST_STREAM so that stream does not hang around.
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
NGHTTP2_INTERNAL_ERROR);
return 0;
}
} // namespace
http2_handler::http2_handler
(boost::asio::io_service& io_service,
boost::asio::io_service& task_io_service_,
connection_write writefun, request_cb cb)
: writefun_(writefun),
request_cb_(std::move(cb)),
io_service_(io_service),
task_io_service_(task_io_service_),
strand_(std::make_shared<boost::asio::io_service::strand>(io_service_)),
session_(nullptr),
buf_(nullptr),
buflen_(0),
inside_callback_(false)
{}
http2_handler::~http2_handler()
{
nghttp2_session_del(session_);
}
int http2_handler::start()
{
int rv;
nghttp2_session_callbacks *callbacks;
rv = nghttp2_session_callbacks_new(&callbacks);
if(rv != 0) {
return -1;
}
auto cb_del = util::defer(callbacks, nghttp2_session_callbacks_del);
nghttp2_session_callbacks_set_on_begin_headers_callback
(callbacks, on_begin_headers_callback);
nghttp2_session_callbacks_set_on_header_callback
(callbacks, on_header_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_stream_close_callback
(callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_frame_send_callback
(callbacks, on_frame_send_callback);
nghttp2_session_callbacks_set_on_frame_not_send_callback
(callbacks, on_frame_not_send_callback);
nghttp2_option *option;
rv = nghttp2_option_new(&option);
if(rv != 0) {
return -1;
}
auto opt_del = util::defer(option, nghttp2_option_del);
nghttp2_option_set_recv_client_preface(option, 1);
rv = nghttp2_session_server_new2(&session_, callbacks, this, option);
if(rv != 0) {
return -1;
}
nghttp2_settings_entry ent { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 };
nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, &ent, 1);
return 0;
}
std::shared_ptr<http2_stream> http2_handler::create_stream(int32_t stream_id)
{
auto stream = std::make_shared<http2_stream>(stream_id);
streams_.emplace(stream_id, stream);
auto self = shared_from_this();
auto& req = stream->get_request()->impl();
auto& res = stream->get_response()->impl();
req.handler(self);
req.stream(stream);
res.handler(self);
res.stream(stream);
return stream;
}
void http2_handler::close_stream(int32_t stream_id)
{
streams_.erase(stream_id);
}
std::shared_ptr<http2_stream> http2_handler::find_stream(int32_t stream_id)
{
auto i = streams_.find(stream_id);
if(i == std::end(streams_)) {
return nullptr;
}
return (*i).second;
}
void http2_handler::call_on_request(http2_stream& stream)
{
request_cb_(stream.get_request(), stream.get_response());
}
bool http2_handler::should_stop() const
{
return
!nghttp2_session_want_read(session_) &&
!nghttp2_session_want_write(session_);
}
int http2_handler::start_response(http2_stream& stream)
{
int rv;
auto& res = stream.get_response()->impl();
auto& headers = res.headers();
auto nva = std::vector<nghttp2_nv>();
nva.reserve(2 + headers.size());
auto status = std::to_string(res.status_code());
auto date = cached_date;
nva.push_back(nghttp2::http2::make_nv_ls(":status", status));
nva.push_back(nghttp2::http2::make_nv_ls("date", *date));
for(auto& hd : headers) {
nva.push_back(nghttp2::http2::make_nv(hd.name, hd.value));
}
nghttp2_data_provider prd;
prd.source.ptr = &stream;
prd.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) -> ssize_t
{
auto& stream = *static_cast<http2_stream*>(source->ptr);
auto rv = stream.get_response()->impl().call_read(buf, length);
if(rv.first < 0) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if(rv.second) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
} else if(rv.first == 0) {
return NGHTTP2_ERR_DEFERRED;
}
return rv.first;
};
rv = nghttp2_submit_response(session_, stream.get_stream_id(),
nva.data(), nva.size(), &prd);
if(rv != 0) {
return -1;
}
return 0;
}
void http2_handler::enter_callback()
{
assert(!inside_callback_);
inside_callback_ = true;
}
void http2_handler::leave_callback()
{
assert(inside_callback_);
inside_callback_ = false;
}
bool http2_handler::inside_callback() const
{
return inside_callback_;
}
void http2_handler::stream_error(int32_t stream_id, uint32_t error_code)
{
::nghttp2::asio_http2::server::stream_error(session_, stream_id, error_code);
}
void http2_handler::initiate_write()
{
writefun_();
}
void http2_handler::resume(http2_stream& stream)
{
nghttp2_session_resume_data(session_, stream.get_stream_id());
}
int http2_handler::push_promise(http2_stream& stream, std::string method,
std::string path,
std::vector<header> headers)
{
int rv;
auto& req = stream.get_request()->impl();
auto nva = std::vector<nghttp2_nv>();
nva.reserve(5 + headers.size());
nva.push_back(nghttp2::http2::make_nv_ls(":method", method));
nva.push_back(nghttp2::http2::make_nv_ls(":scheme", req.scheme()));
if(!req.authority().empty()) {
nva.push_back(nghttp2::http2::make_nv_ls(":authority", req.authority()));
}
nva.push_back(nghttp2::http2::make_nv_ls(":path", path));
if(!req.host().empty()) {
nva.push_back(nghttp2::http2::make_nv_ls("host", req.host()));
}
for(auto& hd : headers) {
nva.push_back(nghttp2::http2::make_nv(hd.name, hd.value));
}
rv = nghttp2_submit_push_promise(session_, NGHTTP2_FLAG_NONE,
stream.get_stream_id(),
nva.data(), nva.size(), nullptr);
if(rv < 0) {
return -1;
}
auto promised_stream = create_stream(rv);
auto& promised_req = promised_stream->get_request()->impl();
promised_req.pushed(true);
promised_req.method(std::move(method));
promised_req.scheme(req.scheme());
promised_req.authority(req.authority());
promised_req.path(std::move(path));
promised_req.host(req.host());
promised_req.set_header(std::move(headers));
if(!req.host().empty()) {
promised_req.add_header("host", req.host());
}
return 0;
}
bool http2_handler::run_task(thread_cb start)
{
auto strand = strand_;
try {
task_io_service_.post
([start, strand]()
{
channel chan;
chan.impl().strand(strand.get());
start(chan);
});
return true;
} catch(std::exception& ex) {
return false;
}
}
boost::asio::io_service& http2_handler::io_service()
{
return io_service_;
}
callback_guard::callback_guard(http2_handler& h)
: handler(h)
{
handler.enter_callback();
}
callback_guard::~callback_guard()
{
handler.leave_callback();
}
} // namespace server
} // namespace asio_http2
} // namespace nghttp2

265
src/asio_http2_handler.h Normal file
View File

@@ -0,0 +1,265 @@
/*
* 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.
*/
#ifndef HTTP2_HANDLER_H
#define HTTP2_HANDLER_H
#include "nghttp2_config.h"
#include <map>
#include <vector>
#include <functional>
#include <string>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <nghttp2/nghttp2.h>
#include <nghttp2/asio_http2.h>
namespace nghttp2 {
namespace asio_http2 {
class channel_impl {
public:
channel_impl();
void post(void_cb cb);
void strand(boost::asio::io_service::strand *strand);
private:
boost::asio::io_service::strand *strand_;
};
namespace server {
class http2_handler;
class http2_stream;
class request_impl {
public:
request_impl();
const std::vector<header>& headers() const;
const std::string& method() const;
const std::string& scheme() const;
const std::string& authority() const;
const std::string& host() const;
const std::string& path() const;
bool push(std::string method, std::string path,
std::vector<header> headers = {});
bool pushed() const;
bool closed() const;
void on_data(data_cb cb);
void on_end(void_cb cb);
bool run_task(thread_cb start);
void set_header(std::vector<header> headers);
void add_header(std::string name, std::string value);
void method(std::string method);
void scheme(std::string scheme);
void authority(std::string authority);
void host(std::string host);
void path(std::string path);
void pushed(bool f);
void handler(std::weak_ptr<http2_handler> h);
void stream(std::weak_ptr<http2_stream> s);
void call_on_data(const uint8_t *data, std::size_t len);
void call_on_end();
private:
std::vector<header> headers_;
std::string method_;
std::string scheme_;
std::string authority_;
std::string host_;
std::string path_;
data_cb on_data_cb_;
void_cb on_end_cb_;
std::weak_ptr<http2_handler> handler_;
std::weak_ptr<http2_stream> stream_;
bool pushed_;
};
class response_impl {
public:
response_impl();
void write_head(unsigned int status_code, std::vector<header> headers = {});
void end(std::string data = "");
void end(read_cb cb);
void resume();
bool closed() const;
unsigned int status_code() const;
const std::vector<header>& headers() const;
bool started() const;
void handler(std::weak_ptr<http2_handler> h);
void stream(std::weak_ptr<http2_stream> s);
read_cb::result_type call_read(uint8_t *data, std::size_t len);
private:
std::vector<header> headers_;
read_cb read_cb_;
std::weak_ptr<http2_handler> handler_;
std::weak_ptr<http2_stream> stream_;
unsigned int status_code_;
bool started_;
};
class http2_stream {
public:
http2_stream(int32_t stream_id);
int32_t get_stream_id() const;
const std::shared_ptr<request>& get_request();
const std::shared_ptr<response>& get_response();
private:
std::shared_ptr<request> request_;
std::shared_ptr<response> response_;
int32_t stream_id_;
};
struct callback_guard {
callback_guard(http2_handler& h);
~callback_guard();
http2_handler& handler;
};
typedef std::function<void(void)> connection_write;
class http2_handler : public std::enable_shared_from_this<http2_handler> {
public:
http2_handler(boost::asio::io_service& io_service,
boost::asio::io_service& task_io_service,
connection_write writefun,
request_cb cb);
~http2_handler();
int start();
std::shared_ptr<http2_stream> create_stream(int32_t stream_id);
void close_stream(int32_t stream_id);
std::shared_ptr<http2_stream> find_stream(int32_t stream_id);
void call_on_request(http2_stream& stream);
bool should_stop() const;
int start_response(http2_stream& stream);
void stream_error(int32_t stream_id, uint32_t error_code);
void initiate_write();
void enter_callback();
void leave_callback();
bool inside_callback() const;
void resume(http2_stream& stream);
int push_promise(http2_stream& stream, std::string method,
std::string path,
std::vector<header> headers);
bool run_task(thread_cb start);
boost::asio::io_service& io_service();
template<size_t N>
int on_read(const boost::array<uint8_t, N>& buffer, std::size_t len)
{
callback_guard cg(*this);
int rv;
rv = nghttp2_session_mem_recv(session_, buffer.data(), len);
if(rv < 0) {
return -1;
}
return 0;
}
template<size_t N>
int on_write(boost::array<uint8_t, N>& buffer, std::size_t& len)
{
callback_guard cg(*this);
len = 0;
if(buf_) {
std::copy(buf_, buf_ + buflen_, std::begin(buffer));
len += buflen_;
buf_ = nullptr;
buflen_ = 0;
}
for(;;) {
const uint8_t *data;
auto nread = nghttp2_session_mem_send(session_, &data);
if(nread < 0) {
return -1;
}
if(nread == 0) {
break;
}
if(len + nread > buffer.size()) {
buf_ = data;
buflen_ = nread;
break;
}
std::copy(data, data + nread, std::begin(buffer) + len);
len += nread;
}
return 0;
}
private:
std::map<int32_t, std::shared_ptr<http2_stream>> streams_;
connection_write writefun_;
request_cb request_cb_;
boost::asio::io_service& io_service_;
boost::asio::io_service& task_io_service_;
std::shared_ptr<boost::asio::io_service::strand> strand_;
nghttp2_session *session_;
const uint8_t *buf_;
std::size_t buflen_;
bool inside_callback_;
};
} // namespace server
} // namespace asio_http2
} // namespace nghttp
#endif // HTTP2_HANDLER_H

214
src/asio_http2_impl.cc Normal file
View File

@@ -0,0 +1,214 @@
/*
* 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.
*/
#include "asio_http2_impl.h"
#include <boost/asio/ssl.hpp>
#include <openssl/ssl.h>
#include <nghttp2/nghttp2.h>
#include "asio_server.h"
#include "util.h"
#include "ssl.h"
namespace nghttp2 {
namespace asio_http2 {
namespace server {
http2::http2()
: impl_(util::make_unique<http2_impl>())
{}
http2::~http2()
{}
void http2::listen(const std::string& address, uint16_t port, request_cb cb)
{
impl_->listen(address, port, std::move(cb));
}
void http2::num_threads(size_t num_threads)
{
impl_->num_threads(num_threads);
}
void http2::tls(std::string private_key_file,
std::string certificate_file)
{
impl_->tls(std::move(private_key_file), std::move(certificate_file));
}
void http2::num_concurrent_tasks(size_t num_concurrent_tasks)
{
impl_->num_concurrent_tasks(num_concurrent_tasks);
}
http2_impl::http2_impl()
: num_threads_(1),
num_concurrent_tasks_(1)
{}
namespace {
std::array<unsigned char, NGHTTP2_PROTO_VERSION_ID_LEN + 1>&
get_alpn_token()
{
static std::array<unsigned char, NGHTTP2_PROTO_VERSION_ID_LEN + 1> token;
token[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
std::copy(NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID + NGHTTP2_PROTO_VERSION_ID_LEN,
std::begin(token) + 1);
return token;
}
} // namespace
void http2_impl::listen(const std::string& address, uint16_t port,
request_cb cb)
{
std::unique_ptr<boost::asio::ssl::context> ssl_ctx;
if(!private_key_file_.empty() && !certificate_file_.empty()) {
ssl_ctx = util::make_unique<boost::asio::ssl::context>
(boost::asio::ssl::context::sslv23);
ssl_ctx->use_private_key_file(private_key_file_,
boost::asio::ssl::context::pem);
ssl_ctx->use_certificate_chain_file(certificate_file_);
auto ctx = ssl_ctx->native_handle();
SSL_CTX_set_options(ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
SSL_OP_SINGLE_ECDH_USE |
SSL_OP_NO_TICKET |
SSL_OP_CIPHER_SERVER_PREFERENCE);
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_cipher_list(ctx, ssl::DEFAULT_CIPHER_LIST);
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if(ecdh) {
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
EC_KEY_free(ecdh);
}
SSL_CTX_set_next_protos_advertised_cb
(ctx,
[](SSL *s, const unsigned char **data, unsigned int *len, void *arg) {
auto& token = get_alpn_token();
*data = token.data();
*len = token.size();
return SSL_TLSEXT_ERR_OK;
}, nullptr);
}
server(address, port, num_threads_, num_concurrent_tasks_,
std::move(cb), std::move(ssl_ctx)).run();
}
void http2_impl::num_threads(size_t num_threads)
{
num_threads_ = num_threads;
}
void http2_impl::tls(std::string private_key_file,
std::string certificate_file)
{
private_key_file_ = std::move(private_key_file);
certificate_file_ = std::move(certificate_file);
}
void http2_impl::num_concurrent_tasks(size_t num_concurrent_tasks)
{
num_concurrent_tasks_ = num_concurrent_tasks;
}
} // namespace server
template<typename T, typename F>
std::shared_ptr<util::Defer<T, F>> defer_shared(T&& t, F f)
{
return std::make_shared<util::Defer<T, F>>(std::forward<T>(t),
std::forward<F>(f));
}
read_cb file_reader(const std::string& path)
{
auto fd = open(path.c_str(), O_RDONLY);
if(fd == -1) {
return read_cb();
}
return file_reader_from_fd(fd);
}
read_cb file_reader_from_fd(int fd)
{
auto d = defer_shared(static_cast<int>(fd), close);
return [fd, d](uint8_t *buf, size_t len) -> read_cb::result_type
{
int rv;
while((rv = read(fd, buf, len)) == -1 && errno == EINTR);
if(rv == -1) {
return std::make_pair(-1, false);
}
if(rv == 0) {
return std::make_pair(rv, true);
}
return std::make_pair(rv, false);
};
}
bool check_path(const std::string& path)
{
return util::check_path(path);
}
std::string percent_decode(const std::string& s)
{
return util::percentDecode(std::begin(s), std::end(s));
}
std::string http_date(int64_t t)
{
return util::http_date(t);
}
} // namespace asio_http2
} // namespace nghttp2

62
src/asio_http2_impl.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* 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.
*/
#ifndef ASIO_HTTP2_IMPL_H
#define ASIO_HTTP2_IMPL_H
#include "nghttp2_config.h"
#include <nghttp2/asio_http2.h>
namespace nghttp2 {
namespace asio_http2 {
namespace server {
class server;
class http2_impl {
public:
http2_impl();
void listen(const std::string& address, uint16_t port,
request_cb cb);
void num_threads(size_t num_threads);
void tls(std::string private_key_file, std::string certificate_file);
void num_concurrent_tasks(size_t num_concurrent_tasks);
private:
std::string private_key_file_;
std::string certificate_file_;
std::unique_ptr<server> server_;
std::size_t num_threads_;
std::size_t num_concurrent_tasks_;
};
} // namespace server
} // namespace asio_http2
} // namespace nghttp2
#endif // ASIO_HTTP2_IMPL_H

131
src/asio_io_service_pool.cc Normal file
View File

@@ -0,0 +1,131 @@
/*
* 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:
//
// io_service_pool.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 "asio_server.h"
#include <stdexcept>
#include <future>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
namespace nghttp2 {
namespace asio_http2 {
namespace server {
io_service_pool::io_service_pool(std::size_t pool_size,
std::size_t thread_pool_size)
: next_io_service_(0),
thread_pool_size_(thread_pool_size)
{
if (pool_size == 0) {
throw std::runtime_error("io_service_pool size is 0");
}
// Give all the io_services work to do so that their run() functions will not
// exit until they are explicitly stopped.
for (std::size_t i = 0; i < pool_size; ++i) {
auto io_service = std::make_shared<boost::asio::io_service>();
auto work = std::make_shared<boost::asio::io_service::work>(*io_service);
io_services_.push_back(io_service);
work_.push_back(work);
}
auto work = std::make_shared<boost::asio::io_service::work>
(task_io_service_);
work_.push_back(work);
}
void io_service_pool::run()
{
for(std::size_t i = 0; i < thread_pool_size_; ++i) {
thread_pool_.create_thread
([this]()
{
task_io_service_.run();
});
}
// Create a pool of threads to run all of the io_services.
auto futs = std::vector<std::future<std::size_t>>();
for (std::size_t i = 0; i < io_services_.size(); ++i) {
futs.push_back
(std::async(std::launch::async,
(size_t(boost::asio::io_service::*)(void))
&boost::asio::io_service::run,
io_services_[i]));
}
// Wait for all threads in the pool to exit.
for (auto& fut : futs) {
fut.get();
}
thread_pool_.join_all();
}
void io_service_pool::stop()
{
// Explicitly stop all io_services.
for (auto& iosv : io_services_) {
iosv->stop();
}
task_io_service_.stop();
}
boost::asio::io_service& io_service_pool::get_io_service()
{
// Use a round-robin scheme to choose the next io_service to use.
auto& io_service = *io_services_[next_io_service_];
++next_io_service_;
if (next_io_service_ == io_services_.size()) {
next_io_service_ = 0;
}
return io_service;
}
boost::asio::io_service& io_service_pool::get_task_io_service()
{
return task_io_service_;
}
} // namespace server
} // namespace asio_http2
} // namespace nghttp2

101
src/asio_io_service_pool.h Normal file
View File

@@ -0,0 +1,101 @@
/*
* 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:
//
// io_service_pool.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// 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)
//
#ifndef HTTP_SERVER2_IO_SERVICE_POOL_HPP
#define HTTP_SERVER2_IO_SERVICE_POOL_HPP
#include "nghttp2_config.h"
#include <vector>
#include <memory>
#include <boost/asio.hpp>
#include <boost/noncopyable.hpp>
#include <boost/thread.hpp>
#include <nghttp2/asio_http2.h>
namespace nghttp2 {
namespace asio_http2 {
namespace server {
/// A pool of io_service objects.
class io_service_pool
: private boost::noncopyable
{
public:
/// Construct the io_service pool.
explicit io_service_pool(std::size_t pool_size,
std::size_t thread_pool_size);
/// Run all io_service objects in the pool.
void run();
/// Stop all io_service objects in the pool.
void stop();
/// Get an io_service to use.
boost::asio::io_service& get_io_service();
boost::asio::io_service& get_task_io_service();
private:
typedef std::shared_ptr<boost::asio::io_service> io_service_ptr;
typedef std::shared_ptr<boost::asio::io_service::work> work_ptr;
/// The pool of io_services.
std::vector<io_service_ptr> io_services_;
boost::asio::io_service task_io_service_;
boost::thread_group thread_pool_;
/// The work that keeps the io_services running.
std::vector<work_ptr> work_;
/// The next io_service to use for a connection.
std::size_t next_io_service_;
std::size_t thread_pool_size_;
};
} // namespace server
} // namespace asio_http2
} // namespace nghttp2
#endif // HTTP_SERVER2_IO_SERVICE_POOL_HPP

165
src/asio_server.cc Normal file
View File

@@ -0,0 +1,165 @@
/*
* 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:
//
// server.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 "asio_server.h"
#include <boost/date_time/posix_time/posix_time.hpp>
namespace nghttp2 {
namespace asio_http2 {
namespace server {
server::server(const std::string& address, uint16_t port,
std::size_t io_service_pool_size,
std::size_t thread_pool_size,
request_cb cb,
std::unique_ptr<boost::asio::ssl::context> ssl_ctx)
: io_service_pool_(io_service_pool_size, thread_pool_size),
signals_(io_service_pool_.get_io_service()),
tick_timer_(io_service_pool_.get_io_service(),
boost::posix_time::seconds(1)),
acceptor_(io_service_pool_.get_io_service()),
ssl_ctx_(std::move(ssl_ctx)),
request_cb_(std::move(cb))
{
// Register to handle the signals that indicate when the server should exit.
// It is safe to register for the same signal multiple times in a program,
// provided all registration for the specified signal is made through Asio.
signals_.add(SIGINT);
signals_.add(SIGTERM);
#if defined(SIGQUIT)
signals_.add(SIGQUIT);
#endif // defined(SIGQUIT)
signals_.async_wait([this](const boost::system::error_code& error,
int signal_number)
{
io_service_pool_.stop();
});
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
boost::asio::ip::tcp::resolver resolver(acceptor_.get_io_service());
boost::asio::ip::tcp::resolver::query query(address, std::to_string(port));
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
acceptor_.open(endpoint.protocol());
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
acceptor_.bind(endpoint);
acceptor_.listen();
start_accept();
start_timer();
}
void server::run()
{
io_service_pool_.run();
}
std::shared_ptr<std::string> cached_date;
namespace {
void update_date()
{
cached_date = std::make_shared<std::string>(util::http_date(time(nullptr)));
}
} // namespace
void server::start_timer()
{
update_date();
tick_timer_.async_wait
([this](const boost::system::error_code& e)
{
tick_timer_.expires_at(tick_timer_.expires_at() +
boost::posix_time::seconds(1));
start_timer();
});
}
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
void server::start_accept()
{
if(ssl_ctx_) {
auto new_connection =
std::make_shared<connection<ssl_socket>>
(request_cb_, io_service_pool_.get_task_io_service(),
io_service_pool_.get_io_service(), *ssl_ctx_);
acceptor_.async_accept
(new_connection->socket().lowest_layer(),
[this, new_connection](const boost::system::error_code& e)
{
if(!e) {
new_connection->socket().lowest_layer().set_option
(boost::asio::ip::tcp::no_delay(true));
new_connection->socket().async_handshake
(boost::asio::ssl::stream_base::server,
[new_connection](const boost::system::error_code& e)
{
if(!e) {
new_connection->start();
}
});
}
start_accept();
});
} else {
auto new_connection =
std::make_shared<connection<boost::asio::ip::tcp::socket>>
(request_cb_, io_service_pool_.get_task_io_service(),
io_service_pool_.get_io_service());
acceptor_.async_accept
(new_connection->socket(),
[this, new_connection](const boost::system::error_code& e)
{
if (!e) {
new_connection->socket().set_option
(boost::asio::ip::tcp::no_delay(true));
new_connection->start();
}
start_accept();
});
}
}
} // namespace server
} // namespace asio_http2
} // namespace nghttp2

104
src/asio_server.h Normal file
View File

@@ -0,0 +1,104 @@
/*
* 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:
//
// server.hpp
// ~~~~~~~~~~
//
// 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)
//
#ifndef HTTP_SERVER2_SERVER_HPP
#define HTTP_SERVER2_SERVER_HPP
#include "nghttp2_config.h"
#include <string>
#include <vector>
#include <memory>
#include <boost/noncopyable.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <nghttp2/asio_http2.h>
#include "asio_connection.h"
#include "asio_io_service_pool.h"
namespace nghttp2 {
namespace asio_http2 {
namespace server {
/// The top-level class of the HTTP server.
class server
: private boost::noncopyable
{
public:
/// Construct the server to listen on the specified TCP address and port, and
/// serve up files from the given directory.
explicit server(const std::string& address, uint16_t port,
std::size_t io_service_pool_size,
std::size_t thread_pool_size,
request_cb cb,
std::unique_ptr<boost::asio::ssl::context> ssl_ctx);
/// Run the server's io_service loop.
void run();
private:
/// Initiate an asynchronous accept operation.
void start_accept();
void start_timer();
/// The pool of io_service objects used to perform asynchronous operations.
io_service_pool io_service_pool_;
/// The signal_set is used to register for process termination notifications.
boost::asio::signal_set signals_;
boost::asio::deadline_timer tick_timer_;
/// Acceptor used to listen for incoming connections.
boost::asio::ip::tcp::acceptor acceptor_;
std::unique_ptr<boost::asio::ssl::context> ssl_ctx_;
request_cb request_cb_;
};
} // namespace server
} // namespace asio_http2
} // namespace nghttp2
#endif // HTTP_SERVER2_SERVER_HPP

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