Compare commits

...

243 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
3a46a2c0a4 Update man pages 2015-05-08 17:55:15 +09:00
Tatsuhiro Tsujikawa
fbff101165 Update bash_completion 2015-05-08 17:54:51 +09:00
Tatsuhiro Tsujikawa
526d2c727d Bump up version number to 0.7.14, LT revision to 13:3:8 2015-05-08 17:51:54 +09:00
Tatsuhiro Tsujikawa
6c232da679 Merge branch 'alagoutte-misc' 2015-05-07 23:40:22 +09:00
Alexis La Goutte
1241c951d6 rv is only used in an assert.
The assert only evaluates to code if NDEBUG is undefined. Protect rv and its use accordingly

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

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

finer stats for h2load: fixed formatting
2015-05-01 10:30:09 -07:00
Tatsuhiro Tsujikawa
7b3a33a313 README.rst: Fix formatting and remove trailing spaces 2015-05-01 13:29:43 +09:00
Tatsuhiro Tsujikawa
ee52290de7 Merge branch 'brk0v-typo' 2015-05-01 00:41:48 +09:00
Viacheslav Biriukov
8f0899a190 mages to images typo 2015-04-30 18:22:51 +03:00
Tatsuhiro Tsujikawa
f6cfd082c7 Merge branch 'alagoutte-misc' 2015-04-30 18:43:41 +09:00
Tatsuhiro Tsujikawa
9d81be4b35 Merge branch 'misc' of https://github.com/alagoutte/nghttp2 into alagoutte-misc 2015-04-30 18:42:17 +09:00
Alexis La Goutte
a62778d6b0 fix comma at end of enumerator list [-Wpedantic] 2015-04-30 07:49:55 +02:00
Tatsuhiro Tsujikawa
ea612a2dce Merge branch 'nghttpx-headers-size-option' 2015-04-29 22:55:30 +09:00
Tatsuhiro Tsujikawa
026521b097 integration: Add tests for --header-field-buffer and --max-header-fields 2015-04-29 22:54:25 +09:00
Tatsuhiro Tsujikawa
9dc5259593 nghttpx: Take into account request URI in header size in https frontend 2015-04-29 22:23:25 +09:00
Tatsuhiro Tsujikawa
ea8a566d98 nghttpx: Send 431 if header field size exceeded the configuration limit 2015-04-29 21:39:46 +09:00
Tatsuhiro Tsujikawa
8c6f9e899f nghttpx: Enforce header field buffer limit for SPDY frontend 2015-04-29 21:27:36 +09:00
Tatsuhiro Tsujikawa
552f675466 nghttpx: Add --header-field-buffer and --max-header-fields options 2015-04-29 21:10:59 +09:00
Tatsuhiro Tsujikawa
f9a50333d2 Fix doc for nghttp2_select_next_protocol
We have to return this error code to notify OpenSSL that we have not
filled any values in |*out| and |*outlen|.
2015-04-28 23:12:27 +09:00
Tatsuhiro Tsujikawa
f05a4830c5 nghttp: Fix assertion error if very large value is given to -t 2015-04-28 21:51:28 +09:00
Tatsuhiro Tsujikawa
9e1b068a4b Fix bug that promised stream was not reset on decompression error 2015-04-28 21:38:52 +09:00
Tatsuhiro Tsujikawa
54bff91762 Bump up version number to 0.7.14-DEV 2015-04-28 00:01:09 +09:00
Tatsuhiro Tsujikawa
63630690a8 Fix make -j3 distcheck error 2015-04-27 23:52:36 +09:00
Tatsuhiro Tsujikawa
dbc613e0d0 Update man pages 2015-04-27 23:09:00 +09:00
Tatsuhiro Tsujikawa
ee354ee6c8 Bump up version number to 0.7.13, LT revision to 13:2:8 2015-04-27 23:06:14 +09:00
Tatsuhiro Tsujikawa
df707df21b Update man pages 2015-04-27 22:36:34 +09:00
Tatsuhiro Tsujikawa
2436acbd23 Update doc about h2load flow control 2015-04-27 22:36:03 +09:00
Tatsuhiro Tsujikawa
b41835f19b h2load: Effectively disable flow control by setting large window size
Previously h2load used default flow control window as described in
HTTP/2 and SPDY specification.  The window size is 64KiB, which is a
bit small, and cannot utilize full server performance when response
size is not too small.  Basically, we do this kind of benchmarking
test to measure server's throughput, and optimal performance.  Smaller
window certainly degrades performance even in local testing because
server is so fast that it has to wait for WINDOW_UPDATE from h2load.
To make default behaviour suitable for peak performance test, we
decided to disable flow control in h2load by setting large enough
window size.

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

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

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

https://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
2015-04-03 11:55:57 +02:00
Tatsuhiro Tsujikawa
524a1f9498 Update sphinx_rtd_theme 2015-04-01 23:11:07 +09:00
Tatsuhiro Tsujikawa
28cfae162a Update doc 2015-04-01 23:10:01 +09:00
Tatsuhiro Tsujikawa
b0123448a4 python: Add async body generation support 2015-04-01 22:54:31 +09:00
Tatsuhiro Tsujikawa
2d15dca096 Merge branch 'alagoutte-scan-build' 2015-04-01 22:53:56 +09:00
Alexis La Goutte
5f05135d1b Fix some "Value stored to 'stream' is never read" found by Clang Analyzer 2015-04-01 13:03:22 +02:00
Alexis La Goutte
3b6b4ff066 Fix Value stored to 'rv' is never read found by Clang Analyzer 2015-04-01 13:03:22 +02:00
Tatsuhiro Tsujikawa
0c8ec7bfa6 Make sure that nghttp2 license is MIT license 2015-04-01 19:41:32 +09:00
Tatsuhiro Tsujikawa
2c05b8d6f0 Update doc 2015-04-01 01:26:21 +09:00
Tatsuhiro Tsujikawa
45c4187d8f doc: Update .gitignore 2015-04-01 01:19:08 +09:00
Tatsuhiro Tsujikawa
87029e05af doc: Split API reference into smaller fine grained files
Previously API reference is gigantic one rst file and it is a bit hard
to use, especially when browsing similar functions.  This commit
splits API reference into smaller fine grained files.  The macros,
enums, types are now in its own file.  Each API function has its own
file now.  API reference doc is now index to above documentation
files.  The apiref-header.rst is renamed as programmers-guide.rst and
becomes standalone document.
2015-04-01 01:13:10 +09:00
Tatsuhiro Tsujikawa
363914c3f7 Mention OCSP stapling in doc 2015-03-31 23:31:24 +09:00
Tatsuhiro Tsujikawa
1316065c14 python: Fix pseudo-header field ordering bug 2015-03-31 21:53:13 +09:00
Tatsuhiro Tsujikawa
2b6a181bef Dockerfile.android: Update openssl to 1.0.2a 2015-03-31 21:36:53 +09:00
Tatsuhiro Tsujikawa
bf68df9ef4 Merge branch 'wzyboy-patch-dockerfile' 2015-03-31 21:35:32 +09:00
Tatsuhiro Tsujikawa
e7f6089b0e Merge branch 'patch-dockerfile' of https://github.com/wzyboy/nghttp2 into wzyboy-patch-dockerfile 2015-03-31 21:35:10 +09:00
Tatsuhiro Tsujikawa
a1500b0ee3 rst document specific corrections 2015-03-31 21:32:25 +09:00
Tatsuhiro Tsujikawa
14001052f8 Merge branch 'fangdingjun-master' 2015-03-31 21:27:18 +09:00
Tatsuhiro Tsujikawa
95ab54c79d Merge branch 'master' of https://github.com/fangdingjun/nghttp2 into fangdingjun-master 2015-03-31 21:26:46 +09:00
Zhuoyun Wei
5e84f767f0 Improve Dockerfile
- Tell Vim this is a Dockerfile to enable syntax highlight;
- Explicity use Ubuntu "Trusty";
- Remove downloaded file to save space;
- Chain up some RUN commands to generate fewer layers.
2015-03-31 14:21:56 +08:00
Dingjun
c47855085b Update README.rst
fix the typo and add the missing command in sample command
2015-03-31 10:02:22 +08:00
Tatsuhiro Tsujikawa
1442b1bd0a nghttpx: Remove --tls-ctx-per-worker option
--tls-ctx-per-worker option does not work well of OCSP stapling.  Also
it makes session ID useless.
2015-03-31 00:42:21 +09:00
Tatsuhiro Tsujikawa
763293a050 Update man pages 2015-03-31 00:23:12 +09:00
Tatsuhiro Tsujikawa
cc94632b29 src: Use separator "--" to mark start of the footer without ambiguity 2015-03-31 00:21:52 +09:00
Tatsuhiro Tsujikawa
5df770b9c1 h2load: Fix compile error with Android NDK 2015-03-30 23:59:03 +09:00
Tatsuhiro Tsujikawa
4bc9afe20a nghttpx: Add OCSP stapling feature 2015-03-30 23:58:28 +09:00
Dingjun
522faeb24f Update README.rst 2015-03-30 18:39:07 +08:00
fangdingjun
362ff09183 add build notes for windows user under Mingw and Cygwin 2015-03-30 18:29:10 +08:00
Tatsuhiro Tsujikawa
ccea4d42b5 Refactor .gitignore files 2015-03-29 18:40:37 +09:00
Tatsuhiro Tsujikawa
ebbe065716 Update .gitignore 2015-03-29 18:23:55 +09:00
Tatsuhiro Tsujikawa
3a97f21383 Reorder fields 2015-03-29 18:10:38 +09:00
Tatsuhiro Tsujikawa
12ced1cddc nghttpx: Add flag to track connection state in HTTP/1 backend 2015-03-29 01:47:22 +09:00
Tatsuhiro Tsujikawa
3576f20e5a nghttpx: Revert part of 6f58434d89
The reverted part of the change may use not connected socket in HTTP/1
backend.
2015-03-29 01:32:27 +09:00
Tatsuhiro Tsujikawa
7ae6e6b4c5 Exclude num_idle_streams when counting active stream 2015-03-29 00:59:15 +09:00
Tatsuhiro Tsujikawa
a2486daee1 nghttpd: Rename Http2Handler::on_connect as connection_made 2015-03-28 20:21:12 +09:00
Tatsuhiro Tsujikawa
8bf440b89c nghttpx: Rename Http2Session::on_connect as connection_made 2015-03-28 20:19:17 +09:00
Tatsuhiro Tsujikawa
e9cdb9c896 h2load: Remove unused fields in Client class 2015-03-28 20:17:30 +09:00
Tatsuhiro Tsujikawa
c4804ee50b h2load: Remove Client::noop 2015-03-28 20:14:12 +09:00
Tatsuhiro Tsujikawa
95cb284e27 h2load: Rename Client::on_connect as connection_made 2015-03-28 20:13:37 +09:00
Tatsuhiro Tsujikawa
c4ccc376df nghttp: Refactor function names
on_SOMETHING should be used only for I/O callback functions
2015-03-28 20:07:12 +09:00
Tatsuhiro Tsujikawa
6133110386 Remove dependency on libws2_32 on Windows build 2015-03-28 19:58:44 +09:00
Tatsuhiro Tsujikawa
6f58434d89 nghttpx, h2load: Perform write whenever read succeeds 2015-03-28 19:13:14 +09:00
Tatsuhiro Tsujikawa
3fd5d0af79 Don't consider num_active_streams in nghttp2_session_want_write() 2015-03-28 19:00:24 +09:00
Tatsuhiro Tsujikawa
1a6855ea7d Merge branch 'remoe-fix/win_build' 2015-03-28 18:41:03 +09:00
remoe
0312521ac9 - source file list updated
- zlib removed
- build of .def files removed
2015-03-27 21:54:44 +01:00
Tatsuhiro Tsujikawa
67b0e0c2d6 Fix "redefine WIN32" bug 2015-03-28 02:16:37 +09:00
Tatsuhiro Tsujikawa
966e3a1308 Define NGHTTP2_EXTERN macro to export function for Windows build 2015-03-28 01:58:59 +09:00
Tatsuhiro Tsujikawa
fd8f8e2708 Bump up version number to 0.7.10-DEV 2015-03-27 01:06:42 +09:00
Tatsuhiro Tsujikawa
d7fdcbb3d6 Update man pages 2015-03-27 00:37:12 +09:00
Tatsuhiro Tsujikawa
de2c2ad65c src: Update hexdump usage output so that help2rst.py can produce good output 2015-03-27 00:36:19 +09:00
Tatsuhiro Tsujikawa
862a0ee66b Bump up version number to 0.7.9, LT revision to 12:2:7 2015-03-27 00:27:49 +09:00
Tatsuhiro Tsujikawa
c2510a01a5 examples: Place AM_CPPFLAGS first to use in-package header files first
Fixes GH-192
2015-03-26 23:09:39 +09:00
Tatsuhiro Tsujikawa
dc85623060 nghttpx: Fix PUSH_PROMISE header field corruption
Fixes GH-194
2015-03-26 22:52:51 +09:00
Tatsuhiro Tsujikawa
8afbb6ca26 h2load: Fix crash if -t > -c 2015-03-26 19:57:37 +09:00
Tatsuhiro Tsujikawa
ed79637737 h2load: Add -d option to upload data to server 2015-03-26 19:53:42 +09:00
Tatsuhiro Tsujikawa
faa2c4467a Merge branch 'wzyboy-patch-1' 2015-03-25 23:26:20 +09:00
Zhuoyun Wei
c87fae463e Fix comments, too 2015-03-25 21:04:49 +08:00
Zhuoyun Wei
29b4b11e78 Change --spdy-proxy to --http2-proxy 2015-03-25 20:42:12 +08:00
Tatsuhiro Tsujikawa
3b24be3bcd src: Fix compile error with clang-3.6 2015-03-25 01:27:18 +09:00
Tatsuhiro Tsujikawa
ece8289aaf nghttpx: Forward only "trailers" keyword in te when forwarding HTTP/2 backend 2015-03-25 01:20:41 +09:00
Tatsuhiro Tsujikawa
4042ff0fc4 nghttpx: Fix te header field is duplicated when forwarding HTTP/2 backend 2015-03-25 01:17:06 +09:00
Tatsuhiro Tsujikawa
d3d6c5e314 Fix bug that inflater->nvbufs is not reset 2015-03-24 21:54:05 +09:00
Tatsuhiro Tsujikawa
125e32eb56 src: Refactor a bit 2015-03-24 21:45:59 +09:00
Tatsuhiro Tsujikawa
94bf8dcd4e src: Refactor util::hexdump 2015-03-24 21:43:28 +09:00
Tatsuhiro Tsujikawa
89b8039466 nghttp, nghttpd: Add --hexdump option to hexdump incoming traffic
The output format is similar to `hexdump -C`
2015-03-24 02:30:51 +09:00
Tatsuhiro Tsujikawa
72843b33d0 Bump up version number to 0.7.9-DEV 2015-03-24 00:14:56 +09:00
Tatsuhiro Tsujikawa
03e699e013 Update man pages 2015-03-24 00:04:07 +09:00
Tatsuhiro Tsujikawa
fcf99fa8fc Bump up version number to 0.7.8, LT revision to 12:1:7 2015-03-24 00:00:22 +09:00
Tatsuhiro Tsujikawa
661fb2eb0e NULL-terminate name and value in nghttp2_nv
Guaranteeing NULL-termination is very useful when name or value are
used with C functions which requires NULL-terminated string.
2015-03-23 23:25:57 +09:00
Tatsuhiro Tsujikawa
42496d638b Merge branch 'Lekensteyn-documentation' 2015-03-22 17:03:31 +09:00
Peter Wu
c0a6a0a6d1 README.rst: OpenSSL 1.0.2 has already been released
OpenSSL 1.0.2 is already released. Avoid the confusing wording that
seems to suggest that a development version of OpenSSL 1.0.2 provides
ALPN support.
2015-03-21 23:16:56 +01:00
Tatsuhiro Tsujikawa
b7bda783c5 Update doc 2015-03-21 23:09:17 +09:00
Tatsuhiro Tsujikawa
6893608ae2 Use literal instead of computed value in token lookup 2015-03-21 23:03:37 +09:00
Tatsuhiro Tsujikawa
ef913bc929 Validate :path header field
For "http" or "https" URIs, :path header field must start with "/".
The only exception is OPTIONS method, which can contain "*" to
represent system-wide OPTIONS request.
2015-03-21 23:03:37 +09:00
Tatsuhiro Tsujikawa
a5ed70bcfe Merge branch 'rasa-patch-1' 2015-03-21 19:47:27 +09:00
Tatsuhiro Tsujikawa
9bf2ca6916 Merge branch 'patch-1' of https://github.com/rasa/nghttp2 into rasa-patch-1 2015-03-21 19:46:22 +09:00
Ross Smith II
57729d0a23 Removed errant markdown 2015-03-20 08:37:06 -07:00
Tatsuhiro Tsujikawa
e86b81ec10 Merge branch 'icing-h2load-reserver-fix' 2015-03-20 23:32:43 +09:00
mod-h2-dev
076eefbed6 fix for segfault by reserving correct worker count 2015-03-16 17:42:22 +02:00
Ross Smith II
58a735dc68 Update README.rst 2015-03-15 23:42:19 -07:00
Tatsuhiro Tsujikawa
948d4d43d5 Bump up version number to 0.7.8-DEV 2015-03-14 18:53:43 +09:00
Tatsuhiro Tsujikawa
ef581e94bb Update man pages 2015-03-14 18:52:50 +09:00
Tatsuhiro Tsujikawa
ad84af2b2b Bump up version number to 0.7.7 2015-03-14 18:50:12 +09:00
Tatsuhiro Tsujikawa
0e65e1254d Bump up version number to 0.7.7-DEV 2015-03-14 18:36:18 +09:00
171 changed files with 6876 additions and 2886 deletions

50
.gitignore vendored
View File

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

View File

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

18
CONTRIBUTION Normal file
View File

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

19
COPYING
View File

@@ -20,22 +20,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[The text below was composed based on 1.2. License section of
curl/libcurl project.]
When contributing with code, you agree to put your changes and new
code under the same license nghttp2 is already using unless stated and
agreed otherwise.
When changing existing source code, you do not alter the copyright of
the original file(s). The copyright will still be owned by the
original creator(s) or those who have been assigned copyright by the
original author(s).
By submitting a patch to the nghttp2 project, you are assumed to have
the right to the code and to be allowed by your employer or whatever
to hand over that patch/code to us. We will credit you for your
changes as far as possible, to give credit but also to keep a trace
back to who made what changes. Please always provide us with your
full real name when contributing!

View File

@@ -1,3 +1,4 @@
# vim: ft=dockerfile:
# Dockerfile to build nghttp2 android binary
#
# $ sudo docker build -t nghttp2-android - < Dockerfile.android
@@ -9,7 +10,7 @@
#
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
FROM ubuntu
FROM ubuntu:trusty
MAINTAINER Tatsuhiro Tsujikawa
@@ -29,9 +30,10 @@ RUN apt-get install -y make binutils autoconf automake autotools-dev libtool \
genisoimage libc6-i386 lib32stdc++6
WORKDIR /root/build
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin
RUN chmod a+x android-ndk-r10c-linux-x86_64.bin
RUN ./android-ndk-r10c-linux-x86_64.bin
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin && \
chmod a+x android-ndk-r10c-linux-x86_64.bin && \
./android-ndk-r10c-linux-x86_64.bin && \
rm android-ndk-r10c-linux-x86_64.bin
WORKDIR /root/build/android-ndk-r10c
RUN /bin/bash build/tools/make-standalone-toolchain.sh \
@@ -57,20 +59,24 @@ RUN autoreconf -i && \
make install
WORKDIR /root/build
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.1j.tar.gz
RUN tar xf openssl-1.0.1j.tar.gz
WORKDIR /root/build/openssl-1.0.1j
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.2a.tar.gz && \
tar xf openssl-1.0.2a.tar.gz && \
rm openssl-1.0.2a.tar.gz
WORKDIR /root/build/openssl-1.0.2a
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
./Configure --prefix=$PREFIX android && \
make && make install_sw
WORKDIR /root/build
RUN curl -L -O http://dist.schmorp.de/libev/libev-4.19.tar.gz
RUN curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch
RUN tar xf libev-4.19.tar.gz
RUN curl -L -O http://dist.schmorp.de/libev/libev-4.19.tar.gz && \
curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch && \
tar xf libev-4.19.tar.gz && \
rm libev-4.19.tar.gz
WORKDIR /root/build/libev-4.19
RUN patch -p1 < ../libev-4.19-android.patch
RUN ./configure \
RUN patch -p1 < ../libev-4.19-android.patch && \
./configure \
--host=arm-linux-androideabi \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--prefix=$PREFIX \
@@ -95,9 +101,9 @@ RUN autoreconf -i && \
--disable-threads \
LIBSPDYLAY_CFLAGS=-I$PREFIX/usr/local/include \
LIBSPDYLAY_LIBS="-L$PREFIX/usr/local/lib -lspdylay" \
CPPFLAGS="-I$PREFIX/include" \
CPPFLAGS="-fPIE -I$PREFIX/include" \
CXXFLAGS="-fno-strict-aliasing" \
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-L$PREFIX/lib" && \
LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
make && \
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp

View File

@@ -1,30 +1,30 @@
nghttp2 - HTTP/2 C Library
==========================
This is an implementation of Hypertext Transfer Protocol version 2
This is an implementation of the Hypertext Transfer Protocol version 2
in 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. We have also developed load test and benchmarking tool for
The framing layer of HTTP/2 is implemented as a reusable C
library. On top of that, we have implemented an HTTP/2 client, server
and proxy. We have also developed load test and benchmarking tools for
HTTP/2 and SPDY.
HPACK encoder and decoder are available as public API.
An HPACK encoder and decoder are available as a public API.
The experimental high level C++ library is also available.
An experimental high level C++ library is also available.
We have Python binding of this libary, but we have not covered
everything yet.
We have Python bindings of this libary, but we do not have full
code coverage yet.
Development Status
------------------
We started to implement h2-14
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), the header
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), and header
compression
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09).
The nghttp2 code base was forked from spdylay project.
The nghttp2 code base was forked from the spdylay project.
=========================== =======
HTTP/2 Features Support
@@ -37,7 +37,7 @@ Large header (CONTINUATION) Yes
Public Test Server
------------------
The following endpoints are available to try out nghttp2
The following endpoints are available to try out our nghttp2
implementation.
* https://nghttp2.org/ (TLS + ALPN/NPN)
@@ -67,16 +67,16 @@ To build the documentation, you need to install:
* sphinx (http://sphinx-doc.org/)
To build and run the application programs (``nghttp``, ``nghttpd`` and
``nghttpx``) in ``src`` directory, the following packages are
``nghttpx``) in the ``src`` directory, the following packages are
required:
* OpenSSL >= 1.0.1
* libev >= 4.15
* zlib >= 1.2.3
ALPN support requires unreleased version OpenSSL >= 1.0.2.
ALPN support requires OpenSSL >= 1.0.2 (released 22 January 2015).
To enable SPDY protocol in the application program ``nghttpx`` and
To enable the SPDY protocol in the application program ``nghttpx`` and
``h2load``, the following package is required:
* spdylay >= 1.3.0
@@ -90,7 +90,7 @@ The HPACK tools require the following package:
* jansson >= 2.5
To build sources under examples directory, libevent is required:
To build sources under the examples directory, libevent is required:
* libevent-openssl >= 2.0.8
@@ -109,16 +109,17 @@ The Python bindings require the following packages:
* cython >= 0.19
* python >= 2.7
If you are using Ubuntu 14.04 LTS, you need the following packages
installed::
If you are using Ubuntu 14.04 LTS (trusty), run the following to install the needed packages::
apt-get install make binutils autoconf automake autotools-dev libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev libjemalloc-dev cython python3.4-dev
sudo apt-get install make binutils autoconf automake autotools-dev libtool pkg-config \
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \
libjemalloc-dev cython python3.4-dev
spdylay is not packaged in Ubuntu, so you need to build it yourself:
http://tatsuhiro-t.github.io/spdylay/
Build from git
--------------
Building from git
-----------------
Building from git is easy, but please be sure that at least autoconf 2.68 is
used::
@@ -129,23 +130,50 @@ used::
$ ./configure
$ make
To compile source code, gcc >= 4.8.3 or clang >= 3.4 is required.
To compile the source code, gcc >= 4.8.3 or clang >= 3.4 is required.
.. note::
Mac OS X users may need ``--disable-threads`` configure option to
disable multi threading in nghttpd, nghttpx and h2load to prevent
them from crashing. Patch is welcome to make multi threading work
Mac OS X users may need the ``--disable-threads`` configure option to
disable multi-threading in nghttpd, nghttpx and h2load to prevent
them from crashing. A patch is welcome to make multi threading work
on Mac OS X platform.
Building documentation
----------------------
Notes for building on Windows (Mingw/Cygwin)
--------------------------------------------
Under Mingw environment, you can only compile the library, it's
``libnghttp2-X.dll`` and ``libnghttp2.a``.
If you want to compile the applications(``h2load``, ``nghttp``,
``nghttpx``, ``nghttpd``), you need to use the Cygwin environment.
Under Cygwin environment, to compile the applications you need to
compile and install the libev first.
Secondly, you need to undefine the macro ``__STRICT_ANSI__``, if you
not, the functions ``fdopen``, ``fileno`` and ``strptime`` will not
available.
the sample command like this::
$ export CFLAGS="-U__STRICT_ANSI__ -I$libev_PREFIX/include -L$libev_PREFIX/lib"
$ export CXXFLAGS=$CFLAGS
$ ./configure
$ make
If you want to compile the applications under ``examples/``, you need
to remove or rename the ``event.h`` from libev's installation, because
it conflicts with libevent's installation.
Building the documentation
--------------------------
.. note::
Documentation is still incomplete.
To build documentation, run::
To build the documentation, run::
$ make html
@@ -159,13 +187,13 @@ https://nghttp2.org/documentation/
Unit tests
----------
Unit tests are done by simply running `make check`.
Unit tests are done by simply running ``make check``.
Integration tests
-----------------
We have the integration tests for nghttpx proxy server. The tests are
written in `Go programming language <http://golang.org/>`_ and uses
We have the integration tests for the nghttpx proxy server. The tests are
written in the `Go programming language <http://golang.org/>`_ and uses
its testing framework. We depend on the following libraries:
* https://github.com/bradfitz/http2
@@ -182,12 +210,12 @@ To run the tests, run the following command under
$ make it
Inside the tests, we use port 3009 to run test subject server.
Inside the tests, we use port 3009 to run the test subject server.
Client, Server and Proxy programs
---------------------------------
The src directory contains HTTP/2 client, server and proxy programs.
The ``src`` directory contains the HTTP/2 client, server and proxy programs.
nghttp - client
+++++++++++++++
@@ -334,7 +362,7 @@ The HTTP Upgrade is performed like this::
[ 0.038] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
With ``-s`` option, ``nghttp`` prints out some timing information for
Using the ``-s`` option, ``nghttp`` prints out some timing information for
requests, sorted by completion time::
$ nghttp -nas https://nghttp2.org/
@@ -360,8 +388,8 @@ requests, sorted by completion time::
+76.14ms +11.17ms 64.97ms 200 171K /images/posts/with-pri-blog.png
+88.52ms +11.17ms 77.36ms 200 174K /images/posts/without-pri-blog.png
With ``-r`` option, ``nghttp`` writes more detailed timing data to
given file in HAR format.
Using the ``-r`` option, ``nghttp`` writes more detailed timing data to
the given file in HAR format.
nghttpd - server
++++++++++++++++
@@ -371,13 +399,13 @@ nghttpd - server
By default, it uses SSL/TLS connection. Use ``--no-tls`` option to
disable it.
``nghttpd`` only accepts the HTTP/2 connection via NPN/ALPN or direct
HTTP/2 connection. No HTTP Upgrade is supported.
``nghttpd`` only accepts HTTP/2 connections via NPN/ALPN or direct
HTTP/2 connections. No HTTP Upgrade is supported.
``-p`` option allows users to configure server push.
The ``-p`` option allows users to configure server push.
Just like ``nghttp``, it has verbose output mode for framing
information. Here is sample output from ``nghttpd`` server::
Just like ``nghttp``, it has a verbose output mode for framing
information. Here is sample output from ``nghttpd``::
$ nghttpd --no-tls -v 8080
IPv4: listen on port 8080
@@ -431,8 +459,15 @@ nghttpx - proxy
+++++++++++++++
``nghttpx`` is a multi-threaded reverse proxy for ``h2-14``, SPDY and
HTTP/1.1 and powers nghttp2.org site and supports HTTP/2 server push.
It has several operation modes:
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server push.
``nghttpx`` implements `important performance-oriented features
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
session IDs, session tickets (with automatic key rotation), OCSP
stapling, dynamic record sizing, ALPN/NPN, forward secrecy and SPDY &
HTTP/2.
``nghttpx`` has several operational modes:
================== ============================ ============== =============
Mode option Frontend Backend Note
@@ -446,19 +481,19 @@ default mode HTTP/2, SPDY, HTTP/1.1 (TLS) HTTP/1.1 Reverse proxy
The interesting mode at the moment is the default mode. It works like
a reverse proxy and listens for ``h2-14``, SPDY and HTTP/1.1 and can
be deployed SSL/TLS terminator for existing web server.
be deployed as a SSL/TLS terminator for existing web server.
The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
SSL/TLS in the frontend connection by default. To disable SSL/TLS,
use ``--frontend-no-tls`` option. If that option is used, SPDY is
disabled in the frontend and incoming HTTP/1.1 connection can be
use the ``--frontend-no-tls`` option. If that option is used, SPDY is
disabled in the frontend and incoming HTTP/1.1 connections can be
upgraded to HTTP/2 through HTTP Upgrade.
The ``--http2-bridge``, ``--client`` and ``--client-proxy`` modes use
SSL/TLS in the backend connection by deafult. To disable SSL/TLS, use
``--backend-no-tls`` option.
the ``--backend-no-tls`` option.
``nghttpx`` supports configuration file. See ``--conf`` option and
``nghttpx`` supports a configuration file. See the ``--conf`` option and
sample configuration file ``nghttpx.conf.sample``.
In the default mode, (without any of ``--http2-proxy``,
@@ -468,18 +503,18 @@ In the default mode, (without any of ``--http2-proxy``,
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Web Server
[reverse proxy]
With ``--http2-proxy`` option, it works as so called secure proxy (aka
With the ``--http2-proxy`` option, it works as a so called secure proxy (aka
SPDY proxy)::
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
[secure proxy] (e.g., Squid, ATS)
The ``Client`` in the above needs to be configured to use
The ``Client`` in the above example needs to be configured to use
``nghttpx`` as secure proxy.
At the time of this writing, Chrome is the only browser which supports
secure proxy. The one way to configure Chrome to use secure proxy is
create proxy.pac script like this:
secure proxy. One way to configure Chrome to use a secure proxy is
to create a proxy.pac script like this:
.. code-block:: javascript
@@ -488,7 +523,7 @@ create proxy.pac script like this:
}
``SERVERADDR`` and ``PORT`` is the hostname/address and port of the
machine nghttpx is running. Please note that Chrome requires valid
machine nghttpx is running on. Please note that Chrome requires a valid
certificate for secure proxy.
Then run Chrome with the following arguments::
@@ -496,24 +531,24 @@ Then run Chrome with the following arguments::
$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
With ``--http2-bridge``, it accepts HTTP/2, SPDY and HTTP/1.1
connections and communicates with backend in HTTP/2::
connections and communicates with the backend in HTTP/2::
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> Web or HTTP/2 Proxy etc
(e.g., nghttpx -s)
With ``--client-proxy`` option, it works as forward proxy and expects
that the backend is HTTP/2 proxy::
With ``--client-proxy``, it works as a forward proxy and expects
that the backend is an HTTP/2 proxy::
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> HTTP/2 Proxy
[forward proxy] (e.g., nghttpx -s)
The ``Client`` needs to be configured to use nghttpx as forward
The ``Client`` needs to be configured to use nghttpx as a forward
proxy. The frontend HTTP/1.1 connection can be upgraded to HTTP/2
through HTTP Upgrade. With the above configuration, one can use
HTTP/1.1 client to access and test their HTTP/2 servers.
With ``--client`` option, it works as reverse proxy and expects that
the backend is HTTP/2 Web server::
With ``--client``, it works as a reverse proxy and expects that
the backend is an HTTP/2 Web server::
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> Web Server
[reverse proxy]
@@ -522,11 +557,11 @@ The frontend HTTP/1.1 connection can be upgraded to HTTP/2
through HTTP Upgrade.
For the operation modes which talk to the backend in HTTP/2 over
SSL/TLS, the backend connections can be tunneled through HTTP proxy.
The proxy is specified using ``--backend-http-proxy-uri`` option. The
following figure illustrates the example of ``--http2-bridge`` and
SSL/TLS, the backend connections can be tunneled through an HTTP proxy.
The proxy is specified using ``--backend-http-proxy-uri``. The
following figure illustrates the example of the ``--http2-bridge`` and
``--backend-http-proxy-uri`` options to talk to the outside HTTP/2
proxy through HTTP proxy::
proxy through an HTTP proxy::
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
@@ -537,7 +572,7 @@ Benchmarking tool
-----------------
The ``h2load`` program is a benchmarking tool for HTTP/2 and SPDY.
The SPDY support is enabled if the program was built with spdylay
The SPDY support is enabled if the program was built with the spdylay
library. The UI of ``h2load`` is heavily inspired by ``weighttp``
(https://github.com/lighttpd/weighttp). The typical usage is as
follows::
@@ -565,38 +600,38 @@ follows::
min max mean sd +/- sd
time for request: 283.86ms 1.46s 659.70ms 150.87ms 84.68%
The above example issued total 100000 requests, using 100 concurrent
clients (in other words, 100 HTTP/2 sessions), and maximum 100 streams
per client. With ``-t`` option, ``h2load`` will use multiple native
threads to avoid saturating single core on client side.
The above example issued total 100,000 requests, using 100 concurrent
clients (in other words, 100 HTTP/2 sessions), and a maximum of 100 streams
per client. With the ``-t`` option, ``h2load`` will use multiple native
threads to avoid saturating a single core on client side.
.. warning::
**Don't use this tool against publicly available servers.** That is
considered a DOS attack. Please only use against your private
considered a DOS attack. Please only use it against your private
servers.
HPACK tools
-----------
The ``src`` directory contains HPACK tools. The ``deflatehd`` is a
command-line header compression tool. The ``inflatehd`` is
The ``src`` directory contains the HPACK tools. The ``deflatehd`` program is a
command-line header compression tool. The ``inflatehd`` program is a
command-line header decompression tool. Both tools read input from
stdin and write output to stdout. The errors are written to stderr.
They take JSON as input and output. We use (mostly) same JSON data
format described at https://github.com/http2jp/hpack-test-case
stdin and write output to stdout. Errors are written to stderr.
They take JSON as input and output. We (mostly) use the same JSON data
format described at https://github.com/http2jp/hpack-test-case.
deflatehd - header compressor
+++++++++++++++++++++++++++++
The ``deflatehd`` reads JSON data or HTTP/1-style header fields from
The ``deflatehd`` program reads JSON data or HTTP/1-style header fields from
stdin and outputs compressed header block in JSON.
For the JSON input, the root JSON object must include ``cases`` key.
For the JSON input, the root JSON object must include a ``cases`` key.
Its value has to include the sequence of input header set. They share
the same compression context and are processed in the order they
appear. Each item in the sequence is a JSON object and it must
include ``headers`` key. Its value is an array of a JSON object,
include a ``headers`` key. Its value is an array of JSON objects,
which includes exactly one name/value pair.
Example:
@@ -622,8 +657,8 @@ Example:
}
With ``-t`` option, the program can accept more familiar HTTP/1 style
header field block. Each header set is delimited by empty line:
With the ``-t`` option, the program can accept more familiar HTTP/1 style
header field blocks. Each header set is delimited by an empty line:
Example::
@@ -634,29 +669,29 @@ Example::
:method: POST
user-agent: nghttp2
The output is JSON object. It should include ``cases`` key and its
value is an array of JSON object, which has at least following keys:
The output is in JSON object. It should include a ``cases`` key and its
value is an array of JSON objects, which has at least the following keys:
seq
The index of header set in the input.
input_length
The sum of length of name/value pair in the input.
The sum of the length of the name/value pairs in the input.
output_length
The length of compressed header block.
The length of the compressed header block.
percentage_of_original_size
``input_length`` / ``output_length`` * 100
wire
The compressed header block in hex string.
The compressed header block as a hex string.
headers
The input header set.
header_table_size
The header table size adjusted before deflating header set.
The header table size adjusted before deflating the header set.
Examples:
@@ -723,7 +758,7 @@ Examples:
The output can be used as the input for ``inflatehd`` and
``deflatehd``.
With ``-d`` option, the extra ``header_table`` key is added and its
With the ``-d`` option, the extra ``header_table`` key is added and its
associated value includes the state of dynamic header table after the
corresponding header set was processed. The value includes at least
the following keys:
@@ -747,8 +782,8 @@ deflate_size
``max_deflate_size``.
max_deflate_size
The maximum header table size encoder uses. This can be smaller
than ``max_size``. In this case, encoder only uses up to first
The maximum header table size the encoder uses. This can be smaller
than ``max_size``. In this case, the encoder only uses up to first
``max_deflate_size`` buffer. Since the header table size is still
``max_size``, the encoder has to keep track of entries ouside the
``max_deflate_size`` but inside the ``max_size`` and make sure
@@ -911,14 +946,14 @@ Example:
inflatehd - header decompressor
+++++++++++++++++++++++++++++++
The ``inflatehd`` reads JSON data from stdin and outputs decompressed
The ``inflatehd`` program reads JSON data from stdin and outputs decompressed
name/value pairs in JSON.
The root JSON object must include ``cases`` key. Its value has to
include the sequence of compressed header block. They share the same
The root JSON object must include the ``cases`` key. Its value has to
include the sequence of compressed header blocks. They share the same
compression context and are processed in the order they appear. Each
item in the sequence is a JSON object and it must have at least
``wire`` key. Its value is a compressed header block in hex string.
item in the sequence is a JSON object and it must have at least a
``wire`` key. Its value is a compressed header block as a hex string.
Example:
@@ -932,17 +967,17 @@ Example:
]
}
The output is JSON object. It should include ``cases`` key and its
value is an array of JSON object, which has at least following keys:
The output is a JSON object. It should include a ``cases`` key and its
value is an array of JSON objects, which has at least following keys:
seq
The index of header set in the input.
The index of the header set in the input.
headers
The JSON array includes decompressed name/value pairs.
A JSON array that includes decompressed name/value pairs.
wire
The compressed header block in hex string.
The compressed header block as a hex string.
header_table_size
The header table size adjusted before inflating compressed header
@@ -1006,8 +1041,8 @@ Example:
The output can be used as the input for ``deflatehd`` and
``inflatehd``.
With ``-d`` option, the extra ``header_table`` key is added and its
associated value includes the state of dynamic header table after the
With the ``-d`` option, the extra ``header_table`` key is added and its
associated value includes the state of the dynamic header table after the
corresponding header set was processed. The format is the same as
``deflatehd``.
@@ -1016,10 +1051,10 @@ 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 client and server API.
on the Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
provides both client and server APIs.
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
libnghttp2_asio is not built by default. Use the ``--enable-asio-lib``
configure flag to build libnghttp2_asio. The required Boost libraries
are:
@@ -1027,9 +1062,9 @@ are:
* 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:
The server API is designed to build an HTTP/2 server very easily to utilize
C++11 anonymous functions and closures. The bare minimum example of
an HTTP/2 server looks like this:
.. code-block:: cpp
@@ -1052,7 +1087,7 @@ HTTP/2 server looks like this:
}
}
Here is the sample code for client API use:
Here is sample code to use the client API:
.. code-block:: cpp
@@ -1109,19 +1144,19 @@ For more details, see the documentation of libnghttp2_asio.
Python bindings
---------------
This ``python`` directory contains nghttp2 Python bindings. The
The ``python`` directory contains nghttp2 Python bindings. The
bindings currently provide HPACK compressor and decompressor classes
and HTTP/2 server.
and an HTTP/2 server.
The extension module is called ``nghttp2``.
``make`` will build the bindings and target Python version is
determined by configure script. If the detected Python version is not
what you expect, specify a path to Python executable in ``PYTHON``
determined by the ``configure`` script. If the detected Python version is not
what you expect, specify a path to Python executable in a ``PYTHON``
variable as an argument to configure script (e.g., ``./configure
PYTHON=/usr/bin/python3.4``).
The following example code illustrates basic usage of HPACK compressor
The following example code illustrates basic usage of the HPACK compressor
and decompressor in Python:
.. code-block:: python
@@ -1148,21 +1183,21 @@ By default, it does nothing. It must be subclassed to handle each
event callback method.
The first callback method invoked is ``on_headers()``. It is called
when HEADERS frame, which includes request header fields, has arrived.
when HEADERS frame, which includes the request header fields, has arrived.
If request has request body, ``on_data(data)`` is invoked for each
If the request has a request body, ``on_data(data)`` is invoked for each
chunk of received data.
When whole request is received, ``on_request_done()`` is invoked.
Once the entire request is received, ``on_request_done()`` is invoked.
When stream is closed, ``on_close(error_code)`` is called.
When the stream is closed, ``on_close(error_code)`` is called.
The application can send response using ``send_response()`` method.
The application can send a response using ``send_response()`` method.
It can be used in ``on_headers()``, ``on_data()`` or
``on_request_done()``.
The application can push resource using ``push()`` method. It must be
used before ``send_response()`` call.
The application can push resources using the ``push()`` method. It must be
used before the ``send_response()`` call.
The following instance variables are available:
@@ -1232,14 +1267,15 @@ 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
When changing existing source code, 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
By submitting a patch to the nghttp2 project, you (or your employer, as
the case may be) agree to assign the copyright of your submission to us.
.. the above really needs to be reworded to pass legal muster.
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

@@ -42,6 +42,6 @@ PATH=$TOOLCHAIN/bin:$PATH
--enable-werror \
CC=clang \
CXX=clang++ \
CPPFLAGS="-I$PREFIX/include" \
CPPFLAGS="-fPIE -I$PREFIX/include" \
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-L$PREFIX/lib"
LDFLAGS="-fPIE -pie -L$PREFIX/lib"

View File

@@ -25,14 +25,14 @@ dnl Do not change user variables!
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
AC_PREREQ(2.61)
AC_INIT([nghttp2], [0.7.6], [t-tujikawa@users.sourceforge.net])
AC_INIT([nghttp2], [0.7.14], [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, 12)
AC_SUBST(LT_REVISION, 0)
AC_SUBST(LT_AGE, 7)
AC_SUBST(LT_CURRENT, 13)
AC_SUBST(LT_REVISION, 3)
AC_SUBST(LT_AGE, 8)
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
@@ -508,13 +508,6 @@ AC_CHECK_HEADERS([ \
unistd.h \
])
case "${host}" in
*mingw*)
# For ntohl, ntohs in Windows
AC_CHECK_HEADERS([winsock2.h])
;;
esac
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
@@ -564,13 +557,6 @@ AM_CONDITIONAL([ENABLE_TINY_NGHTTPD],
[ test "x${have_epoll}" = "xyes" &&
test "x${have_timerfd_create}" = "xyes"])
dnl Windows library for winsock2
case "${host}" in
*mingw*)
LIBS="$LIBS -lws2_32"
;;
esac
ac_save_CFLAGS=$CFLAGS
CFLAGS=

2
contrib/.gitignore vendored
View File

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

View File

@@ -21,19 +21,24 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
EXTRA_DIST = nghttpx-init.in nghttpx-logrotate
configfiles = nghttpx-init nghttpx.service nghttpx-upstart.conf
EXTRA_DIST = $(configfiles:%=%.in) nghttpx-logrotate
edit = sed -e 's|@bindir[@]|$(bindir)|g'
nghttpx-init: Makefile
nghttpx-init: %: $(srcdir)/%.in
rm -f $@ $@.tmp
$(edit) $(srcdir)/$@.in > $@.tmp
$(edit) $< > $@.tmp
chmod +x $@.tmp
mv $@.tmp $@
nghttpx-init: $(srcdir)/nghttpx-init.in
nghttpx.service nghttpx-upstart.conf: %: $(srcdir)/%.in
$(edit) $< > $@
all-local: nghttpx-init
$(configfiles): Makefile
all-local: $(configfiles)
clean-local:
-rm -f nghttpx-init nghttpx-init.tmp
-rm -f nghttpx-init.tmp $(configfiles)

View File

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

View File

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

View File

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

23
doc/.gitignore vendored
View File

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

View File

@@ -23,10 +23,112 @@
man_MANS = nghttp.1 nghttpd.1 nghttpx.1 h2load.1
APIDOCS= \
apiref.rst \
macros.rst \
enums.rst \
types.rst \
nghttp2_check_header_name.rst \
nghttp2_check_header_value.rst \
nghttp2_hd_deflate_bound.rst \
nghttp2_hd_deflate_change_table_size.rst \
nghttp2_hd_deflate_del.rst \
nghttp2_hd_deflate_hd.rst \
nghttp2_hd_deflate_new.rst \
nghttp2_hd_deflate_new2.rst \
nghttp2_hd_inflate_change_table_size.rst \
nghttp2_hd_inflate_del.rst \
nghttp2_hd_inflate_end_headers.rst \
nghttp2_hd_inflate_hd.rst \
nghttp2_hd_inflate_new.rst \
nghttp2_hd_inflate_new2.rst \
nghttp2_is_fatal.rst \
nghttp2_nv_compare_name.rst \
nghttp2_option_del.rst \
nghttp2_option_new.rst \
nghttp2_option_set_no_auto_window_update.rst \
nghttp2_option_set_no_http_messaging.rst \
nghttp2_option_set_peer_max_concurrent_streams.rst \
nghttp2_option_set_recv_client_preface.rst \
nghttp2_pack_settings_payload.rst \
nghttp2_priority_spec_check_default.rst \
nghttp2_priority_spec_default_init.rst \
nghttp2_priority_spec_init.rst \
nghttp2_select_next_protocol.rst \
nghttp2_session_callbacks_del.rst \
nghttp2_session_callbacks_new.rst \
nghttp2_session_callbacks_set_before_frame_send_callback.rst \
nghttp2_session_callbacks_set_data_source_read_length_callback.rst \
nghttp2_session_callbacks_set_on_begin_frame_callback.rst \
nghttp2_session_callbacks_set_on_begin_headers_callback.rst \
nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst \
nghttp2_session_callbacks_set_on_frame_not_send_callback.rst \
nghttp2_session_callbacks_set_on_frame_recv_callback.rst \
nghttp2_session_callbacks_set_on_frame_send_callback.rst \
nghttp2_session_callbacks_set_on_header_callback.rst \
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback.rst \
nghttp2_session_callbacks_set_on_stream_close_callback.rst \
nghttp2_session_callbacks_set_recv_callback.rst \
nghttp2_session_callbacks_set_select_padding_callback.rst \
nghttp2_session_callbacks_set_send_callback.rst \
nghttp2_session_callbacks_set_send_data_callback.rst \
nghttp2_session_client_new.rst \
nghttp2_session_client_new2.rst \
nghttp2_session_client_new3.rst \
nghttp2_session_consume.rst \
nghttp2_session_consume_connection.rst \
nghttp2_session_consume_stream.rst \
nghttp2_session_del.rst \
nghttp2_session_get_effective_local_window_size.rst \
nghttp2_session_get_effective_recv_data_length.rst \
nghttp2_session_get_last_proc_stream_id.rst \
nghttp2_session_get_next_stream_id.rst \
nghttp2_session_get_outbound_queue_size.rst \
nghttp2_session_get_remote_settings.rst \
nghttp2_session_get_remote_window_size.rst \
nghttp2_session_get_stream_effective_local_window_size.rst \
nghttp2_session_get_stream_effective_recv_data_length.rst \
nghttp2_session_get_stream_local_close.rst \
nghttp2_session_get_stream_remote_close.rst \
nghttp2_session_get_stream_remote_window_size.rst \
nghttp2_session_get_stream_user_data.rst \
nghttp2_session_mem_recv.rst \
nghttp2_session_mem_send.rst \
nghttp2_session_recv.rst \
nghttp2_session_resume_data.rst \
nghttp2_session_send.rst \
nghttp2_session_server_new.rst \
nghttp2_session_server_new2.rst \
nghttp2_session_server_new3.rst \
nghttp2_session_set_next_stream_id.rst \
nghttp2_session_set_stream_user_data.rst \
nghttp2_session_terminate_session.rst \
nghttp2_session_terminate_session2.rst \
nghttp2_session_upgrade.rst \
nghttp2_session_want_read.rst \
nghttp2_session_want_write.rst \
nghttp2_strerror.rst \
nghttp2_submit_altsvc.rst \
nghttp2_submit_data.rst \
nghttp2_submit_goaway.rst \
nghttp2_submit_headers.rst \
nghttp2_submit_ping.rst \
nghttp2_submit_priority.rst \
nghttp2_submit_push_promise.rst \
nghttp2_submit_request.rst \
nghttp2_submit_response.rst \
nghttp2_submit_rst_stream.rst \
nghttp2_submit_settings.rst \
nghttp2_submit_shutdown_notice.rst \
nghttp2_submit_trailer.rst \
nghttp2_submit_window_update.rst \
nghttp2_version.rst
EXTRA_DIST = \
mkapiref.py \
README.rst \
apiref-header.rst \
programmers-guide.rst \
$(APIDOCS) \
nghttp.1.rst \
nghttpd.1.rst \
nghttpx.1.rst \
@@ -99,13 +201,30 @@ help:
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
apiref.rst: $(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
apiref.rst macros.rst enums.rst types.rst: \
$(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
--header $(top_srcdir)/doc/apiref-header.rst $^ > $@
$@ macros.rst enums.rst types.rst . $^
# Inspired by
# http://www.gnu.org/savannah-checkouts/gnu/automake/manual/html_node/Multiple-Outputs.html
apidoc.stamp: $(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
@rm -f apidoc.tmp
@touch apidoc.tmp
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
$@ macros.rst enums.rst types.rst . $^
@mv -f apidoc.tmp $@
$(APIDOC): apidoc.stamp
## Recover from the removal of $@
@if test -f $@; then :; else \
rm -f apidoc.stamp; \
$(MAKE) $(AM_MAKEFLAGS) apidoc.stamp; \
fi
clean-local:
-rm apiref.rst
-rm $(APIDOCS)
-rm -rf $(BUILDDIR)/*
html-local: apiref.rst

View File

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

View File

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

View File

@@ -2,10 +2,10 @@
{% if next or prev %}
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
{% if next %}
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}">Next <span class="fa fa-arrow-circle-right"></span></a>
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
{% endif %}
{% if prev %}
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}"><span class="fa fa-arrow-circle-left"></span> Previous</a>
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
{% endif %}
</div>
{% endif %}
@@ -28,6 +28,9 @@
</p>
</div>
{%- if show_sphinx %}
{% trans %}Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}.
{%- endif %}
</footer>

View File

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

View File

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@@ -8,7 +8,7 @@ _h2load()
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--threads --connection-window-bits --input-file --help --requests --verbose --version --window-bits --clients --no-tls-proto --header --max-concurrent-streams ' -- "$cur" ) )
COMPREPLY=( $( compgen -W '--threads --connection-window-bits --input-file --help --requests --data --verbose --version --window-bits --clients --no-tls-proto --header --max-concurrent-streams ' -- "$cur" ) )
;;
*)
_filedir

View File

@@ -8,7 +8,7 @@ _nghttp()
_get_comp_words_by_ref cur prev
case $cur in
-*)
COMPREPLY=( $( compgen -W '--verbose --no-dep --get-assets --har --header-table-size --multiply --padding --dep-idle --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --weight --help --key --null-out --window-bits --stat --header ' -- "$cur" ) )
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --padding --hexdump --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --trailer --weight --help --key --null-out --window-bits --stat --header ' -- "$cur" ) )
;;
*)
_filedir

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "H2LOAD" "1" "February 27, 2015" "0.7.5" "nghttp2"
.TH "H2LOAD" "1" "May 08, 2015" "0.7.14" "nghttp2"
.SH NAME
h2load \- HTTP/2 benchmarking tool
.
@@ -93,6 +93,8 @@ Default: \fBauto\fP
.B \-w, \-\-window\-bits=<N>
Sets the stream level initial window size to (2**<N>)\-1.
For SPDY, 2**<N> is used instead.
.sp
Default: \fB30\fP
.UNINDENT
.INDENT 0.0
.TP
@@ -101,6 +103,8 @@ Sets the connection level initial window size to
(2**<N>)\-1. For SPDY, if <N> is strictly less than 16,
this option is ignored. Otherwise 2**<N> is used for
SPDY.
.sp
Default: \fB30\fP
.UNINDENT
.INDENT 0.0
.TP
@@ -118,6 +122,12 @@ Default: \fBh2c\-14\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-d, \-\-data=<FILE>
Post FILE to server. The request method is changed to
POST.
.UNINDENT
.INDENT 0.0
.TP
.B \-v, \-\-verbose
Output debug information.
.UNINDENT
@@ -195,13 +205,63 @@ The maximum time taken for request and response.
The mean time taken for request and response.
.TP
.B sd
The standard deviation of the time for request and response.
The standard deviation of the time taken for request and response.
.TP
.B +/\- sd
The fraction of the number of requests within standard deviation
range (mean +/\- sd) against total number of successful requests.
.UNINDENT
.TP
.B time for connect
.INDENT 7.0
.TP
.B min
The minimum time taken to connect to a server.
.TP
.B max
The maximum time taken to connect to a server.
.TP
.B mean
The mean time taken to connect to a server.
.TP
.B sd
The standard deviation of the time taken to connect to a server.
.TP
.B +/\- sd
The fraction of the number of connections within standard
deviation range (mean +/\- sd) against total number of successful
connections.
.UNINDENT
.TP
.B time for 1st byte (of (decrypted in case of TLS) application data)
.INDENT 7.0
.TP
.B min
The minimum time taken to get 1st byte from a server.
.TP
.B max
The maximum time taken to get 1st byte from a server.
.TP
.B mean
The mean time taken to get 1st byte from a server.
.TP
.B sd
The standard deviation of the time taken to get 1st byte from a
server.
.TP
.B +/\- sd
The fraction of the number of connections within standard
deviation range (mean +/\- sd) against total number of successful
connections.
.UNINDENT
.UNINDENT
.SH FLOW CONTROL
.sp
h2load sets large flow control window by default, and effectively
disables flow control to avoid under utilization of server
performance. To set smaller flow control window, use \fI\%\-w\fP and
\fI\%\-W\fP options. For example, use \fB\-w16 \-W16\fP to set default
window size described in HTTP/2 and SPDY protocol specification.
.SH SEE ALSO
.sp
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fInghttpx(1)\fP

View File

@@ -1,4 +1,6 @@
.. program:: h2load
h2load(1)
=========
@@ -65,6 +67,8 @@ OPTIONS
Sets the stream level initial window size to (2\*\*<N>)-1.
For SPDY, 2**<N> is used instead.
Default: ``30``
.. option:: -W, --connection-window-bits=<N>
Sets the connection level initial window size to
@@ -72,6 +76,8 @@ OPTIONS
this option is ignored. Otherwise 2\*\*<N> is used for
SPDY.
Default: ``30``
.. option:: -H, --header=<HEADER>
Add/Override a header to the requests.
@@ -84,6 +90,11 @@ OPTIONS
Default: ``h2c-14``
.. option:: -d, --data=<FILE>
Post FILE to server. The request method is changed to
POST.
.. option:: -v, --verbose
Output debug information.
@@ -142,11 +153,49 @@ time for request
mean
The mean time taken for request and response.
sd
The standard deviation of the time for request and response.
The standard deviation of the time taken for request and response.
+/- sd
The fraction of the number of requests within standard deviation
range (mean +/- sd) against total number of successful requests.
time for connect
min
The minimum time taken to connect to a server.
max
The maximum time taken to connect to a server.
mean
The mean time taken to connect to a server.
sd
The standard deviation of the time taken to connect to a server.
+/- sd
The fraction of the number of connections within standard
deviation range (mean +/- sd) against total number of successful
connections.
time for 1st byte (of (decrypted in case of TLS) application data)
min
The minimum time taken to get 1st byte from a server.
max
The maximum time taken to get 1st byte from a server.
mean
The mean time taken to get 1st byte from a server.
sd
The standard deviation of the time taken to get 1st byte from a
server.
+/- sd
The fraction of the number of connections within standard
deviation range (mean +/- sd) against total number of successful
connections.
FLOW CONTROL
------------
h2load sets large flow control window by default, and effectively
disables flow control to avoid under utilization of server
performance. To set smaller flow control window, use :option:`-w` and
:option:`-W` options. For example, use ``-w16 -W16`` to set default
window size described in HTTP/2 and SPDY protocol specification.
SEE ALSO
--------

View File

@@ -44,11 +44,49 @@ time for request
mean
The mean time taken for request and response.
sd
The standard deviation of the time for request and response.
The standard deviation of the time taken for request and response.
+/- sd
The fraction of the number of requests within standard deviation
range (mean +/- sd) against total number of successful requests.
time for connect
min
The minimum time taken to connect to a server.
max
The maximum time taken to connect to a server.
mean
The mean time taken to connect to a server.
sd
The standard deviation of the time taken to connect to a server.
+/- sd
The fraction of the number of connections within standard
deviation range (mean +/- sd) against total number of successful
connections.
time for 1st byte (of (decrypted in case of TLS) application data)
min
The minimum time taken to get 1st byte from a server.
max
The maximum time taken to get 1st byte from a server.
mean
The mean time taken to get 1st byte from a server.
sd
The standard deviation of the time taken to get 1st byte from a
server.
+/- sd
The fraction of the number of connections within standard
deviation range (mean +/- sd) against total number of successful
connections.
FLOW CONTROL
------------
h2load sets large flow control window by default, and effectively
disables flow control to avoid under utilization of server
performance. To set smaller flow control window, use :option:`-w` and
:option:`-W` options. For example, use ``-w16 -W16`` to set default
window size described in HTTP/2 and SPDY protocol specification.
SEE ALSO
--------

View File

@@ -24,19 +24,21 @@
# Generates API reference from C source code.
from __future__ import print_function # At least python 2.6 is required
import re, sys, argparse
import re, sys, argparse, os.path
class FunctionDoc:
def __init__(self, name, content, domain):
self.name = name
self.content = content
self.domain = domain
if self.domain == 'function':
self.funcname = re.search(r'(nghttp2_[^ )]+)\(', self.name).group(1)
def write(self, out):
print('''.. {}:: {}'''.format(self.domain, self.name))
print('')
out.write('.. {}:: {}\n'.format(self.domain, self.name))
out.write('\n')
for line in self.content:
print(' {}'.format(line))
out.write(' {}\n'.format(line))
class StructDoc:
def __init__(self, name, content, members, member_domain):
@@ -47,17 +49,17 @@ class StructDoc:
def write(self, out):
if self.name:
print('''.. type:: {}'''.format(self.name))
print('')
out.write('.. type:: {}\n'.format(self.name))
out.write('\n')
for line in self.content:
print(' {}'.format(line))
print('')
out.write(' {}\n'.format(line))
out.write('\n')
for name, content in self.members:
print(''' .. {}:: {}'''.format(self.member_domain, name))
print('')
out.write(' .. {}:: {}\n'.format(self.member_domain, name))
out.write('\n')
for line in content:
print(''' {}'''.format(line))
print('')
out.write(' {}\n'.format(line))
out.write('\n')
class MacroDoc:
def __init__(self, name, content):
@@ -65,10 +67,10 @@ class MacroDoc:
self.content = content
def write(self, out):
print('''.. macro:: {}'''.format(self.name))
print('')
out.write('''.. macro:: {}\n'''.format(self.name))
out.write('\n')
for line in self.content:
print(' {}'.format(line))
out.write(' {}\n'.format(line))
def make_api_ref(infiles):
macros = []
@@ -93,19 +95,65 @@ def make_api_ref(infiles):
enums.append(process_enum(infile))
elif doctype == '@macro':
macros.append(process_macro(infile))
return macros, enums, types, functions
alldocs = [('Macros', macros),
('Enums', enums),
('Types (structs, unions and typedefs)', types),
('Functions', functions)]
for title, docs in alldocs:
if not docs:
continue
print(title)
print('-'*len(title))
for doc in docs:
doc.write(sys.stdout)
print('')
print('')
def output(
indexfile, macrosfile, enumsfile, typesfile, funcsdir,
macros, enums, types, functions):
indexfile.write('''
API Reference
=============
.. toctree::
:maxdepth: 1
macros
enums
types
''')
for doc in functions:
indexfile.write(' {}\n'.format(doc.funcname))
macrosfile.write('''
Macros
======
''')
for doc in macros:
doc.write(macrosfile)
enumsfile.write('''
Enums
=====
''')
for doc in enums:
doc.write(enumsfile)
typesfile.write('''
Types (structs, unions and typedefs)
====================================
''')
for doc in types:
doc.write(typesfile)
for doc in functions:
with open(os.path.join(funcsdir, doc.funcname + '.rst'), 'w') as f:
f.write('''
{funcname}
{secul}
Synopsis
--------
*#include <nghttp2/nghttp2.h>*
'''.format(funcname=doc.funcname, secul='='*len(doc.funcname)))
doc.write(f)
def process_macro(infile):
content = read_content(infile)
@@ -199,12 +247,30 @@ def transform_content(content):
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Generate API reference")
parser.add_argument('--header', type=argparse.FileType('r'),
help='header inserted at the top of the page')
parser.add_argument('index', type=argparse.FileType('w'),
help='index output file')
parser.add_argument('macros', type=argparse.FileType('w'),
help='macros section output file. The filename should be macros.rst')
parser.add_argument('enums', type=argparse.FileType('w'),
help='enums section output file. The filename should be enums.rst')
parser.add_argument('types', type=argparse.FileType('w'),
help='types section output file. The filename should be types.rst')
parser.add_argument('funcsdir',
help='functions doc output dir')
parser.add_argument('files', nargs='+', type=argparse.FileType('r'),
help='source file')
args = parser.parse_args()
if args.header:
print(args.header.read())
macros = []
enums = []
types = []
funcs = []
for infile in args.files:
make_api_ref(args.files)
m, e, t, f = make_api_ref(args.files)
macros.extend(m)
enums.extend(e)
types.extend(t)
funcs.extend(f)
funcs.sort(key=lambda x: x.funcname)
output(
args.index, args.macros, args.enums, args.types, args.funcsdir,
macros, enums, types, funcs)

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTP" "1" "February 27, 2015" "0.7.5" "nghttp2"
.TH "NGHTTP" "1" "May 08, 2015" "0.7.14" "nghttp2"
.SH NAME
nghttp \- HTTP/2 experimental client
.
@@ -64,8 +64,9 @@ yet.
.UNINDENT
.INDENT 0.0
.TP
.B \-t, \-\-timeout=<SEC>
Timeout each request after <SEC> seconds.
.B \-t, \-\-timeout=<DURATION>
Timeout each request after <DURATION>. Set 0 to disable
timeout.
.UNINDENT
.INDENT 0.0
.TP
@@ -101,6 +102,14 @@ Add a header to the requests. Example: \fI\%\-H\fP\(aq:method: PUT\(aq
.UNINDENT
.INDENT 0.0
.TP
.B \-\-trailer=<HEADER>
Add a trailer header to the requests. <HEADER> must not
include pseudo header field (header field name starting
with \(aq:\(aq). To send trailer, one must use \fI\%\-d\fP option to
send request body. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-cert=<CERT>
Use the specified client certificate file. The file
must be in PEM format.
@@ -127,7 +136,7 @@ requested twice. This option disables it too.
.TP
.B \-u, \-\-upgrade
Perform HTTP Upgrade for HTTP/2. This option is ignored
if the request URI has https scheme. If \fI\-d\fP is used, the
if the request URI has https scheme. If \fI\%\-d\fP is used, the
HTTP upgrade request is performed with OPTIONS method.
.UNINDENT
.INDENT 0.0
@@ -184,8 +193,15 @@ Don\(aqt send dependency based priority hint to server.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-dep\-idle
Use idle streams as anchor nodes to express priority.
.B \-\-hexdump
Display the incoming traffic in hexadecimal (Canonical
hex+ASCII display). If SSL/TLS is used, decrypted data
are used.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-no\-push
Disable server push.
.UNINDENT
.INDENT 0.0
.TP
@@ -200,6 +216,68 @@ Display this help and exit.
.sp
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).
.sp
The <DURATION> argument is an integer and an optional unit (e.g., 1s
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit.
.SH DEPENDENCY BASED PRIORITY
.sp
nghttp sends priority hints to server by default unless
\fI\%\-\-no\-dep\fP is used. nghttp mimics the way Firefox employs to
manages dependency using idle streams. We follows the behaviour of
Firefox Nightly as of April, 2015, and nghttp\(aqs behaviour is very
static and could be different from Firefox in detail. But reproducing
the same behaviour of Firefox is not our goal. The goal is provide
the easy way to test out the dependency priority in server
implementation.
.sp
When connection is established, nghttp sends 5 PRIORITY frames to idle
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
tree:
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
+\-\-\-\-\-+
|id=0 |
+\-\-\-\-\-+
^ ^ ^
w=201 / | \e w=1
/ | \e
/ w=101| \e
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
|id=3 | |id=5 | |id=7 |
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
^ ^
w=1 | w=1 |
| |
+\-\-\-\-\-+ +\-\-\-\-\-+
|id=11| |id=9 |
+\-\-\-\-\-+ +\-\-\-\-\-+
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
In the above figure, \fBid\fP means stream ID, and \fBw\fP means weight.
The stream 0 is non\-existence stream, and forms the root of the tree.
The stream 7 and 9 are not used for now.
.sp
The URIs given in the command\-line depend on stream 11 with the weight
given in \fI\%\-p\fP option, which defaults to 16.
.sp
If \fI\%\-a\fP option is used, nghttp parses the resource pointed by
URI given in command\-line as html, and extracts resource links from
it. When requesting those resources, nghttp uses dependency according
to its resource type.
.sp
For CSS, and Javascript files inside "head" element, they depend on
stream 3 with the weight 2. The Javascript files outside "head"
element depend on stream 5 with the weight 2. The mages depend on
stream 11 with the weight 12. The other resources (e.g., icon) depend
on stream 11 with the weight 2.
.SH SEE ALSO
.sp
\fInghttpd(1)\fP, \fInghttpx(1)\fP, \fIh2load(1)\fP

View File

@@ -1,4 +1,6 @@
.. program:: nghttp
nghttp(1)
=========
@@ -36,9 +38,10 @@ OPTIONS
'index.html' is used as a filename. Not implemented
yet.
.. option:: -t, --timeout=<SEC>
.. option:: -t, --timeout=<DURATION>
Timeout each request after <SEC> seconds.
Timeout each request after <DURATION>. Set 0 to disable
timeout.
.. option:: -w, --window-bits=<N>
@@ -67,6 +70,13 @@ OPTIONS
Add a header to the requests. Example: :option:`-H`\':method: PUT'
.. option:: --trailer=<HEADER>
Add a trailer header to the requests. <HEADER> must not
include pseudo header field (header field name starting
with ':'). To send trailer, one must use :option:`-d` option to
send request body. Example: :option:`--trailer` 'foo: bar'.
.. option:: --cert=<CERT>
Use the specified client certificate file. The file
@@ -136,9 +146,15 @@ OPTIONS
Don't send dependency based priority hint to server.
.. option:: --dep-idle
.. option:: --hexdump
Use idle streams as anchor nodes to express priority.
Display the incoming traffic in hexadecimal (Canonical
hex+ASCII display). If SSL/TLS is used, decrypted data
are used.
.. option:: --no-push
Disable server push.
.. option:: --version
@@ -149,9 +165,66 @@ OPTIONS
Display this help and exit.
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).
The <DURATION> argument is an integer and an optional unit (e.g., 1s
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit.
DEPENDENCY BASED PRIORITY
-------------------------
nghttp sends priority hints to server by default unless
:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
manages dependency using idle streams. We follows the behaviour of
Firefox Nightly as of April, 2015, and nghttp's behaviour is very
static and could be different from Firefox in detail. But reproducing
the same behaviour of Firefox is not our goal. The goal is provide
the easy way to test out the dependency priority in server
implementation.
When connection is established, nghttp sends 5 PRIORITY frames to idle
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
tree::
+-----+
|id=0 |
+-----+
^ ^ ^
w=201 / | \ w=1
/ | \
/ w=101| \
+-----+ +-----+ +-----+
|id=3 | |id=5 | |id=7 |
+-----+ +-----+ +-----+
^ ^
w=1 | w=1 |
| |
+-----+ +-----+
|id=11| |id=9 |
+-----+ +-----+
In the above figure, ``id`` means stream ID, and ``w`` means weight.
The stream 0 is non-existence stream, and forms the root of the tree.
The stream 7 and 9 are not used for now.
The URIs given in the command-line depend on stream 11 with the weight
given in :option:`-p` option, which defaults to 16.
If :option:`-a` option is used, nghttp parses the resource pointed by
URI given in command-line as html, and extracts resource links from
it. When requesting those resources, nghttp uses dependency according
to its resource type.
For CSS, and Javascript files inside "head" element, they depend on
stream 3 with the weight 2. The Javascript files outside "head"
element depend on stream 5 with the weight 2. The mages depend on
stream 11 with the weight 12. The other resources (e.g., icon) depend
on stream 11 with the weight 2.
SEE ALSO
--------

View File

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

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPD" "1" "February 27, 2015" "0.7.5" "nghttp2"
.TH "NGHTTPD" "1" "May 08, 2015" "0.7.14" "nghttp2"
.SH NAME
nghttpd \- HTTP/2 experimental server
.
@@ -63,7 +63,7 @@ address determined by getaddrinfo is used.
.INDENT 0.0
.TP
.B \-D, \-\-daemon
Run in a background. If \fI\-D\fP is used, the current working
Run in a background. If \fI\%\-D\fP is used, the current working
directory is changed to \(aq\fI/\fP\(aq. Therefore if this option
is used, \fI\%\-d\fP option must be specified.
.UNINDENT
@@ -109,7 +109,7 @@ Push resources <PUSH_PATH>s when <PATH> is requested.
This option can be used repeatedly to specify multiple
push configurations. <PATH> and <PUSH_PATH>s are
relative to document root. See \fI\%\-\-htdocs\fP option.
Example: \fI\-p\fP/=/foo.png \fI\-p\fP/doc=/bar.css
Example: \fI\%\-p\fP/=/foo.png \fI\%\-p\fP/doc=/bar.css
.UNINDENT
.INDENT 0.0
.TP
@@ -119,6 +119,14 @@ Specify 0 to disable padding.
.UNINDENT
.INDENT 0.0
.TP
.B \-m, \-\-max\-concurrent\-streams=<N>
Set the maximum number of the concurrent streams in one
HTTP/2 session.
.sp
Default: \fB100\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-n, \-\-workers=<N>
Set the number of worker threads.
.sp
@@ -144,6 +152,21 @@ rather than complete request is received.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-trailer=<HEADER>
Add a trailer header to a response. <HEADER> must not
include pseudo header field (header field name starting
with \(aq:\(aq). The trailer is sent only if a response has
body part. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-hexdump
Display the incoming traffic in hexadecimal (Canonical
hex+ASCII display). If SSL/TLS is used, decrypted data
are used.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-version
Display version information and exit.
.UNINDENT

View File

@@ -1,4 +1,6 @@
.. program:: nghttpd
nghttpd(1)
==========
@@ -83,6 +85,13 @@ OPTIONS
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
.. option:: -m, --max-concurrent-streams=<N>
Set the maximum number of the concurrent streams in one
HTTP/2 session.
Default: ``100``
.. option:: -n, --workers=<N>
Set the number of worker threads.
@@ -104,6 +113,19 @@ OPTIONS
Start sending response when request HEADERS is received,
rather than complete request is received.
.. option:: --trailer=<HEADER>
Add a trailer header to a response. <HEADER> must not
include pseudo header field (header field name starting
with ':'). The trailer is sent only if a response has
body part. Example: :option:`--trailer` 'foo: bar'.
.. option:: --hexdump
Display the incoming traffic in hexadecimal (Canonical
hex+ASCII display). If SSL/TLS is used, decrypted data
are used.
.. option:: --version
Display version information and exit.
@@ -113,6 +135,7 @@ OPTIONS
Display this help and exit.
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPX" "1" "February 27, 2015" "0.7.5" "nghttp2"
.TH "NGHTTPX" "1" "May 08, 2015" "0.7.14" "nghttp2"
.SH NAME
nghttpx \- HTTP/2 experimental proxy
.
@@ -46,7 +46,8 @@ Set path to server\(aqs private key. Required unless \fI\%\-p\fP,
.TP
.B <CERT>
Set path to server\(aqs certificate. Required unless \fI\%\-p\fP,
\fI\%\-\-client\fP or \fI\%\-\-frontend\-no\-tls\fP are given.
\fI\%\-\-client\fP or \fI\%\-\-frontend\-no\-tls\fP are given. To make OCSP
stapling work, this must be absolute path.
.UNINDENT
.SH OPTIONS
.sp
@@ -55,13 +56,10 @@ The options are categorized into several groups.
.INDENT 0.0
.TP
.B \-b, \-\-backend=<HOST,PORT>
Set backend host and port. For HTTP/1 backend, multiple
backend addresses are accepted by repeating this option.
HTTP/2 backend does not support multiple backend
addresses and the first occurrence of this option is
used. UNIX domain socket can be specified by prefixing
path name with "unix:" (e.g.,
unix:/var/run/backend.sock)
Set backend host and port. The multiple backend
addresses are accepted by repeating this option. UNIX
domain socket can be specified by prefixing path name
with "unix:" (e.g., unix:/var/run/backend.sock)
.sp
Default: \fB127.0.0.1,80\fP
.UNINDENT
@@ -196,6 +194,13 @@ Default: \fB0\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-backend\-http2\-connections\-per\-worker=<N>
Set maximum number of HTTP/2 connections per worker.
The default value is 0, which means the number of
backend addresses specified by \fI\%\-b\fP option.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-backend\-http1\-connections\-per\-host=<N>
Set maximum number of backend concurrent HTTP/1
connections per host. This option is meaningful when \fI\%\-s\fP
@@ -245,14 +250,14 @@ Default: \fB16K\fP
Specify read timeout for HTTP/2 and SPDY frontend
connection.
.sp
Default: \fB180s\fP
Default: \fB3m\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-frontend\-read\-timeout=<DURATION>
Specify read timeout for HTTP/1.1 frontend connection.
.sp
Default: \fB180s\fP
Default: \fB3m\fP
.UNINDENT
.INDENT 0.0
.TP
@@ -282,7 +287,7 @@ Default: \fB0\fP
.B \-\-backend\-read\-timeout=<DURATION>
Specify read timeout for backend connection.
.sp
Default: \fB180s\fP
Default: \fB3m\fP
.UNINDENT
.INDENT 0.0
.TP
@@ -344,7 +349,8 @@ password protected it\(aqll be requested interactively.
Specify additional certificate and private key file.
nghttpx will choose certificates based on the hostname
indicated by client using TLS SNI extension. This
option can be used multiple times.
option can be used multiple times. To make OCSP
stapling work, <CERTPATH> must be absolute path.
.UNINDENT
.INDENT 0.0
.TP
@@ -429,14 +435,23 @@ are stored in memory.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-ctx\-per\-worker
Create OpenSSL\(aqs SSL_CTX per worker, so that no internal
locking is required. This may improve scalability with
multi threaded configuration. If this option is
enabled, session ID is no longer shared accross SSL_CTX
objects, which means session ID generated by one worker
is not acceptable by another worker. On the other hand,
session ticket key is shared across all worker threads.
.B \-\-fetch\-ocsp\-response\-file=<PATH>
Path to fetch\-ocsp\-response script file. It should be
absolute path.
.sp
Default: \fB/usr/local/share/nghttp2/fetch\-ocsp\-response\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-ocsp\-update\-interval=<DURATION>
Set interval to update OCSP response cache.
.sp
Default: \fB4h\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-no\-ocsp
Disable OCSP stapling.
.UNINDENT
.SS HTTP/2 and SPDY
.INDENT 0.0
@@ -617,7 +632,8 @@ Default: \fB$remote_addr \- \- [$time_local] "$request" $status $body_bytes_sent
.TP
.B \-\-errorlog\-file=<PATH>
Set path to write error log. To reopen file, send USR1
signal to nghttpx.
signal to nghttpx. stderr will be redirected to the
error log file unless \fI\%\-\-errorlog\-syslog\fP is used.
.sp
Default: \fB/dev/stderr\fP
.UNINDENT
@@ -688,6 +704,23 @@ won\(aqt replace anything already set. This option can be
used several times to specify multiple header fields.
Example: \fI\%\-\-add\-response\-header\fP="foo: bar"
.UNINDENT
.INDENT 0.0
.TP
.B \-\-header\-field\-buffer=<SIZE>
Set maximum buffer size for incoming HTTP header field
list. This is the sum of header name and value in
bytes.
.sp
Default: \fB64K\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-max\-header\-fields=<N>
Set maximum number of incoming HTTP header fields, which
appear in one request or response header field list.
.sp
Default: \fB100\fP
.UNINDENT
.SS Debug
.INDENT 0.0
.TP
@@ -755,8 +788,9 @@ The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).
.sp
The <DURATION> argument is an integer and an optional unit (e.g., 1s
is 1 second and 500ms is 500 milliseconds). Units are s or ms. If
a unit is omitted, a second is used as unit.
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit.
.SH FILES
.INDENT 0.0
.TP
@@ -845,6 +879,15 @@ specified socket already exists in the file system, nghttpx first
deletes it. However, if SIGUSR2 is used to execute new binary and
both old and new configurations use same filename, new binary does not
delete the socket and continues to use it.
.SH OCSP STAPLING
.sp
OCSP query is done using external perl script \fBfetch\-ocsp\-response\fP,
which has been developed as part of h2o project
(\fI\%https://github.com/h2o/h2o\fP).
.sp
The script file is usually installed under
\fB$(prefix)/share/nghttp2/\fP directory. The actual path to script can
be customized using \fI\%\-\-fetch\-ocsp\-response\-file\fP option.
.SH SEE ALSO
.sp
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fIh2load(1)\fP

View File

@@ -1,4 +1,6 @@
.. program:: nghttpx
nghttpx(1)
==========
@@ -21,7 +23,8 @@ A reverse proxy for HTTP/2, HTTP/1 and SPDY.
.. describe:: <CERT>
Set path to server's certificate. Required unless :option:`-p`\,
:option:`--client` or :option:`\--frontend-no-tls` are given.
:option:`--client` or :option:`\--frontend-no-tls` are given. To make OCSP
stapling work, this must be absolute path.
OPTIONS
@@ -34,13 +37,10 @@ Connections
.. option:: -b, --backend=<HOST,PORT>
Set backend host and port. For HTTP/1 backend, multiple
backend addresses are accepted by repeating this option.
HTTP/2 backend does not support multiple backend
addresses and the first occurrence of this option is
used. UNIX domain socket can be specified by prefixing
path name with "unix:" (e.g.,
unix:/var/run/backend.sock)
Set backend host and port. The multiple backend
addresses are accepted by repeating this option. UNIX
domain socket can be specified by prefixing path name
with "unix:" (e.g., unix:/var/run/backend.sock)
Default: ``127.0.0.1,80``
@@ -161,6 +161,12 @@ Performance
Default: ``0``
.. option:: --backend-http2-connections-per-worker=<N>
Set maximum number of HTTP/2 connections per worker.
The default value is 0, which means the number of
backend addresses specified by :option:`-b` option.
.. option:: --backend-http1-connections-per-host=<N>
Set maximum number of backend concurrent HTTP/1
@@ -209,13 +215,13 @@ Timeout
Specify read timeout for HTTP/2 and SPDY frontend
connection.
Default: ``180s``
Default: ``3m``
.. option:: --frontend-read-timeout=<DURATION>
Specify read timeout for HTTP/1.1 frontend connection.
Default: ``180s``
Default: ``3m``
.. option:: --frontend-write-timeout=<DURATION>
@@ -241,7 +247,7 @@ Timeout
Specify read timeout for backend connection.
Default: ``180s``
Default: ``3m``
.. option:: --backend-write-timeout=<DURATION>
@@ -298,7 +304,8 @@ SSL/TLS
Specify additional certificate and private key file.
nghttpx will choose certificates based on the hostname
indicated by client using TLS SNI extension. This
option can be used multiple times.
option can be used multiple times. To make OCSP
stapling work, <CERTPATH> must be absolute path.
.. option:: --backend-tls-sni-field=<HOST>
@@ -372,15 +379,22 @@ SSL/TLS
automatically and renewed every 12hrs. At most 2 keys
are stored in memory.
.. option:: --tls-ctx-per-worker
.. option:: --fetch-ocsp-response-file=<PATH>
Create OpenSSL's SSL_CTX per worker, so that no internal
locking is required. This may improve scalability with
multi threaded configuration. If this option is
enabled, session ID is no longer shared accross SSL_CTX
objects, which means session ID generated by one worker
is not acceptable by another worker. On the other hand,
session ticket key is shared across all worker threads.
Path to fetch-ocsp-response script file. It should be
absolute path.
Default: ``/usr/local/share/nghttp2/fetch-ocsp-response``
.. option:: --ocsp-update-interval=<DURATION>
Set interval to update OCSP response cache.
Default: ``4h``
.. option:: --no-ocsp
Disable OCSP stapling.
HTTP/2 and SPDY
@@ -539,7 +553,8 @@ Logging
.. option:: --errorlog-file=<PATH>
Set path to write error log. To reopen file, send USR1
signal to nghttpx.
signal to nghttpx. stderr will be redirected to the
error log file unless :option:`--errorlog-syslog` is used.
Default: ``/dev/stderr``
@@ -604,6 +619,21 @@ HTTP
used several times to specify multiple header fields.
Example: :option:`--add-response-header`\="foo: bar"
.. option:: --header-field-buffer=<SIZE>
Set maximum buffer size for incoming HTTP header field
list. This is the sum of header name and value in
bytes.
Default: ``64K``
.. option:: --max-header-fields=<N>
Set maximum number of incoming HTTP header fields, which
appear in one request or response header field list.
Default: ``100``
Debug
~~~~~
@@ -667,12 +697,14 @@ Misc
Print this help and exit.
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).
The <DURATION> argument is an integer and an optional unit (e.g., 1s
is 1 second and 500ms is 500 milliseconds). Units are s or ms. If
a unit is omitted, a second is used as unit.
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit.
FILES
-----
@@ -760,6 +792,17 @@ deletes it. However, if SIGUSR2 is used to execute new binary and
both old and new configurations use same filename, new binary does not
delete the socket and continues to use it.
OCSP STAPLING
-------------
OCSP query is done using external perl script ``fetch-ocsp-response``,
which has been developed as part of h2o project
(https://github.com/h2o/h2o).
The script file is usually installed under
``$(prefix)/share/nghttp2/`` directory. The actual path to script can
be customized using :option:`--fetch-ocsp-response-file` option.
SEE ALSO
--------

View File

@@ -84,6 +84,17 @@ deletes it. However, if SIGUSR2 is used to execute new binary and
both old and new configurations use same filename, new binary does not
delete the socket and continues to use it.
OCSP STAPLING
-------------
OCSP query is done using external perl script ``fetch-ocsp-response``,
which has been developed as part of h2o project
(https://github.com/h2o/h2o).
The script file is usually installed under
``$(prefix)/share/nghttp2/`` directory. The actual path to script can
be customized using :option:`--fetch-ocsp-response-file` option.
SEE ALSO
--------

View File

@@ -1,5 +1,5 @@
API Reference
=============
Programmers' Guide
==================
Includes
--------
@@ -32,6 +32,8 @@ 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.
.. _http-messaging:
HTTP Messaging
--------------
@@ -84,6 +86,11 @@ are floating around in existing internet and resetting stream just
because of this may break many web sites. This is especially true if
we forward to or translate from HTTP/1 traffic.
For "http" or "https" URIs, ":path" pseudo header fields must start
with "/". The only exception is OPTIONS request, in that case, "*" is
allowed in ":path" pseudo header field to represent system-wide
OPTIONS request.
With the above validations, nghttp2 library guarantees that header
field name passed to `nghttp2_on_header_callback()` is not empty.
Also required pseudo headers are all present and not empty.

View File

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

View File

@@ -28,6 +28,7 @@ Contents:
h2load.1
nghttpx-howto
h2load-howto
programmers-guide
apiref
libnghttp2_asio
python-apiref

View File

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

View File

@@ -60,7 +60,10 @@ if ENABLE_ASIO_LIB
noinst_PROGRAMS += asio-sv asio-sv2 asio-cl asio-cl2
ASIOCPPFLAGS = ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
# AM_CPPFLAGS must be placed first, so that header file (e.g.,
# nghttp2/nghttp2.h) in this package is used rather than installed
# one.
ASIOCPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
$(top_builddir)/third-party/libhttp-parser.la \

View File

@@ -258,8 +258,7 @@ static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
stream), if it is closed, we send GOAWAY and tear down the
session */
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code,
void *user_data) {
uint32_t error_code, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
int rv;

View File

@@ -190,7 +190,7 @@ typedef enum {
NGHTTP2_TOKEN__METHOD,
NGHTTP2_TOKEN__PATH,
NGHTTP2_TOKEN__SCHEME,
NGHTTP2_TOKEN_HOST,
NGHTTP2_TOKEN_HOST
} nghttp2_token;
/* Inspired by h2o header lookup. https://github.com/h2o/h2o */
@@ -658,19 +658,52 @@ static void stream_error(connection *conn, int32_t stream_id,
error_code);
}
static int send_data_callback(nghttp2_session *session _U_,
nghttp2_frame *frame, const uint8_t *framehd,
size_t length, nghttp2_data_source *source,
void *user_data) {
connection *conn = user_data;
uint8_t *p = conn->buf.last;
stream *strm = source->ptr;
/* We never use padding in this program */
assert(frame->data.padlen == 0);
if ((size_t)io_buf_left(&conn->buf) < 9 + frame->hd.length) {
return NGHTTP2_ERR_WOULDBLOCK;
}
memcpy(p, framehd, 9);
p += 9;
while (length) {
ssize_t nread;
while ((nread = read(strm->filefd, p, length)) == -1 && errno == EINTR)
;
if (nread == -1) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
length -= nread;
p += nread;
}
conn->buf.last = p;
return 0;
}
static ssize_t fd_read_callback(nghttp2_session *session _U_,
int32_t stream_id _U_, uint8_t *buf,
int32_t stream_id _U_, uint8_t *buf _U_,
size_t length, uint32_t *data_flags,
nghttp2_data_source *source,
void *user_data _U_) {
stream *strm = source->ptr;
ssize_t nread;
ssize_t nread =
(int64_t)length < strm->fileleft ? (int64_t)length : strm->fileleft;
*data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
while ((nread = read(strm->filefd, buf, length)) == -1 && errno == EINTR)
;
if (nread == -1) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
strm->fileleft -= nread;
if (nread == 0 || strm->fileleft == 0) {
if (strm->fileleft != 0) {
@@ -1274,6 +1307,8 @@ int main(int argc, char **argv) {
shared_callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_frame_not_send_callback(
shared_callbacks, on_frame_not_send_callback);
nghttp2_session_callbacks_set_send_data_callback(shared_callbacks,
send_data_callback);
rv = nghttp2_option_new(&shared_option);
if (rv != 0) {

View File

@@ -77,7 +77,7 @@ int lookup_token(const uint8_t *name, size_t namelen) {
print '''\
case {}:'''.format(size)
print '''\
switch (name[namelen - 1]) {'''
switch (name[{}]) {{'''.format(size - 1)
for c in sorted(ents.keys()):
headers = sorted(ents[c])
print '''\

View File

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

View File

@@ -61,6 +61,8 @@ def help2man(infile):
description.append(line)
print '''
.. program:: {cmdname}
{cmdname}(1)
{cmdnameunderline}
@@ -78,6 +80,7 @@ DESCRIPTION
synopsis=synopsis, description=format_text('\n'.join(description)))
in_arg = False
in_footer = False
for line in infile:
line = line.rstrip()
@@ -95,6 +98,14 @@ DESCRIPTION
print ''
in_arg = False
if line == '--':
in_footer = True
continue
if in_footer:
print line.strip()
continue
if line == 'Options:':
print 'OPTIONS'
print '-------'

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

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

View File

@@ -246,6 +246,72 @@ func TestH1H1RequestTrailer(t *testing.T) {
}
}
// TestH1H1HeaderFieldBufferPath tests that request with request path
// larger than configured buffer size is rejected.
func TestH1H1HeaderFieldBufferPath(t *testing.T) {
// The value 100 is chosen so that sum of header fields bytes
// does not exceed it. We use > 100 bytes URI to exceed this
// limit.
st := newServerTester([]string{"--header-field-buffer=100"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1HeaderFieldBufferPath",
path: "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1HeaderFieldBuffer tests that request with header fields
// larger than configured buffer size is rejected.
func TestH1H1HeaderFieldBuffer(t *testing.T) {
st := newServerTester([]string{"--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1HeaderFieldBuffer",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1HeaderFields tests that request with header fields more
// than configured number is rejected.
func TestH1H1HeaderFields(t *testing.T) {
st := newServerTester([]string{"--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1HeaderFields",
header: []hpack.HeaderField{
// Add extra header field to ensure that
// header field limit exceeds
pair("Connection", "close"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H2ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/2 backend failed.
func TestH1H2ConnectFailure(t *testing.T) {

View File

@@ -8,6 +8,7 @@ import (
"io"
"io/ioutil"
"net/http"
"strings"
"syscall"
"testing"
)
@@ -494,7 +495,9 @@ func TestH2H1SNI(t *testing.T) {
func TestH2H1ServerPush(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
// only resources marked as rel=preload are pushed
w.Header().Add("Link", "</css/main.css>; rel=preload, </foo>, </css/theme.css>; rel=preload")
if !strings.HasPrefix(r.URL.Path, "/css/") {
w.Header().Add("Link", "</css/main.css>; rel=preload, </foo>, </css/theme.css>; rel=preload")
}
})
defer st.Close()
@@ -555,6 +558,79 @@ func TestH2H1RequestTrailer(t *testing.T) {
}
}
// TestH2H1HeaderFieldBuffer tests that request with header fields
// larger than configured buffer size is rejected.
func TestH2H1HeaderFieldBuffer(t *testing.T) {
st := newServerTester([]string{"--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1HeaderFieldBuffer",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1HeaderFields tests that request with header fields more
// than configured number is rejected.
func TestH2H1HeaderFields(t *testing.T) {
st := newServerTester([]string{"--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("execution path should not be here")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1HeaderFields",
// we have at least 4 pseudo-header fields sent, and
// that ensures that buffer limit exceeds.
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 431; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1Upgrade tests HTTP Upgrade to HTTP/2
func TestH2H1Upgrade(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH2H1Upgrade",
header: []hpack.HeaderField{
pair("Connection", "Upgrade, HTTP2-Settings"),
pair("Upgrade", "h2c-14"),
pair("HTTP2-Settings", "AAMAAABkAAQAAP__"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 101; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
res, err = st.http2(requestParam{
httpUpgrade: true,
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
}
// TestH2H1GracefulShutdown tests graceful shutdown.
func TestH2H1GracefulShutdown(t *testing.T) {
st := newServerTester(nil, t, noopHandler)

View File

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

View File

@@ -247,15 +247,16 @@ func (st *serverTester) readSpdyFrame() (spdy.Frame, error) {
}
type requestParam struct {
name string // name for this request to identify the request in log easily
streamID uint32 // stream ID, automatically assigned if 0
method string // method, defaults to GET
scheme string // scheme, defaults to http
authority string // authority, defaults to backend server address
path string // path, defaults to /
header []hpack.HeaderField // additional request header fields
body []byte // request body
trailer []hpack.HeaderField // trailer part
name string // name for this request to identify the request in log easily
streamID uint32 // stream ID, automatically assigned if 0
method string // method, defaults to GET
scheme string // scheme, defaults to http
authority string // authority, defaults to backend server address
path string // path, defaults to /
header []hpack.HeaderField // additional request header fields
body []byte // request body
trailer []hpack.HeaderField // trailer part
httpUpgrade bool // true if upgraded to HTTP/2 through HTTP Upgrade
}
// wrapper for request body to set trailer part
@@ -296,7 +297,19 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
body = cbr
}
}
req, err := http.NewRequest(method, st.url, body)
reqURL := st.url
if rp.path != "" {
u, err := url.Parse(st.url)
if err != nil {
st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err)
}
u.Path = rp.path
reqURL = u.String()
}
req, err := http.NewRequest(method, reqURL, body)
if err != nil {
return nil, err
}
@@ -478,69 +491,70 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
streams := make(map[uint32]*serverResponse)
streams[id] = res
method := "GET"
if rp.method != "" {
method = rp.method
}
_ = st.enc.WriteField(pair(":method", method))
scheme := "http"
if rp.scheme != "" {
scheme = rp.scheme
}
_ = st.enc.WriteField(pair(":scheme", scheme))
authority := st.authority
if rp.authority != "" {
authority = rp.authority
}
_ = st.enc.WriteField(pair(":authority", authority))
path := "/"
if rp.path != "" {
path = rp.path
}
_ = st.enc.WriteField(pair(":path", path))
_ = st.enc.WriteField(pair("test-case", rp.name))
for _, h := range rp.header {
_ = st.enc.WriteField(h)
}
err := st.fr.WriteHeaders(http2.HeadersFrameParam{
StreamID: id,
EndStream: len(rp.body) == 0 && len(rp.trailer) == 0,
EndHeaders: true,
BlockFragment: st.headerBlkBuf.Bytes(),
})
if err != nil {
return nil, err
}
if len(rp.body) != 0 {
// TODO we assume rp.body fits in 1 frame
if err := st.fr.WriteData(id, len(rp.trailer) == 0, rp.body); err != nil {
return nil, err
if !rp.httpUpgrade {
method := "GET"
if rp.method != "" {
method = rp.method
}
}
_ = st.enc.WriteField(pair(":method", method))
if len(rp.trailer) != 0 {
st.headerBlkBuf.Reset()
for _, h := range rp.trailer {
scheme := "http"
if rp.scheme != "" {
scheme = rp.scheme
}
_ = st.enc.WriteField(pair(":scheme", scheme))
authority := st.authority
if rp.authority != "" {
authority = rp.authority
}
_ = st.enc.WriteField(pair(":authority", authority))
path := "/"
if rp.path != "" {
path = rp.path
}
_ = st.enc.WriteField(pair(":path", path))
_ = st.enc.WriteField(pair("test-case", rp.name))
for _, h := range rp.header {
_ = st.enc.WriteField(h)
}
err := st.fr.WriteHeaders(http2.HeadersFrameParam{
StreamID: id,
EndStream: true,
EndStream: len(rp.body) == 0 && len(rp.trailer) == 0,
EndHeaders: true,
BlockFragment: st.headerBlkBuf.Bytes(),
})
if err != nil {
return nil, err
}
}
if len(rp.body) != 0 {
// TODO we assume rp.body fits in 1 frame
if err := st.fr.WriteData(id, len(rp.trailer) == 0, rp.body); err != nil {
return nil, err
}
}
if len(rp.trailer) != 0 {
st.headerBlkBuf.Reset()
for _, h := range rp.trailer {
_ = st.enc.WriteField(h)
}
err := st.fr.WriteHeaders(http2.HeadersFrameParam{
StreamID: id,
EndStream: true,
EndHeaders: true,
BlockFragment: st.headerBlkBuf.Bytes(),
})
if err != nil {
return nil, err
}
}
}
loop:
for {
fr, err := st.readFrame()

3
lib/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# generated files
includes/nghttp2/nghttp2ver.h
libnghttp2.pc

View File

@@ -2,15 +2,14 @@
# GNU Makefile for nghttp2 / MSVC.
#
# By G. Vanem <gvanem@yahoo.no> 2013
# Updated 3/2015 by Remo Eichenberger @remoe
# 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')
@@ -38,7 +37,7 @@ INSTALL_HDR = $(VC_ROOT)/include
TARGETS = nghttp2.lib nghttp2.dll nghttp2_imp.lib \
nghttp2d.lib nghttp2d.dll nghttp2d_imp.lib
EXT_LIBS = $(ZLIB_ROOT)/zlib.lib ws2_32.lib
EXT_LIBS =
OBJ_DIR = MSVC_obj
@@ -46,32 +45,34 @@ 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 = -I./includes -Dssize_t=long -D_U_=""
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
LDFLAGS = -nologo -machine:x64 -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_SRC = nghttp2_pq.c \
nghttp2_map.c \
nghttp2_queue.c \
nghttp2_frame.c \
nghttp2_buf.c \
nghttp2_stream.c \
nghttp2_outbound_item.c \
nghttp2_session.c \
nghttp2_submit.c \
nghttp2_helper.c \
nghttp2_npn.c \
nghttp2_hd.c \
nghttp2_hd_huffman.c \
nghttp2_hd_huffman_data.c \
nghttp2_version.c \
nghttp2_priority_spec.c \
nghttp2_option.c \
nghttp2_callbacks.c \
nghttp2_mem.c \
nghttp2_http.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)))
@@ -116,13 +117,13 @@ 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.dll nghttp2_imp.lib: $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res
link $(LDFLAGS) -dll -out:nghttp2.dll -implib:nghttp2_imp.lib \
$(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 \
nghttp2d.dll nghttp2d_imp.lib: $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res
link $(LDFLAGS) -dll -out:nghttp2d.dll -implib:nghttp2d_imp.lib \
$(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(EXT_LIBS)
@echo
@@ -219,24 +220,6 @@ nghttp2.rc: Makefile.MSVC
@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
@@ -263,4 +246,4 @@ depend: includes/nghttp2/nghttp2ver.h
sed -e $(REPLACE_D) .depend.tmp >> .depend.MSVC
rm -f .depend.tmp
-include .depend.MSVC
-include .depend.MSVC

File diff suppressed because it is too large Load Diff

View File

@@ -410,36 +410,46 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
len += nghttp2_buf_len(&chain->buf);
}
if (!len) {
if (len == 0) {
res = NULL;
} else {
res = nghttp2_mem_malloc(bufs->mem, len);
return 0;
}
if (res == NULL) {
return NGHTTP2_ERR_NOMEM;
}
res = nghttp2_mem_malloc(bufs->mem, len);
if (res == NULL) {
return NGHTTP2_ERR_NOMEM;
}
nghttp2_buf_wrap_init(&resbuf, res, len);
for (chain = bufs->head; chain; chain = chain->next) {
buf = &chain->buf;
if (resbuf.last) {
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
}
nghttp2_buf_reset(buf);
nghttp2_buf_shift_right(&chain->buf, bufs->offset);
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
}
bufs->cur = bufs->head;
*out = res;
return (ssize_t)len;
}
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) {
size_t len;
nghttp2_buf_chain *chain;
nghttp2_buf *buf;
nghttp2_buf resbuf;
len = nghttp2_bufs_len(bufs);
nghttp2_buf_wrap_init(&resbuf, out, len);
for (chain = bufs->head; chain; chain = chain->next) {
buf = &chain->buf;
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
}
return len;
}
void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
nghttp2_buf_chain *chain, *ci;
size_t k;

View File

@@ -313,9 +313,8 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
* function allocates the contagious memory to store all data in
* |bufs| and assigns it to |*out|.
*
* On successful return, nghttp2_bufs_len(bufs) returns 0, just like
* after calling nghttp2_bufs_reset().
* The contents of |bufs| is left unchanged.
*
* This function returns the length of copied data and assigns the
* pointer to copied data to |*out| if it succeeds, or one of the
* following negative error codes:
@@ -325,6 +324,17 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
*/
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
/*
* Copies all data stored in |bufs| to |out|. This function assumes
* that the buffer space pointed by |out| has at least
* nghttp2_bufs(bufs) bytes.
*
* The contents of |bufs| is left unchanged.
*
* This function returns the length of copied data.
*/
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out);
/*
* Resets |bufs| and makes the buffers empty.
*/

View File

@@ -121,3 +121,9 @@ void nghttp2_session_callbacks_set_on_begin_frame_callback(
nghttp2_on_begin_frame_callback on_begin_frame_callback) {
cbs->on_begin_frame_callback = on_begin_frame_callback;
}
void nghttp2_session_callbacks_set_send_data_callback(
nghttp2_session_callbacks *cbs,
nghttp2_send_data_callback send_data_callback) {
cbs->send_data_callback = send_data_callback;
}

View File

@@ -106,6 +106,7 @@ struct nghttp2_session_callbacks {
* Sets callback function invoked when a frame header is received.
*/
nghttp2_on_begin_frame_callback on_begin_frame_callback;
nghttp2_send_data_callback send_data_callback;
};
#endif /* NGHTTP2_CALLBACKS_H */

View File

@@ -739,7 +739,8 @@ int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
nghttp2_nv *p;
for (i = 0; i < nvlen; ++i) {
buflen += nva[i].namelen + nva[i].valuelen;
/* + 2 for null-termination */
buflen += nva[i].namelen + nva[i].valuelen + 2;
}
if (nvlen == 0) {
@@ -765,12 +766,14 @@ int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
memcpy(data, nva[i].name, nva[i].namelen);
p->name = data;
p->namelen = nva[i].namelen;
data[p->namelen] = '\0';
nghttp2_downcase(p->name, p->namelen);
data += nva[i].namelen;
data += nva[i].namelen + 1;
memcpy(data, nva[i].value, nva[i].valuelen);
p->value = data;
p->valuelen = nva[i].valuelen;
data += nva[i].valuelen;
data[p->valuelen] = '\0';
data += nva[i].valuelen + 1;
++p;
}
return 0;
@@ -810,7 +813,7 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
return 1;
}
static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) {
size_t trail_padlen;
size_t newlen;
@@ -825,6 +828,10 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen;
nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3]));
if (framehd_only) {
return;
}
trail_padlen = padlen - 1;
buf->pos[NGHTTP2_FRAME_HDLEN] = trail_padlen;
@@ -833,12 +840,10 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
/* extend buffers trail_padlen bytes, since we ate previous padlen -
trail_padlen byte(s) */
buf->last += trail_padlen;
return;
}
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
size_t padlen) {
size_t padlen, int framehd_only) {
nghttp2_buf *buf;
if (padlen == 0) {
@@ -871,7 +876,7 @@ int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
assert(nghttp2_buf_avail(buf) >= (ssize_t)padlen - 1);
frame_set_pad(buf, padlen);
frame_set_pad(buf, padlen, framehd_only);
hd->length += padlen;
hd->flags |= NGHTTP2_FLAG_PADDED;

View File

@@ -471,7 +471,9 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
/*
* Copies name/value pairs from |nva|, which contains |nvlen| pairs,
* to |*nva_ptr|, which is dynamically allocated so that all items can
* be stored.
* be stored. The resultant name and value in nghttp2_nv are
* guaranteed to be NULL-terminated even if the input is not
* null-terminated.
*
* The |*nva_ptr| must be freed using nghttp2_nv_array_del().
*
@@ -508,7 +510,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
* Sets Pad Length field and flags and adjusts frame header position
* of each buffers in |bufs|. The number of padding is given in the
* |padlen| including Pad Length field. The |hd| is the frame header
* for the serialized data.
* for the serialized data. This function fills zeros padding region
* unless framehd_only is nonzero.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -519,6 +522,6 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
* The length of the resulting frame is too large.
*/
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
size_t padlen);
size_t padlen, int framehd_only);
#endif /* NGHTTP2_FRAME_H */

File diff suppressed because it is too large Load Diff

View File

@@ -49,7 +49,68 @@
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
/* Exported for unit test */
extern const size_t NGHTTP2_STATIC_TABLE_LENGTH;
#define NGHTTP2_STATIC_TABLE_LENGTH 61
/* Generated by genlibtokenlookup.py */
typedef enum {
NGHTTP2_TOKEN__AUTHORITY = 0,
NGHTTP2_TOKEN__METHOD = 1,
NGHTTP2_TOKEN__PATH = 3,
NGHTTP2_TOKEN__SCHEME = 5,
NGHTTP2_TOKEN__STATUS = 7,
NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
NGHTTP2_TOKEN_ACCEPT = 18,
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
NGHTTP2_TOKEN_AGE = 20,
NGHTTP2_TOKEN_ALLOW = 21,
NGHTTP2_TOKEN_AUTHORIZATION = 22,
NGHTTP2_TOKEN_CACHE_CONTROL = 23,
NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
NGHTTP2_TOKEN_CONTENT_RANGE = 29,
NGHTTP2_TOKEN_CONTENT_TYPE = 30,
NGHTTP2_TOKEN_COOKIE = 31,
NGHTTP2_TOKEN_DATE = 32,
NGHTTP2_TOKEN_ETAG = 33,
NGHTTP2_TOKEN_EXPECT = 34,
NGHTTP2_TOKEN_EXPIRES = 35,
NGHTTP2_TOKEN_FROM = 36,
NGHTTP2_TOKEN_HOST = 37,
NGHTTP2_TOKEN_IF_MATCH = 38,
NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
NGHTTP2_TOKEN_IF_RANGE = 41,
NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
NGHTTP2_TOKEN_LAST_MODIFIED = 43,
NGHTTP2_TOKEN_LINK = 44,
NGHTTP2_TOKEN_LOCATION = 45,
NGHTTP2_TOKEN_MAX_FORWARDS = 46,
NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
NGHTTP2_TOKEN_RANGE = 49,
NGHTTP2_TOKEN_REFERER = 50,
NGHTTP2_TOKEN_REFRESH = 51,
NGHTTP2_TOKEN_RETRY_AFTER = 52,
NGHTTP2_TOKEN_SERVER = 53,
NGHTTP2_TOKEN_SET_COOKIE = 54,
NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
NGHTTP2_TOKEN_USER_AGENT = 57,
NGHTTP2_TOKEN_VARY = 58,
NGHTTP2_TOKEN_VIA = 59,
NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
NGHTTP2_TOKEN_TE,
NGHTTP2_TOKEN_CONNECTION,
NGHTTP2_TOKEN_KEEP_ALIVE,
NGHTTP2_TOKEN_PROXY_CONNECTION,
NGHTTP2_TOKEN_UPGRADE
} nghttp2_token;
typedef enum {
NGHTTP2_HD_FLAG_NONE = 0,
@@ -67,18 +128,14 @@ typedef enum {
typedef struct {
nghttp2_nv nv;
uint32_t name_hash;
uint32_t value_hash;
/* nghttp2_token value for nv.name. It could be -1 if we have no
token for that header field name. */
int token;
/* Reference count */
uint8_t ref;
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;
@@ -107,6 +164,12 @@ typedef enum {
NGHTTP2_HD_STATE_READ_VALUE
} nghttp2_hd_inflate_state;
typedef enum {
NGHTTP2_HD_WITH_INDEXING,
NGHTTP2_HD_WITHOUT_INDEXING,
NGHTTP2_HD_NEVER_INDEXING
} nghttp2_hd_indexing_mode;
typedef struct {
/* dynamic header table */
nghttp2_hd_ringbuf hd_table;
@@ -176,9 +239,8 @@ 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. The |name_hash| and |value_hash| are hash
* value for |name| and |value| respectively. The hash function is
* defined in nghttp2_hd.c.
* |valuelen| is copied. The |token| is enum number looked up by
* |name|. It could be -1 if we don't have that enum value.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -188,8 +250,7 @@ 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,
uint32_t name_hash, uint32_t value_hash,
nghttp2_mem *mem);
int token, nghttp2_mem *mem);
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent, nghttp2_mem *mem);
@@ -271,13 +332,25 @@ int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
*/
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
/*
* Similar to nghttp2_hd_inflate_hd(), but this takes additional
* output parameter |token|. On successful header emission, it
* contains nghttp2_token value for nv_out->name. It could be -1 if
* we don't have enum value for the name. Other than that return
* values and semantics are the same as nghttp2_hd_inflate_hd().
*/
ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
nghttp2_nv *nv_out, int *inflate_flags,
int *token, uint8_t *in, size_t inlen,
int in_final);
/* For unittesting purpose */
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
nghttp2_nv *nv, int inc_indexing);
nghttp2_nv *nv, int indexing_mode);
/* For unittesting purpose */
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
int inc_indexing);
int indexing_mode);
/* For unittesting purpose */
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
@@ -324,8 +397,7 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
* be initialized by nghttp2_hd_huff_decode_context_init(). The result
* will be added to |dest|. This function may expand |dest| as
* needed. The caller is responsible to release the memory of |dest|
* by calling nghttp2_bufs_free() or export its content using
* nghttp2_bufs_remove().
* by calling nghttp2_bufs_free().
*
* The caller must set the |final| to nonzero if the given input is
* the final block.

View File

@@ -168,10 +168,27 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
ctx->accept = 1;
}
/* Use macro to make the code simpler..., but error case is tricky.
We spent most of the CPU in decoding, so we are doing this
thing. */
#define hd_huff_decode_sym_emit(bufs, sym, avail) \
do { \
if ((avail)) { \
nghttp2_bufs_fast_addb((bufs), (sym)); \
--(avail); \
} else { \
rv = nghttp2_bufs_addb((bufs), (sym)); \
if (rv != 0) { \
return rv; \
} \
(avail) = nghttp2_bufs_cur_avail((bufs)); \
} \
} while (0)
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_bufs *bufs, const uint8_t *src,
size_t srclen, int final) {
size_t i, j;
size_t i;
int rv;
size_t avail;
@@ -180,30 +197,28 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
/* We use the decoding algorithm described in
http://graphics.ics.uci.edu/pub/Prefix.pdf */
for (i = 0; i < srclen; ++i) {
uint8_t in = src[i] >> 4;
for (j = 0; j < 2; ++j) {
const nghttp2_huff_decode *t;
const nghttp2_huff_decode *t;
t = &huff_decode_table[ctx->state][in];
if (t->flags & NGHTTP2_HUFF_FAIL) {
return NGHTTP2_ERR_HEADER_COMP;
}
if (t->flags & NGHTTP2_HUFF_SYM) {
if (avail) {
nghttp2_bufs_fast_addb(bufs, t->sym);
--avail;
} else {
rv = nghttp2_bufs_addb(bufs, t->sym);
if (rv != 0) {
return rv;
}
avail = nghttp2_bufs_cur_avail(bufs);
}
}
ctx->state = t->state;
ctx->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
in = src[i] & 0xf;
t = &huff_decode_table[ctx->state][src[i] >> 4];
if (t->flags & NGHTTP2_HUFF_FAIL) {
return NGHTTP2_ERR_HEADER_COMP;
}
if (t->flags & NGHTTP2_HUFF_SYM) {
/* this is macro, and may return from this function on error */
hd_huff_decode_sym_emit(bufs, t->sym, avail);
}
t = &huff_decode_table[t->state][src[i] & 0xf];
if (t->flags & NGHTTP2_HUFF_FAIL) {
return NGHTTP2_ERR_HEADER_COMP;
}
if (t->flags & NGHTTP2_HUFF_SYM) {
/* this is macro, and may return from this function on error */
hd_huff_decode_sym_emit(bufs, t->sym, avail);
}
ctx->state = t->state;
ctx->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
}
if (final && !ctx->accept) {
return NGHTTP2_ERR_HEADER_COMP;

View File

@@ -29,12 +29,16 @@
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <string.h>
#include <nghttp2/nghttp2.h>
#include "nghttp2_mem.h"
#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
/*
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
* network byte order.

View File

@@ -28,11 +28,8 @@
#include <assert.h>
#include <stdio.h>
static int memeq(const void *a, const void *b, size_t n) {
return memcmp(a, b, n) == 0;
}
#define streq(A, B, N) ((sizeof((A)) - 1) == (N) && memeq((A), (B), (N)))
#include "nghttp2_hd.h"
#include "nghttp2_helper.h"
static char downcase(char c) {
return 'A' <= c && c <= 'Z' ? (c - 'A' + 'a') : c;
@@ -50,129 +47,7 @@ static int memieq(const void *a, const void *b, size_t n) {
return 1;
}
#define strieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
typedef enum {
NGHTTP2_TOKEN__AUTHORITY,
NGHTTP2_TOKEN__METHOD,
NGHTTP2_TOKEN__PATH,
NGHTTP2_TOKEN__SCHEME,
NGHTTP2_TOKEN__STATUS,
NGHTTP2_TOKEN_CONNECTION,
NGHTTP2_TOKEN_CONTENT_LENGTH,
NGHTTP2_TOKEN_HOST,
NGHTTP2_TOKEN_KEEP_ALIVE,
NGHTTP2_TOKEN_PROXY_CONNECTION,
NGHTTP2_TOKEN_TE,
NGHTTP2_TOKEN_TRANSFER_ENCODING,
NGHTTP2_TOKEN_UPGRADE,
NGHTTP2_TOKEN_MAXIDX,
} nghttp2_token;
/*
* This function was generated by genlibtokenlookup.py. Inspired by
* h2o header lookup. https://github.com/h2o/h2o
*/
static int lookup_token(const uint8_t *name, size_t namelen) {
switch (namelen) {
case 2:
switch (name[namelen - 1]) {
case 'e':
if (streq("t", name, 1)) {
return NGHTTP2_TOKEN_TE;
}
break;
}
break;
case 4:
switch (name[namelen - 1]) {
case 't':
if (streq("hos", name, 3)) {
return NGHTTP2_TOKEN_HOST;
}
break;
}
break;
case 5:
switch (name[namelen - 1]) {
case 'h':
if (streq(":pat", name, 4)) {
return NGHTTP2_TOKEN__PATH;
}
break;
}
break;
case 7:
switch (name[namelen - 1]) {
case 'd':
if (streq(":metho", name, 6)) {
return NGHTTP2_TOKEN__METHOD;
}
break;
case 'e':
if (streq(":schem", name, 6)) {
return NGHTTP2_TOKEN__SCHEME;
}
if (streq("upgrad", name, 6)) {
return NGHTTP2_TOKEN_UPGRADE;
}
break;
case 's':
if (streq(":statu", name, 6)) {
return NGHTTP2_TOKEN__STATUS;
}
break;
}
break;
case 10:
switch (name[namelen - 1]) {
case 'e':
if (streq("keep-aliv", name, 9)) {
return NGHTTP2_TOKEN_KEEP_ALIVE;
}
break;
case 'n':
if (streq("connectio", name, 9)) {
return NGHTTP2_TOKEN_CONNECTION;
}
break;
case 'y':
if (streq(":authorit", name, 9)) {
return NGHTTP2_TOKEN__AUTHORITY;
}
break;
}
break;
case 14:
switch (name[namelen - 1]) {
case 'h':
if (streq("content-lengt", name, 13)) {
return NGHTTP2_TOKEN_CONTENT_LENGTH;
}
break;
}
break;
case 16:
switch (name[namelen - 1]) {
case 'n':
if (streq("proxy-connectio", name, 15)) {
return NGHTTP2_TOKEN_PROXY_CONNECTION;
}
break;
}
break;
case 17:
switch (name[namelen - 1]) {
case 'g':
if (streq("transfer-encodin", name, 16)) {
return NGHTTP2_TOKEN_TRANSFER_ENCODING;
}
break;
}
break;
}
return -1;
}
#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
static int64_t parse_uint(const uint8_t *s, size_t len) {
int64_t n = 0;
@@ -225,10 +100,20 @@ static int expect_response_body(nghttp2_stream *stream) {
stream->status_code != 204;
}
static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
int trailer) {
int token;
/* For "http" or "https" URIs, OPTIONS request may have "*" in :path
header field to represent system-wide OPTIONS request. Otherwise,
:path header field value must start with "/". This function must
be called after ":method" header field was received. This function
returns nonzero if path is valid.*/
static int check_path(nghttp2_stream *stream) {
return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 ||
((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) ||
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) &&
(stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK)));
}
static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
int token, int trailer) {
if (nv->name[0] == ':') {
if (trailer ||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
@@ -236,8 +121,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
}
}
token = lookup_token(nv->name, nv->namelen);
switch (token) {
case NGHTTP2_TOKEN__AUTHORITY:
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
@@ -248,18 +131,34 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if (streq("HEAD", nv->value, nv->valuelen)) {
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
} else if (streq("CONNECT", nv->value, nv->valuelen)) {
if (stream->stream_id % 2 == 0) {
/* we won't allow CONNECT for push */
return NGHTTP2_ERR_HTTP_HEADER;
switch (nv->valuelen) {
case 4:
if (lstreq("HEAD", nv->value, nv->valuelen)) {
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
}
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
if (stream->http_flags &
(NGHTTP2_HTTP_FLAG__PATH | NGHTTP2_HTTP_FLAG__SCHEME)) {
return NGHTTP2_ERR_HTTP_HEADER;
break;
case 7:
switch (nv->value[6]) {
case 'T':
if (lstreq("CONNECT", nv->value, nv->valuelen)) {
if (stream->stream_id % 2 == 0) {
/* we won't allow CONNECT for push */
return NGHTTP2_ERR_HTTP_HEADER;
}
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
if (stream->http_flags &
(NGHTTP2_HTTP_FLAG__PATH | NGHTTP2_HTTP_FLAG__SCHEME)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
}
break;
case 'S':
if (lstreq("OPTIONS", nv->value, nv->valuelen)) {
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_OPTIONS;
}
break;
}
break;
}
break;
case NGHTTP2_TOKEN__PATH:
@@ -269,6 +168,11 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if (nv->value[0] == '/') {
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR;
} else if (nv->valuelen == 1 && nv->value[0] == '*') {
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK;
}
break;
case NGHTTP2_TOKEN__SCHEME:
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
@@ -277,6 +181,10 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if ((nv->valuelen == 4 && memieq("http", nv->value, 4)) ||
(nv->valuelen == 5 && memieq("https", nv->value, 5))) {
stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP;
}
break;
case NGHTTP2_TOKEN_HOST:
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
@@ -301,7 +209,7 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
case NGHTTP2_TOKEN_UPGRADE:
return NGHTTP2_ERR_HTTP_HEADER;
case NGHTTP2_TOKEN_TE:
if (!strieq("trailers", nv->value, nv->valuelen)) {
if (!lstrieq("trailers", nv->value, nv->valuelen)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
break;
@@ -319,9 +227,7 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
}
static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
int trailer) {
int token;
int token, int trailer) {
if (nv->name[0] == ':') {
if (trailer ||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
@@ -329,8 +235,6 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
}
}
token = lookup_token(nv->name, nv->namelen);
switch (token) {
case NGHTTP2_TOKEN__STATUS: {
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
@@ -363,7 +267,7 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
case NGHTTP2_TOKEN_UPGRADE:
return NGHTTP2_ERR_HTTP_HEADER;
case NGHTTP2_TOKEN_TE:
if (!strieq("trailers", nv->value, nv->valuelen)) {
if (!lstrieq("trailers", nv->value, nv->valuelen)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
break;
@@ -381,7 +285,8 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
}
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
nghttp2_frame *frame, nghttp2_nv *nv, int trailer) {
nghttp2_frame *frame, nghttp2_nv *nv, int token,
int trailer) {
/* We are strict for pseudo header field. One bad character should
lead to fail. OTOH, we should be a bit forgiving for regular
headers, since existing public internet has so much illegal
@@ -421,10 +326,10 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
}
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
return http_request_on_header(stream, nv, trailer);
return http_request_on_header(stream, nv, token, trailer);
}
return http_response_on_header(stream, nv, trailer);
return http_response_on_header(stream, nv, token, trailer);
}
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
@@ -434,11 +339,16 @@ int nghttp2_http_on_request_headers(nghttp2_stream *stream,
return -1;
}
stream->content_length = -1;
} else if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
(stream->http_flags &
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
return -1;
} else {
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
(stream->http_flags &
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
return -1;
}
if (!check_path(stream)) {
return -1;
}
}
if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
@@ -532,14 +442,15 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream,
/* TODO we should do this strictly. */
for (i = 0; i < nvlen; ++i) {
const nghttp2_nv *nv = &nva[i];
if (lookup_token(nv->name, nv->namelen) != NGHTTP2_TOKEN__METHOD) {
if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
continue;
}
if (streq("CONNECT", nv->value, nv->valuelen)) {
if (lstreq("CONNECT", nv->value, nv->valuelen)) {
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
return;
}
if (streq("HEAD", nv->value, nv->valuelen)) {
if (lstreq("HEAD", nv->value, nv->valuelen)) {
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
return;
}

View File

@@ -36,7 +36,8 @@
/*
* This function is called when HTTP header field |nv| in |frame| is
* received for |stream|. This function will validate |nv| against
* the current state of stream.
* the current state of stream. The |token| is nghttp2_token value
* for nv->name, or -1 if we don't have enum value for the name.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -48,7 +49,8 @@
* if it was not received because of compatibility reasons.
*/
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
nghttp2_frame *frame, nghttp2_nv *nv, int trailer);
nghttp2_frame *frame, nghttp2_nv *nv, int token,
int trailer);
/*
* This function is called when request header is received. This

View File

@@ -39,7 +39,8 @@
} while (0)
#endif
typedef int (*nghttp2_compar)(const void *lhs, const void *rhs);
/* "less" function, return nonzero if |lhs| is less than |rhs|. */
typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
/* Internal error code. They must be in the range [-499, -100],
inclusive. */
@@ -51,7 +52,7 @@ typedef enum {
* Invalid HTTP header field was received but it can be treated as
* if it was not received because of compatibility reasons.
*/
NGHTTP2_ERR_IGN_HTTP_HEADER = -105,
NGHTTP2_ERR_IGN_HTTP_HEADER = -105
} nghttp2_internal_error;
#endif /* NGHTTP2_INT_H */

View File

@@ -37,8 +37,55 @@
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#endif /* HAVE_WINSOCK2_H */
#include <nghttp2/nghttp2.h>
#if defined(WIN32)
/* Windows requires ws2_32 library for ntonl family functions. We
define inline functions for those function so that we don't have
dependeny on that lib. */
#ifdef _MSC_VER
#define STIN static __inline
#else
#define STIN static inline
#endif
STIN uint32_t htonl(uint32_t hostlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&res;
*p++ = hostlong >> 24;
*p++ = (hostlong >> 16) & 0xffu;
*p++ = (hostlong >> 8) & 0xffu;
*p = hostlong & 0xffu;
return res;
}
STIN uint16_t htons(uint16_t hostshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&res;
*p++ = hostshort >> 8;
*p = hostshort & 0xffu;
return res;
}
STIN uint32_t ntohl(uint32_t netlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&netlong;
res = *p++ << 24;
res += *p++ << 16;
res += *p++ << 8;
res += *p;
return res;
}
STIN uint16_t ntohs(uint16_t netshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&netshort;
res = *p++ << 8;
res += *p;
return res;
}
#endif /* WIN32 */
#endif /* NGHTTP2_NET_H */

View File

@@ -58,7 +58,7 @@ typedef enum {
*/
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
NGHTTP2_OPT_RECV_CLIENT_PREFACE = 1 << 2,
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3
} nghttp2_option_flag;
/**

View File

@@ -25,6 +25,15 @@
#include "nghttp2_outbound_item.h"
#include <assert.h>
#include <string.h>
void nghttp2_outbound_item_init(nghttp2_outbound_item *item) {
item->cycle = 0;
item->qnext = NULL;
item->queued = 0;
memset(&item->aux_data, 0, sizeof(nghttp2_aux_data));
}
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
nghttp2_frame *frame;
@@ -65,3 +74,32 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
break;
}
}
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q) {
q->head = q->tail = NULL;
q->n = 0;
}
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
nghttp2_outbound_item *item) {
if (q->tail) {
q->tail = q->tail->qnext = item;
} else {
q->head = q->tail = item;
}
++q->n;
}
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q) {
nghttp2_outbound_item *item;
if (!q->head) {
return;
}
item = q->head;
q->head = q->head->qnext;
item->qnext = NULL;
if (!q->head) {
q->tail = NULL;
}
--q->n;
}

View File

@@ -33,13 +33,6 @@
#include "nghttp2_frame.h"
#include "nghttp2_mem.h"
/* A bit higher weight for non-DATA frames */
#define NGHTTP2_OB_EX_WEIGHT 300
/* Higher weight for SETTINGS */
#define NGHTTP2_OB_SETTINGS_WEIGHT 301
/* 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;
@@ -74,6 +67,10 @@ typedef struct {
* |eof| is 0. It becomes 1 after all data were read.
*/
uint8_t eof;
/**
* The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used.
*/
uint8_t no_copy;
} nghttp2_data_aux_data;
typedef enum {
@@ -84,7 +81,7 @@ typedef enum {
/* indicates that this GOAWAY is just a notification for graceful
shutdown. No nghttp2_session.goaway_flags should be updated on
the reaction to this frame. */
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2,
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2
} nghttp2_goaway_aux_flag;
/* struct used for GOAWAY frame */
@@ -100,19 +97,31 @@ typedef union {
nghttp2_goaway_aux_data goaway;
} nghttp2_aux_data;
typedef struct {
struct nghttp2_outbound_item;
typedef struct nghttp2_outbound_item nghttp2_outbound_item;
struct nghttp2_outbound_item {
nghttp2_frame frame;
nghttp2_aux_data aux_data;
int64_t seq;
/* Reset count of weight. See comment for last_cycle in
nghttp2_session.h */
/* The priority used in priority comparion. Smaller is served
ealier. For PING, SETTINGS and non-DATA frames (excluding
response HEADERS frame) have dedicated cycle value defined above.
For DATA frame, cycle is computed by taking into account of
effective weight and frame payload length previously sent, so
that the amount of transmission is distributed across streams
proportional to effective weight (inside a tree). */
uint64_t cycle;
/* The priority used in priority comparion. Larger is served
ealier. */
int32_t weight;
nghttp2_outbound_item *qnext;
/* nonzero if this object is queued. */
uint8_t queued;
} nghttp2_outbound_item;
};
/*
* Initializes |item|. No memory allocation is done in this function.
* Don't call nghttp2_outbound_item_free() until frame member is
* initialized.
*/
void nghttp2_outbound_item_init(nghttp2_outbound_item *item);
/*
* Deallocates resource for |item|. If |item| is NULL, this function
@@ -120,4 +129,29 @@ typedef struct {
*/
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem);
/*
* queue for nghttp2_outbound_item.
*/
typedef struct {
nghttp2_outbound_item *head, *tail;
/* number of items in this queue. */
size_t n;
} nghttp2_outbound_queue;
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q);
/* Pushes |item| into |q| */
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
nghttp2_outbound_item *item);
/* Pops |item| at the top from |q|. If |q| is empty, nothing
happens. */
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q);
/* Returns the top item. */
#define nghttp2_outbound_queue_top(Q) ((Q)->head)
/* Returns the size of the queue */
#define nghttp2_outbound_queue_size(Q) ((Q)->n)
#endif /* NGHTTP2_OUTBOUND_ITEM_H */

View File

@@ -24,7 +24,7 @@
*/
#include "nghttp2_pq.h"
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar compar, nghttp2_mem *mem) {
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
pq->mem = mem;
pq->capacity = 128;
pq->q = nghttp2_mem_malloc(mem, pq->capacity * sizeof(void *));
@@ -32,7 +32,7 @@ int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar compar, nghttp2_mem *mem) {
return NGHTTP2_ERR_NOMEM;
}
pq->length = 0;
pq->compar = compar;
pq->less = less;
return 0;
}
@@ -52,7 +52,7 @@ static void bubble_up(nghttp2_pq *pq, size_t index) {
return;
} else {
size_t parent = (index - 1) / 2;
if (pq->compar(pq->q[parent], pq->q[index]) > 0) {
if (pq->less(pq->q[index], pq->q[parent])) {
swap(pq, parent, index);
bubble_up(pq, parent);
}
@@ -93,7 +93,7 @@ static void bubble_down(nghttp2_pq *pq, size_t index) {
if (j >= pq->length) {
break;
}
if (pq->compar(pq->q[minindex], pq->q[j]) > 0) {
if (pq->less(pq->q[j], pq->q[minindex])) {
minindex = j;
}
}

View File

@@ -45,8 +45,8 @@ typedef struct {
/* The maximum number of items this pq can store. This is
automatically extended when length is reached to this value. */
size_t capacity;
/* The compare function between items */
nghttp2_compar compar;
/* The less function between items */
nghttp2_less less;
} nghttp2_pq;
/*
@@ -58,7 +58,7 @@ typedef struct {
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar cmp, nghttp2_mem *mem);
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |pq|. The stored items are

File diff suppressed because it is too large Load Diff

View File

@@ -47,12 +47,13 @@
typedef enum {
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2
} nghttp2_optmask;
typedef enum {
NGHTTP2_OB_POP_ITEM,
NGHTTP2_OB_SEND_DATA
NGHTTP2_OB_SEND_DATA,
NGHTTP2_OB_SEND_NO_COPY
} nghttp2_outbound_state;
typedef struct {
@@ -83,7 +84,7 @@ typedef enum {
NGHTTP2_IB_READ_PAD_DATA,
NGHTTP2_IB_READ_DATA,
NGHTTP2_IB_IGN_DATA,
NGHTTP2_IB_IGN_ALL,
NGHTTP2_IB_IGN_ALL
} nghttp2_inbound_state;
#define NGHTTP2_INBOUND_NUM_IV 7
@@ -135,18 +136,21 @@ typedef enum {
/* Flag means GOAWAY was sent */
NGHTTP2_GOAWAY_SENT = 0x4,
/* Flag means GOAWAY was received */
NGHTTP2_GOAWAY_RECV = 0x8,
NGHTTP2_GOAWAY_RECV = 0x8
} nghttp2_goaway_flag;
struct nghttp2_session {
nghttp2_map /* <nghttp2_stream*> */ streams;
nghttp2_stream_roots roots;
/* 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 */
/* Queue for outbound urgent frames (PING and SETTINGS) */
nghttp2_outbound_queue ob_urgent;
/* Queue for non-DATA frames */
nghttp2_outbound_queue ob_reg;
/* Queue for outbound stream-creating HEADERS (request or push
response) frame, which are subject to
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
nghttp2_outbound_queue ob_syn;
/* Queue for DATA frame */
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_da_pq;
nghttp2_active_outbound_item aob;
nghttp2_inbound_frame iframe;
@@ -155,22 +159,8 @@ struct nghttp2_session {
nghttp2_session_callbacks callbacks;
/* Memory allocator */
nghttp2_mem mem;
/* Sequence number of outbound frame to maintain the order of
enqueue if priority is equal. */
int64_t next_seq;
/* Reset count of nghttp2_outbound_item's weight. We decrements
weight each time DATA is sent to simulate resource sharing. We
use priority queue and larger weight has the precedence. If
weight is reached to lowest weight, it resets to its initial
weight. If this happens, other items which have the lower weight
currently but same initial weight cannot send DATA until item
having large weight is decreased. To avoid this, we use this
cycle variable. Initally, this is set to 1. If weight gets
lowest weight, and if item's cycle == last_cycle, we increments
last_cycle and assigns it to item's cycle. Otherwise, just
assign last_cycle. In priority queue comparator, we first
compare items' cycle value. Lower cycle value has the
precedence. */
/* Base value when we schedule next DATA frame write. This is
updated when one frame was written. */
uint64_t last_cycle;
void *user_data;
/* Points to the latest closed stream. NULL if there is no closed
@@ -290,14 +280,6 @@ typedef struct {
int nghttp2_session_is_my_stream_id(nghttp2_session *session,
int32_t stream_id);
/*
* 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
@@ -703,13 +685,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_frame *frame,
nghttp2_data_aux_data *aux_data);
/*
* Returns top of outbound frame queue. This function returns NULL if
* queue is empty.
*/
nghttp2_outbound_item *nghttp2_session_get_ob_pq_top(nghttp2_session *session);
nghttp2_data_aux_data *aux_data,
nghttp2_stream *stream);
/*
* Pops and returns next item to send. If there is no such item,

View File

@@ -63,7 +63,6 @@ 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;
@@ -87,7 +86,8 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
}
static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
int rv;
/* This is required for Android NDK r10d */
int rv = 0;
nghttp2_outbound_item *item;
assert(stream->item);
@@ -101,33 +101,33 @@ static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
return 0;
}
if (item->weight > stream->effective_weight) {
item->weight = stream->effective_weight;
}
item->cycle = session->last_cycle;
switch (item->frame.hd.type) {
case NGHTTP2_DATA:
/* Penalize item by delaying scheduling according to effective
weight. This will delay low priority stream, which is good.
OTOH, this may incur delay for high priority item. Will
see. */
item->cycle =
session->last_cycle +
NGHTTP2_DATA_PAYLOADLEN * NGHTTP2_MAX_WEIGHT / stream->effective_weight;
rv = nghttp2_pq_push(&session->ob_da_pq, item);
if (rv != 0) {
return rv;
}
break;
case NGHTTP2_HEADERS:
if (stream->state == NGHTTP2_STREAM_RESERVED) {
rv = nghttp2_pq_push(&session->ob_ss_pq, item);
nghttp2_outbound_queue_push(&session->ob_syn, item);
} else {
rv = nghttp2_pq_push(&session->ob_pq, item);
nghttp2_outbound_queue_push(&session->ob_reg, item);
}
break;
default:
rv = 0;
/* should not reach here */
assert(0);
}
if (rv != 0) {
return rv;
}
item->queued = 1;
return 0;
@@ -178,18 +178,6 @@ int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
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
@@ -199,10 +187,9 @@ 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, "
"sum_top_weight=%d\n",
"stream(%p)=%d, weight=%d, sum_norest_weight=%d\n",
stream, stream->stream_id, stream->weight,
stream->sum_norest_weight, stream->sum_top_weight));
stream->sum_norest_weight));
/* stream->sum_norest_weight == 0 means there is no
NGHTTP2_STREAM_DPRI_TOP under stream */
@@ -211,47 +198,13 @@ 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_TOP) {
if (si->dpri != NGHTTP2_STREAM_DPRI_REST) {
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;
nghttp2_stream_dep_distributed_effective_weight(stream, si->weight);
}
if (si->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM) {
DEBUGF(fprintf(stderr, "stream: stream=%d no_item, 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));
}
stream_update_dep_effective_weight(si);
}
}
@@ -347,25 +300,20 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
}
/*
* 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_ITEM, 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.
* Updates stream->sum_norest_weight recursively. We have to gather
* effective sum of weight of descendants. If stream->dpri ==
* NGHTTP2_STREAM_DPRI_NO_ITEM, 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.
*/
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) {
nghttp2_stream *si;
int rv;
stream->sum_norest_weight = 0;
stream->sum_top_weight = 0;
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return 1;
@@ -383,10 +331,6 @@ 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;

View File

@@ -120,10 +120,20 @@ typedef enum {
/* HTTP method flags */
NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
NGHTTP2_HTTP_FLAG_METH_ALL =
NGHTTP2_HTTP_FLAG_METH_CONNECT | NGHTTP2_HTTP_FLAG_METH_HEAD,
NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT |
NGHTTP2_HTTP_FLAG_METH_HEAD |
NGHTTP2_HTTP_FLAG_METH_OPTIONS,
/* :path category */
/* path starts with "/" */
NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 10,
/* path "*" */
NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 11,
/* scheme */
/* "http" or "https" scheme */
NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 12,
/* set if final response is expected */
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 9,
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 13
} nghttp2_http_flag;
typedef enum {
@@ -144,6 +154,10 @@ typedef struct nghttp2_stream nghttp2_stream;
struct nghttp2_stream {
/* Intrusive Map */
nghttp2_map_entry map_entry;
/* Content-Length of request/response body. -1 if unknown. */
int64_t content_length;
/* Received body so far */
int64_t recv_content_length;
/* pointers to form dependency tree. If multiple streams depend on
a stream, only one stream (left most) has non-NULL dep_prev which
points to the stream it depends on. The remaining streams are
@@ -203,22 +217,15 @@ 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;
/* Bitwise OR of zero or more nghttp2_shut_flag values */
uint8_t shut_flags;
/* Content-Length of request/response body. -1 if unknown. */
int64_t content_length;
/* Received body so far */
int64_t recv_content_length;
/* status code from remote server */
int16_t status_code;
/* Bitwise OR of zero or more nghttp2_http_flag values */
uint16_t http_flags;
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
uint8_t flags;
/* Bitwise OR of zero or more nghttp2_shut_flag values */
uint8_t shut_flags;
};
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,

View File

@@ -62,7 +62,7 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
goto fail;
}
nghttp2_session_outbound_item_init(session, item);
nghttp2_outbound_item_init(item);
if (data_prd != NULL && data_prd->read_callback != NULL) {
item->aux_data.headers.data_prd = *data_prd;
@@ -212,7 +212,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
return NGHTTP2_ERR_NOMEM;
}
nghttp2_session_outbound_item_init(session, item);
nghttp2_outbound_item_init(item);
frame = &item->frame;
@@ -299,7 +299,7 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
return NGHTTP2_ERR_NOMEM;
}
nghttp2_session_outbound_item_init(session, item);
nghttp2_outbound_item_init(item);
item->aux_data.headers.stream_user_data = promised_stream_user_data;
@@ -453,7 +453,7 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
return NGHTTP2_ERR_NOMEM;
}
nghttp2_session_outbound_item_init(session, item);
nghttp2_outbound_item_init(item);
frame = &item->frame;
aux_data = &item->aux_data.data;

View File

@@ -10,8 +10,271 @@
from __future__ import unicode_literals
import re
import sys
import StringIO
# From [1]
HUFFMAN_CODE_TABLE = """\
( 0) |11111111|11000 1ff8 [13]
( 1) |11111111|11111111|1011000 7fffd8 [23]
( 2) |11111111|11111111|11111110|0010 fffffe2 [28]
( 3) |11111111|11111111|11111110|0011 fffffe3 [28]
( 4) |11111111|11111111|11111110|0100 fffffe4 [28]
( 5) |11111111|11111111|11111110|0101 fffffe5 [28]
( 6) |11111111|11111111|11111110|0110 fffffe6 [28]
( 7) |11111111|11111111|11111110|0111 fffffe7 [28]
( 8) |11111111|11111111|11111110|1000 fffffe8 [28]
( 9) |11111111|11111111|11101010 ffffea [24]
( 10) |11111111|11111111|11111111|111100 3ffffffc [30]
( 11) |11111111|11111111|11111110|1001 fffffe9 [28]
( 12) |11111111|11111111|11111110|1010 fffffea [28]
( 13) |11111111|11111111|11111111|111101 3ffffffd [30]
( 14) |11111111|11111111|11111110|1011 fffffeb [28]
( 15) |11111111|11111111|11111110|1100 fffffec [28]
( 16) |11111111|11111111|11111110|1101 fffffed [28]
( 17) |11111111|11111111|11111110|1110 fffffee [28]
( 18) |11111111|11111111|11111110|1111 fffffef [28]
( 19) |11111111|11111111|11111111|0000 ffffff0 [28]
( 20) |11111111|11111111|11111111|0001 ffffff1 [28]
( 21) |11111111|11111111|11111111|0010 ffffff2 [28]
( 22) |11111111|11111111|11111111|111110 3ffffffe [30]
( 23) |11111111|11111111|11111111|0011 ffffff3 [28]
( 24) |11111111|11111111|11111111|0100 ffffff4 [28]
( 25) |11111111|11111111|11111111|0101 ffffff5 [28]
( 26) |11111111|11111111|11111111|0110 ffffff6 [28]
( 27) |11111111|11111111|11111111|0111 ffffff7 [28]
( 28) |11111111|11111111|11111111|1000 ffffff8 [28]
( 29) |11111111|11111111|11111111|1001 ffffff9 [28]
( 30) |11111111|11111111|11111111|1010 ffffffa [28]
( 31) |11111111|11111111|11111111|1011 ffffffb [28]
' ' ( 32) |010100 14 [ 6]
'!' ( 33) |11111110|00 3f8 [10]
'"' ( 34) |11111110|01 3f9 [10]
'#' ( 35) |11111111|1010 ffa [12]
'$' ( 36) |11111111|11001 1ff9 [13]
'%' ( 37) |010101 15 [ 6]
'&' ( 38) |11111000 f8 [ 8]
''' ( 39) |11111111|010 7fa [11]
'(' ( 40) |11111110|10 3fa [10]
')' ( 41) |11111110|11 3fb [10]
'*' ( 42) |11111001 f9 [ 8]
'+' ( 43) |11111111|011 7fb [11]
',' ( 44) |11111010 fa [ 8]
'-' ( 45) |010110 16 [ 6]
'.' ( 46) |010111 17 [ 6]
'/' ( 47) |011000 18 [ 6]
'0' ( 48) |00000 0 [ 5]
'1' ( 49) |00001 1 [ 5]
'2' ( 50) |00010 2 [ 5]
'3' ( 51) |011001 19 [ 6]
'4' ( 52) |011010 1a [ 6]
'5' ( 53) |011011 1b [ 6]
'6' ( 54) |011100 1c [ 6]
'7' ( 55) |011101 1d [ 6]
'8' ( 56) |011110 1e [ 6]
'9' ( 57) |011111 1f [ 6]
':' ( 58) |1011100 5c [ 7]
';' ( 59) |11111011 fb [ 8]
'<' ( 60) |11111111|1111100 7ffc [15]
'=' ( 61) |100000 20 [ 6]
'>' ( 62) |11111111|1011 ffb [12]
'?' ( 63) |11111111|00 3fc [10]
'@' ( 64) |11111111|11010 1ffa [13]
'A' ( 65) |100001 21 [ 6]
'B' ( 66) |1011101 5d [ 7]
'C' ( 67) |1011110 5e [ 7]
'D' ( 68) |1011111 5f [ 7]
'E' ( 69) |1100000 60 [ 7]
'F' ( 70) |1100001 61 [ 7]
'G' ( 71) |1100010 62 [ 7]
'H' ( 72) |1100011 63 [ 7]
'I' ( 73) |1100100 64 [ 7]
'J' ( 74) |1100101 65 [ 7]
'K' ( 75) |1100110 66 [ 7]
'L' ( 76) |1100111 67 [ 7]
'M' ( 77) |1101000 68 [ 7]
'N' ( 78) |1101001 69 [ 7]
'O' ( 79) |1101010 6a [ 7]
'P' ( 80) |1101011 6b [ 7]
'Q' ( 81) |1101100 6c [ 7]
'R' ( 82) |1101101 6d [ 7]
'S' ( 83) |1101110 6e [ 7]
'T' ( 84) |1101111 6f [ 7]
'U' ( 85) |1110000 70 [ 7]
'V' ( 86) |1110001 71 [ 7]
'W' ( 87) |1110010 72 [ 7]
'X' ( 88) |11111100 fc [ 8]
'Y' ( 89) |1110011 73 [ 7]
'Z' ( 90) |11111101 fd [ 8]
'[' ( 91) |11111111|11011 1ffb [13]
'\' ( 92) |11111111|11111110|000 7fff0 [19]
']' ( 93) |11111111|11100 1ffc [13]
'^' ( 94) |11111111|111100 3ffc [14]
'_' ( 95) |100010 22 [ 6]
'`' ( 96) |11111111|1111101 7ffd [15]
'a' ( 97) |00011 3 [ 5]
'b' ( 98) |100011 23 [ 6]
'c' ( 99) |00100 4 [ 5]
'd' (100) |100100 24 [ 6]
'e' (101) |00101 5 [ 5]
'f' (102) |100101 25 [ 6]
'g' (103) |100110 26 [ 6]
'h' (104) |100111 27 [ 6]
'i' (105) |00110 6 [ 5]
'j' (106) |1110100 74 [ 7]
'k' (107) |1110101 75 [ 7]
'l' (108) |101000 28 [ 6]
'm' (109) |101001 29 [ 6]
'n' (110) |101010 2a [ 6]
'o' (111) |00111 7 [ 5]
'p' (112) |101011 2b [ 6]
'q' (113) |1110110 76 [ 7]
'r' (114) |101100 2c [ 6]
's' (115) |01000 8 [ 5]
't' (116) |01001 9 [ 5]
'u' (117) |101101 2d [ 6]
'v' (118) |1110111 77 [ 7]
'w' (119) |1111000 78 [ 7]
'x' (120) |1111001 79 [ 7]
'y' (121) |1111010 7a [ 7]
'z' (122) |1111011 7b [ 7]
'{' (123) |11111111|1111110 7ffe [15]
'|' (124) |11111111|100 7fc [11]
'}' (125) |11111111|111101 3ffd [14]
'~' (126) |11111111|11101 1ffd [13]
(127) |11111111|11111111|11111111|1100 ffffffc [28]
(128) |11111111|11111110|0110 fffe6 [20]
(129) |11111111|11111111|010010 3fffd2 [22]
(130) |11111111|11111110|0111 fffe7 [20]
(131) |11111111|11111110|1000 fffe8 [20]
(132) |11111111|11111111|010011 3fffd3 [22]
(133) |11111111|11111111|010100 3fffd4 [22]
(134) |11111111|11111111|010101 3fffd5 [22]
(135) |11111111|11111111|1011001 7fffd9 [23]
(136) |11111111|11111111|010110 3fffd6 [22]
(137) |11111111|11111111|1011010 7fffda [23]
(138) |11111111|11111111|1011011 7fffdb [23]
(139) |11111111|11111111|1011100 7fffdc [23]
(140) |11111111|11111111|1011101 7fffdd [23]
(141) |11111111|11111111|1011110 7fffde [23]
(142) |11111111|11111111|11101011 ffffeb [24]
(143) |11111111|11111111|1011111 7fffdf [23]
(144) |11111111|11111111|11101100 ffffec [24]
(145) |11111111|11111111|11101101 ffffed [24]
(146) |11111111|11111111|010111 3fffd7 [22]
(147) |11111111|11111111|1100000 7fffe0 [23]
(148) |11111111|11111111|11101110 ffffee [24]
(149) |11111111|11111111|1100001 7fffe1 [23]
(150) |11111111|11111111|1100010 7fffe2 [23]
(151) |11111111|11111111|1100011 7fffe3 [23]
(152) |11111111|11111111|1100100 7fffe4 [23]
(153) |11111111|11111110|11100 1fffdc [21]
(154) |11111111|11111111|011000 3fffd8 [22]
(155) |11111111|11111111|1100101 7fffe5 [23]
(156) |11111111|11111111|011001 3fffd9 [22]
(157) |11111111|11111111|1100110 7fffe6 [23]
(158) |11111111|11111111|1100111 7fffe7 [23]
(159) |11111111|11111111|11101111 ffffef [24]
(160) |11111111|11111111|011010 3fffda [22]
(161) |11111111|11111110|11101 1fffdd [21]
(162) |11111111|11111110|1001 fffe9 [20]
(163) |11111111|11111111|011011 3fffdb [22]
(164) |11111111|11111111|011100 3fffdc [22]
(165) |11111111|11111111|1101000 7fffe8 [23]
(166) |11111111|11111111|1101001 7fffe9 [23]
(167) |11111111|11111110|11110 1fffde [21]
(168) |11111111|11111111|1101010 7fffea [23]
(169) |11111111|11111111|011101 3fffdd [22]
(170) |11111111|11111111|011110 3fffde [22]
(171) |11111111|11111111|11110000 fffff0 [24]
(172) |11111111|11111110|11111 1fffdf [21]
(173) |11111111|11111111|011111 3fffdf [22]
(174) |11111111|11111111|1101011 7fffeb [23]
(175) |11111111|11111111|1101100 7fffec [23]
(176) |11111111|11111111|00000 1fffe0 [21]
(177) |11111111|11111111|00001 1fffe1 [21]
(178) |11111111|11111111|100000 3fffe0 [22]
(179) |11111111|11111111|00010 1fffe2 [21]
(180) |11111111|11111111|1101101 7fffed [23]
(181) |11111111|11111111|100001 3fffe1 [22]
(182) |11111111|11111111|1101110 7fffee [23]
(183) |11111111|11111111|1101111 7fffef [23]
(184) |11111111|11111110|1010 fffea [20]
(185) |11111111|11111111|100010 3fffe2 [22]
(186) |11111111|11111111|100011 3fffe3 [22]
(187) |11111111|11111111|100100 3fffe4 [22]
(188) |11111111|11111111|1110000 7ffff0 [23]
(189) |11111111|11111111|100101 3fffe5 [22]
(190) |11111111|11111111|100110 3fffe6 [22]
(191) |11111111|11111111|1110001 7ffff1 [23]
(192) |11111111|11111111|11111000|00 3ffffe0 [26]
(193) |11111111|11111111|11111000|01 3ffffe1 [26]
(194) |11111111|11111110|1011 fffeb [20]
(195) |11111111|11111110|001 7fff1 [19]
(196) |11111111|11111111|100111 3fffe7 [22]
(197) |11111111|11111111|1110010 7ffff2 [23]
(198) |11111111|11111111|101000 3fffe8 [22]
(199) |11111111|11111111|11110110|0 1ffffec [25]
(200) |11111111|11111111|11111000|10 3ffffe2 [26]
(201) |11111111|11111111|11111000|11 3ffffe3 [26]
(202) |11111111|11111111|11111001|00 3ffffe4 [26]
(203) |11111111|11111111|11111011|110 7ffffde [27]
(204) |11111111|11111111|11111011|111 7ffffdf [27]
(205) |11111111|11111111|11111001|01 3ffffe5 [26]
(206) |11111111|11111111|11110001 fffff1 [24]
(207) |11111111|11111111|11110110|1 1ffffed [25]
(208) |11111111|11111110|010 7fff2 [19]
(209) |11111111|11111111|00011 1fffe3 [21]
(210) |11111111|11111111|11111001|10 3ffffe6 [26]
(211) |11111111|11111111|11111100|000 7ffffe0 [27]
(212) |11111111|11111111|11111100|001 7ffffe1 [27]
(213) |11111111|11111111|11111001|11 3ffffe7 [26]
(214) |11111111|11111111|11111100|010 7ffffe2 [27]
(215) |11111111|11111111|11110010 fffff2 [24]
(216) |11111111|11111111|00100 1fffe4 [21]
(217) |11111111|11111111|00101 1fffe5 [21]
(218) |11111111|11111111|11111010|00 3ffffe8 [26]
(219) |11111111|11111111|11111010|01 3ffffe9 [26]
(220) |11111111|11111111|11111111|1101 ffffffd [28]
(221) |11111111|11111111|11111100|011 7ffffe3 [27]
(222) |11111111|11111111|11111100|100 7ffffe4 [27]
(223) |11111111|11111111|11111100|101 7ffffe5 [27]
(224) |11111111|11111110|1100 fffec [20]
(225) |11111111|11111111|11110011 fffff3 [24]
(226) |11111111|11111110|1101 fffed [20]
(227) |11111111|11111111|00110 1fffe6 [21]
(228) |11111111|11111111|101001 3fffe9 [22]
(229) |11111111|11111111|00111 1fffe7 [21]
(230) |11111111|11111111|01000 1fffe8 [21]
(231) |11111111|11111111|1110011 7ffff3 [23]
(232) |11111111|11111111|101010 3fffea [22]
(233) |11111111|11111111|101011 3fffeb [22]
(234) |11111111|11111111|11110111|0 1ffffee [25]
(235) |11111111|11111111|11110111|1 1ffffef [25]
(236) |11111111|11111111|11110100 fffff4 [24]
(237) |11111111|11111111|11110101 fffff5 [24]
(238) |11111111|11111111|11111010|10 3ffffea [26]
(239) |11111111|11111111|1110100 7ffff4 [23]
(240) |11111111|11111111|11111010|11 3ffffeb [26]
(241) |11111111|11111111|11111100|110 7ffffe6 [27]
(242) |11111111|11111111|11111011|00 3ffffec [26]
(243) |11111111|11111111|11111011|01 3ffffed [26]
(244) |11111111|11111111|11111100|111 7ffffe7 [27]
(245) |11111111|11111111|11111101|000 7ffffe8 [27]
(246) |11111111|11111111|11111101|001 7ffffe9 [27]
(247) |11111111|11111111|11111101|010 7ffffea [27]
(248) |11111111|11111111|11111101|011 7ffffeb [27]
(249) |11111111|11111111|11111111|1110 ffffffe [28]
(250) |11111111|11111111|11111101|100 7ffffec [27]
(251) |11111111|11111111|11111101|101 7ffffed [27]
(252) |11111111|11111111|11111101|110 7ffffee [27]
(253) |11111111|11111111|11111101|111 7ffffef [27]
(254) |11111111|11111111|11111110|000 7fffff0 [27]
(255) |11111111|11111111|11111011|10 3ffffee [26]
EOS (256) |11111111|11111111|11111111|111111 3fffffff [30]
"""
class Node:
def __init__(self, term = None):
self.term = term
self.left = None
@@ -20,21 +283,18 @@ class Node:
self.id = None
self.accept = False
def to_bin(s):
res = []
for i in range(0, len(s), 8):
x = s[i:i+8]
x += '0'*(8 - len(x))
a = 0
for j in range(8):
a *= 2
a += ord(x[j]) - ord('0')
res.append(a) #chr(a))
return res
class Context:
nodes = []
def __init__(self):
self.next_id_ = 0
self.root = Node()
def insert(node, sym, bits):
def next_id(self):
id = self.next_id_
self.next_id_ += 1
return id
def _add(node, sym, bits):
if len(bits) == 0:
node.term = sym
return
@@ -47,67 +307,71 @@ def insert(node, sym, bits):
if node.right is None:
node.right = Node()
child = node.right
insert(child, sym, bits[1:])
_add(child, sym, bits[1:])
def traverse(node, bits, syms, start_node, root, depth):
if depth == 4:
if 256 in syms:
syms = []
def huffman_tree_add(ctx, sym, bits):
_add(ctx.root, sym, bits)
def _set_node_id(ctx, node, prefix):
if node.term is not None:
return
if len(prefix) <= 7 and [1] * len(prefix) == prefix:
node.accept = True
node.id = ctx.next_id()
_set_node_id(ctx, node.left, prefix + [0])
_set_node_id(ctx, node.right, prefix + [1])
def huffman_tree_set_node_id(ctx):
_set_node_id(ctx, ctx.root, [])
def _traverse(node, sym, start_node, root, left):
if left == 0:
if sym == 256:
sym = None
node = None
start_node.trans.append((node, bits, syms))
start_node.trans.append((node, sym))
return
if node.term is not None:
node = root
def go(node, bit):
nbits = list(bits)
nbits.append(bit)
nsyms = list(syms)
def go(node):
if node.term is not None:
nsyms.append(node.term)
traverse(node, nbits, nsyms, start_node, root, depth + 1)
assert sym is None
nsym = node.term
else:
nsym = sym
go(node.left, 0)
go(node.right, 1)
_traverse(node, nsym, start_node, root, left - 1)
idseed = 0
go(node.left)
go(node.right)
def dfs_setid(node, prefix):
if node.term is not None:
return
if len(prefix) <= 7 and [1] * len(prefix) == prefix:
node.accept = True
global idseed
node.id = idseed
idseed += 1
dfs_setid(node.left, prefix + [0])
dfs_setid(node.right, prefix + [1])
def dfs(node, root):
def _build_transition_table(ctx, node):
if node is None:
return
traverse(node, [], [], node, root, 0)
dfs(node.left, root)
dfs(node.right, root)
_traverse(node, None, node, ctx.root, 4)
_build_transition_table(ctx, node.left)
_build_transition_table(ctx, node.right)
def huffman_tree_build_transition_table(ctx):
_build_transition_table(ctx, ctx.root)
NGHTTP2_HUFF_ACCEPTED = 1
NGHTTP2_HUFF_SYM = 1 << 1
NGHTTP2_HUFF_FAIL = 1 << 2
def dfs_print(node):
def _print_transition_table(node):
if node.term is not None:
return
print '/* {} */'.format(node.id)
print '{'
for nd, bits, syms in node.trans:
outlen = len(syms)
for nd, sym in node.trans:
flags = 0
if outlen == 0:
if sym is None:
out = 0
else:
assert(outlen == 1)
out = syms[0]
out = sym
flags |= NGHTTP2_HUFF_SYM
if nd is None:
id = 0
@@ -122,52 +386,50 @@ def dfs_print(node):
flags |= NGHTTP2_HUFF_ACCEPTED
print ' {{{}, 0x{:02x}, {}}},'.format(id, flags, out)
print '},'
dfs_print(node.left)
dfs_print(node.right)
_print_transition_table(node.left)
_print_transition_table(node.right)
symbol_tbl = [(None, 0) for i in range(257)]
tables = {}
def huffman_tree_print_transition_table(ctx):
_print_transition_table(ctx.root)
root = Node()
if __name__ == '__main__':
ctx = Context()
symbol_tbl = [(None, 0) for i in range(257)]
for line in sys.stdin:
m = re.match(r'.*\(\s*(\d+)\)\s+([|01]+)\s+(\S+)\s+\[\s*(\d+)\].*', line)
if m:
#print m.group(1), m.group(2), m.group(4)
if len(m.group(3)) > 8:
raise Error('Code is more than 4 bytes long')
sym = int(m.group(1))
bits = re.sub(r'\|', '', m.group(2))
nbits = int(m.group(4))
assert(len(bits) == nbits)
binpat = to_bin(bits)
assert(len(binpat) == (nbits+7)/8)
symbol_tbl[sym] = (binpat, nbits, m.group(3))
#print "Inserting", sym
insert(root, sym, bits)
for line in StringIO.StringIO(HUFFMAN_CODE_TABLE):
m = re.match(
r'.*\(\s*(\d+)\)\s+([|01]+)\s+(\S+)\s+\[\s*(\d+)\].*', line)
if m:
sym = int(m.group(1))
bits = re.sub(r'\|', '', m.group(2))
code = m.group(3)
nbits = int(m.group(4))
if len(code) > 8:
raise Error('Code is more than 4 bytes long')
assert(len(bits) == nbits)
symbol_tbl[sym] = (nbits, code)
huffman_tree_add(ctx, sym, bits)
dfs_setid(root, [])
dfs(root, root)
huffman_tree_set_node_id(ctx)
huffman_tree_build_transition_table(ctx)
print '''\
print '''\
typedef struct {
uint32_t nbits;
uint32_t code;
} nghttp2_huff_sym;
'''
print '''\
const nghttp2_huff_sym huff_sym_table[] = {'''
for i in range(257):
pat = list(symbol_tbl[i][0])
pat += [0]*(4 - len(pat))
print '''\
const nghttp2_huff_sym huff_sym_table[] = {'''
for i in range(257):
print '''\
{{ {}, 0x{}u }}{}\
'''.format(symbol_tbl[i][1], symbol_tbl[i][2], ',' if i < 256 else '')
print '};'
print ''
'''.format(symbol_tbl[i][0], symbol_tbl[i][1], ',' if i < 256 else '')
print '};'
print ''
print '''\
print '''\
enum {{
NGHTTP2_HUFF_ACCEPTED = {},
NGHTTP2_HUFF_SYM = {},
@@ -175,7 +437,7 @@ enum {{
}} nghttp2_huff_decode_flag;
'''.format(NGHTTP2_HUFF_ACCEPTED, NGHTTP2_HUFF_SYM, NGHTTP2_HUFF_FAIL)
print '''\
print '''\
typedef struct {
uint8_t state;
uint8_t flags;
@@ -183,7 +445,7 @@ typedef struct {
} nghttp2_huff_decode;
'''
print '''\
print '''\
const nghttp2_huff_decode huff_decode_table[][16] = {'''
dfs_print(root)
print '};'
huffman_tree_print_transition_table(ctx)
print '};'

View File

@@ -10,39 +10,17 @@
from __future__ import unicode_literals
import re, sys
def hash(s):
h = 0
for c in s:
h = h * 31 + ord(c)
return h & ((1 << 32) - 1)
entries = []
for line in sys.stdin:
m = re.match(r'(\d+)\s+(\S+)\s+(\S.*)?', line)
val = m.group(3).strip() if m.group(3) else ''
entries.append((hash(m.group(2)), int(m.group(1)), m.group(2), val))
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_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(' ')
entries.append((int(m.group(1)), m.group(2), val))
print 'static nghttp2_hd_entry static_table[] = {'
idx = 0
for i, ent in enumerate(entries):
if entries[idx][1] != ent[1]:
idx = i
print 'MAKE_STATIC_ENT("{}", "{}", {}),'\
.format(ent[1], ent[2], entries[idx][0] - 1)
print '};'

View File

@@ -10,7 +10,7 @@
#
# * The options which do not take argument in the command-line *take*
# argument in the configuration file. Specify 'yes' as argument
# (e.g., spdy-proxy=yes). If other string is given, it disables the
# (e.g., http2-proxy=yes). If other string is given, it disables the
# option.
#
# * To specify private key and certificate file, use private-key-file
@@ -25,5 +25,5 @@
# backend=127.0.0.1,80
# private-key-file=/path/to/server.key
# certificate-file=/path/to/server.crt
# spdy-proxy=no
# http2-proxy=no
# workers=1

4
python/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# generated files
MANIFEST
dist/
setup.py

View File

@@ -34,6 +34,7 @@ cdef extern from 'nghttp2/nghttp2.h':
ctypedef enum nghttp2_error:
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
NGHTTP2_ERR_DEFERRED
ctypedef enum nghttp2_flag:
NGHTTP2_FLAG_NONE
@@ -282,6 +283,9 @@ cdef extern from 'nghttp2/nghttp2.h':
int nghttp2_session_terminate_session(nghttp2_session *session,
uint32_t error_code)
int nghttp2_session_resume_data(nghttp2_session *session,
int32_t stream_id)
const char* nghttp2_strerror(int lib_error_code)
int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,

View File

@@ -258,19 +258,35 @@ try:
except ImportError:
asyncio = None
# body generator flags
DATA_OK = 0
DATA_EOF = 1
DATA_DEFERRED = 2
class _ByteIOWrapper:
def __init__(self, b):
self.b = b
def generate(self, n):
data = self.b.read1(n)
if not data:
return None, DATA_EOF
return data, DATA_OK
def wrap_body(body):
if body is None:
return body
elif isinstance(body, str):
return io.BytesIO(body.encode('utf-8'))
return _ByteIOWrapper(io.BytesIO(body.encode('utf-8'))).generate
elif isinstance(body, bytes):
return io.BytesIO(body)
return _ByteIOWrapper(io.BytesIO(body)).generate
elif isinstance(body, io.IOBase):
return body
return _ByteIOWrapper(body).generate
else:
raise Exception(('body must be None or instance of str or '
'bytes or io.IOBase'))
# assume that callable in the form f(n) returning tuple byte
# string and flag.
return body
cdef _get_stream_user_data(cnghttp2.nghttp2_session *session,
int32_t stream_id):
@@ -488,29 +504,39 @@ cdef int on_stream_close(cnghttp2.nghttp2_session *session,
return 0
cdef ssize_t server_data_source_read(cnghttp2.nghttp2_session *session,
int32_t stream_id,
uint8_t *buf, size_t length,
uint32_t *data_flags,
cnghttp2.nghttp2_data_source *source,
void *user_data):
cdef http2 = <_HTTP2SessionCore>user_data
handler = <object>source.ptr
cdef ssize_t data_source_read(cnghttp2.nghttp2_session *session,
int32_t stream_id,
uint8_t *buf, size_t length,
uint32_t *data_flags,
cnghttp2.nghttp2_data_source *source,
void *user_data):
cdef http2 = <_HTTP2SessionCoreBase>user_data
generator = <object>source.ptr
http2.enter_callback()
try:
data = handler.response_body.read(length)
data, flag = generator(length)
except:
sys.stderr.write(traceback.format_exc())
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
finally:
http2.leave_callback()
if flag == DATA_DEFERRED:
return cnghttp2.NGHTTP2_ERR_DEFERRED
if data:
nread = len(data)
memcpy(buf, <uint8_t*>data, nread)
return nread
else:
nread = 0
data_flags[0] = cnghttp2.NGHTTP2_DATA_FLAG_EOF
if flag == DATA_EOF:
data_flags[0] = cnghttp2.NGHTTP2_DATA_FLAG_EOF
elif flag != DATA_OK:
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
return 0
return nread
cdef int client_on_begin_headers(cnghttp2.nghttp2_session *session,
const cnghttp2.nghttp2_frame *frame,
@@ -595,36 +621,13 @@ cdef int client_on_frame_send(cnghttp2.nghttp2_session *session,
return 0
http2._start_settings_timer()
cdef ssize_t client_data_source_read(cnghttp2.nghttp2_session *session,
int32_t stream_id,
uint8_t *buf, size_t length,
uint32_t *data_flags,
cnghttp2.nghttp2_data_source *source,
void *user_data):
cdef http2 = <_HTTP2ClientSessionCore>user_data
body = <object>source.ptr
try:
data = body.read(length)
except:
sys.stderr.write(traceback.format_exc())
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
if data:
nread = len(data)
memcpy(buf, <uint8_t*>data, nread)
return nread
data_flags[0] = cnghttp2.NGHTTP2_DATA_FLAG_EOF
return 0
cdef class _HTTP2SessionCoreBase:
cdef cnghttp2.nghttp2_session *session
cdef transport
cdef handler_class
cdef handlers
cdef settings_timer
cdef inside_callback
def __cinit__(self, transport, handler_class=None):
self.session = NULL
@@ -632,6 +635,7 @@ cdef class _HTTP2SessionCoreBase:
self.handler_class = handler_class
self.handlers = set()
self.settings_timer = None
self.inside_callback = False
def __dealloc__(self):
cnghttp2.nghttp2_session_del(self.session)
@@ -668,6 +672,17 @@ cdef class _HTTP2SessionCoreBase:
cnghttp2.nghttp2_session_want_write(self.session) == 0:
self.transport.close()
def resume(self, stream_id):
cnghttp2.nghttp2_session_resume_data(self.session, stream_id)
if not self.inside_callback:
self.send_data()
def enter_callback(self):
self.inside_callback = True
def leave_callback(self):
self.inside_callback = False
def _make_handler(self, stream_id):
logging.debug('_make_handler, stream_id:%s', stream_id)
handler = self.handler_class(self, stream_id)
@@ -815,8 +830,8 @@ cdef class _HTTP2SessionCore(_HTTP2SessionCoreBase):
nvlen = _make_nva(&nva, handler.response_headers)
if handler.response_body:
prd.source.ptr = <void*>handler
prd.read_callback = server_data_source_read
prd.source.ptr = <void*>handler.response_body
prd.read_callback = data_source_read
prd_ptr = &prd
else:
prd_ptr = NULL
@@ -921,8 +936,8 @@ cdef class _HTTP2ClientSessionCore(_HTTP2SessionCoreBase):
custom_headers = _encode_headers(headers)
headers = [
(b':scheme', scheme.encode('utf-8')),
(b':method', method.encode('utf-8')),
(b':scheme', scheme.encode('utf-8')),
(b':authority', host.encode('utf-8')),
(b':path', path.encode('utf-8'))
]
@@ -933,7 +948,7 @@ cdef class _HTTP2ClientSessionCore(_HTTP2SessionCoreBase):
if body:
prd.source.ptr = <void*>body
prd.read_callback = client_data_source_read
prd.read_callback = data_source_read
prd_ptr = &prd
else:
prd_ptr = NULL
@@ -1095,8 +1110,26 @@ if asyncio:
additional response headers. The :status header field is
appended by the library. The body is the response body. It
could be None if response body is empty. Or it must be
instance of either str, bytes or io.IOBase. If instance of str
is specified, it is encoded using UTF-8.
instance of either str, bytes, io.IOBase or callable,
called body generator, which takes one parameter,
size. The body generator generates response body. It can
pause generation of response so that it can wait for slow
backend data generation. When invoked, it should return
tuple, byte string and flag. The flag is either DATA_OK,
DATA_EOF and DATA_DEFERRED. For non-empty byte string and
it is not the last chunk of response, DATA_OK is returned
as flag. If this is the last chunk of the response (byte
string is possibly None), DATA_EOF must be returned as
flag. If there is no data available right now, but
additional data are anticipated, return tuple (None,
DATA_DEFERRD). When data arrived, call resume() and
restart response body transmission.
Only the body generator can pause response body
generation; instance of io.IOBase must not block.
If instance of str is specified as body, it is encoded
using UTF-8.
The headers is a list of tuple of the form (name,
value). The name and value can be either unicode string or
@@ -1129,11 +1162,9 @@ if asyncio:
request_headers parameter).
The status is HTTP status code. The headers is additional
response headers. The :status header field is appended by the
library. The body is the response body. It could be None if
response body is empty. Or it must be instance of either str,
bytes or io.IOBase. If instance of str is specified, it is
encoded using UTF-8.
response headers. The :status header field is appended by
the library. The body is the response body. It has the
same semantics of body parameter of send_response().
The headers and request_headers are a list of tuple of the
form (name, value). The name and value can be either
@@ -1161,16 +1192,15 @@ if asyncio:
promised_handler.path = path.encode('utf-8')
promised_handler._set_response_prop(status, headers, body)
if request_headers is None:
request_headers = []
headers = [
(b':method', promised_handler.method),
(b':scheme', promised_handler.scheme),
(b':authority', promised_handler.host),
(b':path', promised_handler.path)
]
headers.extend(_encode_headers(request_headers))
request_headers = _encode_headers(request_headers)
request_headers.append((b':scheme', promised_handler.scheme))
request_headers.append((b':method', promised_handler.method))
request_headers.append((b':authority', promised_handler.host))
request_headers.append((b':path', promised_handler.path))
promised_handler.headers = request_headers
promised_handler.headers = headers
return self.http2.push(self, promised_handler)
@@ -1180,12 +1210,14 @@ if asyncio:
if headers is None:
headers = []
self.response_headers = _encode_headers(headers)
self.response_headers.append((b':status', str(status)\
.encode('utf-8')))
self.response_headers = [(b':status', str(status).encode('utf-8'))]
self.response_headers.extend(_encode_headers(headers))
self.response_body = body
def resume(self):
self.http2.resume(self.stream_id)
def _encode_headers(headers):
if not headers:
return []
@@ -1432,6 +1464,9 @@ if asyncio:
'''
self.http2.push(push_promise, handler)
def resume(self):
self.http2.resume(self.stream_id)
class _HTTP2ClientSession(asyncio.Protocol):
def __init__(self, client):

View File

@@ -36,7 +36,7 @@ setup(
author = 'Tatsuhiro Tsujikawa',
version = '@PACKAGE_VERSION@',
author_email = 'tatsuhiro.t@gmail.com',
url = 'http://tatsuhiro-t.github.io/nghttp2/',
url = 'https://nghttp2.org/',
keywords = [],
ext_modules = [Extension("nghttp2",
["nghttp2.c"],

20
src/.gitignore vendored
View File

@@ -1,12 +1,16 @@
# generated files
libnghttp2_asio.pc
# programs
deflatehd
h2load
inflatehd
nghttp
nghttpd
nghttpx
nghttpx-unittest
nghttpx-unittest.log
nghttpx-unittest.trs
test-suite.log
.dirstamp
# build
libnghttpx.a
deflatehd
inflatehd
h2load
# tests
nghttpx-unittest

View File

@@ -30,7 +30,8 @@
namespace nghttp2 {
ParserData::ParserData(const std::string &base_uri) : base_uri(base_uri) {}
ParserData::ParserData(const std::string &base_uri)
: base_uri(base_uri), inside_head(0) {}
HtmlParser::HtmlParser(const std::string &base_uri)
: base_uri_(base_uri), parser_ctx_(nullptr), parser_data_(base_uri) {}
@@ -52,13 +53,13 @@ const char *get_attr(const xmlChar **attrs, const char *name) {
} // namespace
namespace {
void add_link(ParserData *parser_data, const char *uri, RequestPriority pri) {
void add_link(ParserData *parser_data, const char *uri, ResourceType res_type) {
auto u = xmlBuildURI(
reinterpret_cast<const xmlChar *>(uri),
reinterpret_cast<const xmlChar *>(parser_data->base_uri.c_str()));
if (u) {
parser_data->links.push_back(
std::make_pair(reinterpret_cast<char *>(u), pri));
std::make_pair(reinterpret_cast<char *>(u), res_type));
free(u);
}
}
@@ -68,6 +69,9 @@ namespace {
void start_element_func(void *user_data, const xmlChar *name,
const xmlChar **attrs) {
auto parser_data = static_cast<ParserData *>(user_data);
if (util::strieq(reinterpret_cast<const char *>(name), "head")) {
++parser_data->inside_head;
}
if (util::strieq(reinterpret_cast<const char *>(name), "link")) {
auto rel_attr = get_attr(attrs, "rel");
auto href_attr = get_attr(attrs, "href");
@@ -75,22 +79,35 @@ void start_element_func(void *user_data, const xmlChar *name,
return;
}
if (util::strieq(rel_attr, "shortcut icon")) {
add_link(parser_data, href_attr, REQ_PRI_LOWEST);
add_link(parser_data, href_attr, REQ_OTHERS);
} else if (util::strieq(rel_attr, "stylesheet")) {
add_link(parser_data, href_attr, REQ_PRI_MEDIUM);
add_link(parser_data, href_attr, REQ_CSS);
}
} else if (util::strieq(reinterpret_cast<const char *>(name), "img")) {
auto src_attr = get_attr(attrs, "src");
if (!src_attr) {
return;
}
add_link(parser_data, src_attr, REQ_PRI_LOWEST);
add_link(parser_data, src_attr, REQ_IMG);
} else if (util::strieq(reinterpret_cast<const char *>(name), "script")) {
auto src_attr = get_attr(attrs, "src");
if (!src_attr) {
return;
}
add_link(parser_data, src_attr, REQ_PRI_LOW);
if (parser_data->inside_head) {
add_link(parser_data, src_attr, REQ_JS);
} else {
add_link(parser_data, src_attr, REQ_UNBLOCK_JS);
}
}
}
} // namespace
namespace {
void end_element_func(void *user_data, const xmlChar *name) {
auto parser_data = static_cast<ParserData *>(user_data);
if (util::strieq(reinterpret_cast<const char *>(name), "head")) {
--parser_data->inside_head;
}
}
} // namespace
@@ -112,7 +129,7 @@ xmlSAXHandler saxHandler = {
nullptr, // startDocumentSAXFunc
nullptr, // endDocumentSAXFunc
&start_element_func, // startElementSAXFunc
nullptr, // endElementSAXFunc
&end_element_func, // endElementSAXFunc
nullptr, // referenceSAXFunc
nullptr, // charactersSAXFunc
nullptr, // ignorableWhitespaceSAXFunc
@@ -160,7 +177,7 @@ int HtmlParser::parse_chunk_internal(const char *chunk, size_t size, int fin) {
}
}
const std::vector<std::pair<std::string, RequestPriority>> &
const std::vector<std::pair<std::string, ResourceType>> &
HtmlParser::get_links() const {
return parser_data_.links;
}

View File

@@ -38,16 +38,19 @@
namespace nghttp2 {
enum RequestPriority {
REQ_PRI_HIGH = 0,
REQ_PRI_MEDIUM = 1,
REQ_PRI_LOW = 2,
REQ_PRI_LOWEST = 3
enum ResourceType {
REQ_CSS = 1,
REQ_JS,
REQ_UNBLOCK_JS,
REQ_IMG,
REQ_OTHERS,
};
struct ParserData {
std::string base_uri;
std::vector<std::pair<std::string, RequestPriority>> links;
std::vector<std::pair<std::string, ResourceType>> links;
// > 0 if we are inside "head" element.
int inside_head;
ParserData(const std::string &base_uri);
};
@@ -58,7 +61,7 @@ public:
HtmlParser(const std::string &base_uri);
~HtmlParser();
int parse_chunk(const char *chunk, size_t size, int fin);
const std::vector<std::pair<std::string, RequestPriority>> &get_links() const;
const std::vector<std::pair<std::string, ResourceType>> &get_links() const;
void clear_links();
private:
@@ -75,14 +78,13 @@ class HtmlParser {
public:
HtmlParser(const std::string &base_uri) {}
int parse_chunk(const char *chunk, size_t size, int fin) { return 0; }
const std::vector<std::pair<std::string, RequestPriority>> &
get_links() const {
const std::vector<std::pair<std::string, ResourceType>> &get_links() const {
return links_;
}
void clear_links() {}
private:
std::vector<std::pair<std::string, RequestPriority>> links_;
std::vector<std::pair<std::string, ResourceType>> links_;
};
#endif // !HAVE_LIBXML2

View File

@@ -57,11 +57,6 @@
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";
const std::string DEFAULT_HTML = "index.html";
const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION;
} // namespace
@@ -94,9 +89,9 @@ template <typename Array> void append_nv(Stream *stream, const Array &nva) {
Config::Config()
: stream_read_timeout(60.), stream_write_timeout(60.),
session_option(nullptr), data_ptr(nullptr), padding(0), num_worker(1),
header_table_size(-1), port(0), verbose(false), daemon(false),
verify_client(false), no_tls(false), error_gzip(false),
early_response(false) {
max_concurrent_streams(100), header_table_size(-1), port(0),
verbose(false), daemon(false), verify_client(false), no_tls(false),
error_gzip(false), early_response(false), hexdump(false) {
nghttp2_option_new(&session_option);
nghttp2_option_set_recv_client_preface(session_option, 1);
}
@@ -171,9 +166,10 @@ void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config);
class Sessions {
public:
Sessions(struct ev_loop *loop, const Config *config, SSL_CTX *ssl_ctx)
: loop_(loop), config_(config), ssl_ctx_(ssl_ctx), callbacks_(nullptr),
next_session_id_(1), tstamp_cached_(ev_now(loop)),
Sessions(HttpServer *sv, struct ev_loop *loop, const Config *config,
SSL_CTX *ssl_ctx)
: sv_(sv), loop_(loop), config_(config), ssl_ctx_(ssl_ctx),
callbacks_(nullptr), next_session_id_(1), tstamp_cached_(ev_now(loop)),
cached_date_(util::http_date(tstamp_cached_)) {
nghttp2_session_callbacks_new(&callbacks_);
@@ -229,7 +225,7 @@ public:
make_unique<Http2Handler>(this, fd, ssl, get_next_session_id());
handler->setup_bev();
if (!ssl) {
if (handler->on_connect() != 0) {
if (handler->connection_made() != 0) {
return;
}
}
@@ -244,9 +240,37 @@ public:
}
return cached_date_;
}
FileEntry *get_cached_fd(const std::string &path) {
auto i = fd_cache_.find(path);
if (i == std::end(fd_cache_)) {
return nullptr;
}
auto &ent = (*i).second;
++ent.usecount;
return &ent;
}
FileEntry *cache_fd(const std::string &path, const FileEntry &ent) {
auto rv = fd_cache_.emplace(path, ent);
return &(*rv.first).second;
}
void release_fd(const std::string &path) {
auto i = fd_cache_.find(path);
if (i == std::end(fd_cache_)) {
return;
}
auto &ent = (*i).second;
if (--ent.usecount == 0) {
close(ent.fd);
fd_cache_.erase(i);
}
}
const HttpServer *get_server() const { return sv_; }
private:
std::set<Http2Handler *> handlers_;
// cache for file descriptors to read file.
std::map<std::string, FileEntry> fd_cache_;
HttpServer *sv_;
struct ev_loop *loop_;
const Config *config_;
SSL_CTX *ssl_ctx_;
@@ -257,7 +281,8 @@ private:
};
Stream::Stream(Http2Handler *handler, int32_t stream_id)
: handler(handler), body_left(0), stream_id(stream_id), file(-1) {
: handler(handler), file_ent(nullptr), body_length(0), body_offset(0),
stream_id(stream_id) {
auto config = handler->get_config();
ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
ev_timer_init(&wtimer, stream_timeout_cb, 0., config->stream_write_timeout);
@@ -270,8 +295,9 @@ Stream::Stream(Http2Handler *handler, int32_t stream_id)
}
Stream::~Stream() {
if (file != -1) {
close(file);
if (file_ent != nullptr) {
auto sessions = handler->get_sessions();
sessions->release_fd(file_ent->path);
}
auto loop = handler->get_loop();
@@ -371,6 +397,8 @@ struct ev_loop *Http2Handler::get_loop() const {
return sessions_->get_loop();
}
Http2Handler::WriteBuf *Http2Handler::get_wb() { return &wb_; }
int Http2Handler::setup_bev() { return 0; }
int Http2Handler::fill_wb() {
@@ -426,6 +454,11 @@ int Http2Handler::read_clear() {
if (nread == 0) {
return -1;
}
if (get_config()->hexdump) {
util::hexdump(stdout, buf.data(), nread);
}
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
if (rv < 0) {
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
@@ -515,7 +548,7 @@ int Http2Handler::tls_handshake() {
read_ = &Http2Handler::read_tls;
write_ = &Http2Handler::write_tls;
if (on_connect() != 0) {
if (connection_made() != 0) {
return -1;
}
@@ -548,6 +581,11 @@ int Http2Handler::read_tls() {
}
auto nread = rv;
if (get_config()->hexdump) {
util::hexdump(stdout, buf.data(), nread);
}
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
if (rv < 0) {
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
@@ -619,11 +657,13 @@ int Http2Handler::on_read() { return read_(*this); }
int Http2Handler::on_write() { return write_(*this); }
int Http2Handler::on_connect() {
int Http2Handler::connection_made() {
int r;
auto config = sessions_->get_config();
r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
sessions_->get_config()->session_option);
config->session_option);
if (r != 0) {
return r;
}
@@ -631,11 +671,11 @@ int Http2Handler::on_connect() {
size_t niv = 1;
entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
entry[0].value = 100;
entry[0].value = config->max_concurrent_streams;
if (sessions_->get_config()->header_table_size >= 0) {
if (config->header_table_size >= 0) {
entry[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
entry[niv].value = sessions_->get_config()->header_table_size;
entry[niv].value = config->header_table_size;
++niv;
}
r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(), niv);
@@ -823,21 +863,12 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
auto hd = static_cast<Http2Handler *>(user_data);
auto stream = hd->get_stream(stream_id);
int fd = source->fd;
ssize_t nread;
auto nread = std::min(stream->body_length - stream->body_offset,
static_cast<int64_t>(length));
while ((nread = read(fd, buf, length)) == -1 && errno == EINTR)
;
*data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
if (nread == -1) {
remove_stream_read_timeout(stream);
remove_stream_write_timeout(stream);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
stream->body_left -= nread;
if (nread == 0 || stream->body_left <= 0) {
if (nread == 0 || stream->body_length == stream->body_offset + nread) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
auto config = hd->get_config();
@@ -869,59 +900,27 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
}
namespace {
void prepare_status_response(Stream *stream, Http2Handler *hd,
const std::string &status) {
int pipefd[2];
if (status == STATUS_304 || pipe(pipefd) == -1) {
hd->submit_response(status, stream->stream_id, 0);
return;
}
std::string body;
body.reserve(256);
body = "<html><head><title>";
body += status;
body += "</title></head><body><h1>";
body += status;
body += "</h1><hr><address>";
body += NGHTTPD_SERVER;
body += " at port ";
body += util::utos(hd->get_config()->port);
body += "</address>";
body += "</body></html>";
void prepare_status_response(Stream *stream, Http2Handler *hd, int status) {
auto sessions = hd->get_sessions();
auto status_page = sessions->get_server()->get_status_page(status);
auto file_ent = &status_page->file_ent;
// we don't set stream->file_ent since we don't want to expire it.
stream->body_length = file_ent->length;
nghttp2_data_provider data_prd;
data_prd.source.fd = file_ent->fd;
data_prd.read_callback = file_read_callback;
Headers headers;
if (hd->get_config()->error_gzip) {
gzFile write_fd = gzdopen(pipefd[1], "w");
gzwrite(write_fd, body.c_str(), body.size());
gzclose(write_fd);
headers.emplace_back("content-encoding", "gzip");
} else {
ssize_t rv;
while ((rv = write(pipefd[1], body.c_str(), body.size())) == -1 &&
errno == EINTR)
;
if (rv != static_cast<ssize_t>(body.size())) {
std::cerr << "Could not write all response body: " << rv << std::endl;
}
}
close(pipefd[1]);
stream->file = pipefd[0];
stream->body_left = body.size();
nghttp2_data_provider data_prd;
data_prd.source.fd = pipefd[0];
data_prd.read_callback = file_read_callback;
headers.emplace_back("content-type", "text/html; charset=UTF-8");
hd->submit_response(status, stream->stream_id, headers, &data_prd);
hd->submit_response(status_page->status, stream->stream_id, headers,
&data_prd);
}
} // namespace
namespace {
void prepare_redirect_response(Stream *stream, Http2Handler *hd,
const std::string &path,
const std::string &status) {
const std::string &path, int status) {
auto scheme =
http2::get_header(stream->hdidx, http2::HD__SCHEME, stream->headers);
auto authority =
@@ -938,7 +937,10 @@ void prepare_redirect_response(Stream *stream, Http2Handler *hd,
auto headers = Headers{{"location", redirect_url}};
hd->submit_response(status, stream->stream_id, headers, nullptr);
auto sessions = hd->get_sessions();
auto status_page = sessions->get_server()->get_status_page(status);
hd->submit_response(status_page->status, stream->stream_id, headers, nullptr);
}
} // namespace
@@ -972,7 +974,7 @@ void prepare_response(Stream *stream, Http2Handler *hd,
url = util::percentDecode(url.begin(), url.end());
if (!util::check_path(url)) {
prepare_status_response(stream, hd, STATUS_404);
prepare_status_response(stream, hd, 404);
return;
}
auto push_itr = hd->get_config()->push.find(url);
@@ -989,51 +991,66 @@ void prepare_response(Stream *stream, Http2Handler *hd,
if (path[path.size() - 1] == '/') {
path += DEFAULT_HTML;
}
int file = open(path.c_str(), O_RDONLY | O_BINARY);
if (file == -1) {
prepare_status_response(stream, hd, STATUS_404);
return;
}
auto sessions = hd->get_sessions();
auto file_ent = sessions->get_cached_fd(path);
struct stat buf;
if (file_ent == nullptr) {
int file = open(path.c_str(), O_RDONLY | O_BINARY);
if (file == -1) {
prepare_status_response(stream, hd, 404);
if (fstat(file, &buf) == -1) {
close(file);
prepare_status_response(stream, hd, STATUS_404);
return;
}
if (buf.st_mode & S_IFDIR) {
close(file);
if (query_pos == std::string::npos) {
reqpath += "/";
} else {
reqpath.insert(query_pos, "/");
return;
}
prepare_redirect_response(stream, hd, reqpath, STATUS_301);
struct stat buf;
if (fstat(file, &buf) == -1) {
close(file);
prepare_status_response(stream, hd, 404);
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, 301);
return;
}
if (last_mod_found && buf.st_mtime <= last_mod) {
close(file);
prepare_status_response(stream, hd, 304);
return;
}
file_ent = sessions->cache_fd(
path, FileEntry(path, buf.st_size, buf.st_mtime, file));
} else if (last_mod_found && file_ent->mtime <= last_mod) {
sessions->release_fd(file_ent->path);
prepare_status_response(stream, hd, 304);
return;
}
stream->file = file;
stream->body_left = buf.st_size;
stream->file_ent = file_ent;
stream->body_length = file_ent->length;
nghttp2_data_provider data_prd;
data_prd.source.fd = file;
data_prd.source.fd = file_ent->fd;
data_prd.read_callback = file_read_callback;
if (last_mod_found && buf.st_mtime <= last_mod) {
prepare_status_response(stream, hd, STATUS_304);
return;
}
hd->submit_file_response(STATUS_200, stream, buf.st_mtime, buf.st_size,
hd->submit_file_response("200", stream, file_ent->mtime, file_ent->length,
&data_prd);
}
} // namespace
@@ -1210,6 +1227,58 @@ int hd_on_frame_send_callback(nghttp2_session *session,
}
} // namespace
namespace {
int send_data_callback(nghttp2_session *session, nghttp2_frame *frame,
const uint8_t *framehd, size_t length,
nghttp2_data_source *source, void *user_data) {
auto hd = static_cast<Http2Handler *>(user_data);
auto wb = hd->get_wb();
auto padlen = frame->data.padlen;
auto stream = hd->get_stream(frame->hd.stream_id);
if (wb->wleft() < 9 + length + padlen) {
return NGHTTP2_ERR_WOULDBLOCK;
}
int fd = source->fd;
auto p = wb->last;
p = std::copy_n(framehd, 9, p);
if (padlen) {
*p++ = padlen - 1;
}
while (length) {
ssize_t nread;
while ((nread = pread(fd, p, length, stream->body_offset)) == -1 &&
errno == EINTR)
;
if (nread == -1) {
remove_stream_read_timeout(stream);
remove_stream_write_timeout(stream);
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
stream->body_offset += nread;
length -= nread;
p += nread;
}
if (padlen) {
std::fill(p, p + padlen - 1, 0);
p += padlen - 1;
}
wb->last = p;
return 0;
}
} // namespace
namespace {
ssize_t select_padding_callback(nghttp2_session *session,
const nghttp2_frame *frame, size_t max_payload,
@@ -1278,6 +1347,9 @@ void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config) {
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
nghttp2_session_callbacks_set_send_data_callback(callbacks,
send_data_callback);
if (config->padding) {
nghttp2_session_callbacks_set_select_padding_callback(
callbacks, select_padding_callback);
@@ -1324,7 +1396,7 @@ void run_worker(Worker *worker) {
class AcceptHandler {
public:
AcceptHandler(Sessions *sessions, const Config *config)
AcceptHandler(HttpServer *sv, Sessions *sessions, const Config *config)
: sessions_(sessions), config_(config), next_worker_(0) {
if (config_->num_worker == 1) {
return;
@@ -1336,7 +1408,7 @@ public:
auto worker = make_unique<Worker>();
auto loop = ev_loop_new(0);
worker->sessions =
make_unique<Sessions>(loop, config_, sessions_->get_ssl_ctx());
make_unique<Sessions>(sv, loop, config_, sessions_->get_ssl_ctx());
ev_async_init(&worker->w, worker_acceptcb);
worker->w.data = worker.get();
ev_async_start(loop, &worker->w);
@@ -1420,7 +1492,61 @@ void acceptcb(struct ev_loop *loop, ev_io *w, int revents) {
}
} // namespace
HttpServer::HttpServer(const Config *config) : config_(config) {}
namespace {
FileEntry make_status_body(int status, uint16_t port) {
std::string body;
body = "<html><head><title>";
body += http2::get_status_string(status);
body += "</title></head><body><h1>";
body += http2::get_status_string(status);
body += "</h1><hr><address>";
body += NGHTTPD_SERVER;
body += " at port ";
body += util::utos(port);
body += "</address>";
body += "</body></html>";
char tempfn[] = "/tmp/nghttpd.temp.XXXXXX";
int fd = mkstemp(tempfn);
if (fd == -1) {
auto error = errno;
std::cerr << "Could not open status response body file: errno=" << error;
assert(0);
}
unlink(tempfn);
ssize_t nwrite;
while ((nwrite = write(fd, body.c_str(), body.size())) == -1 &&
errno == EINTR)
;
if (nwrite == -1) {
auto error = errno;
std::cerr << "Could not write status response body into file: errno="
<< error;
assert(0);
}
return FileEntry(util::utos(status), nwrite, 0, fd);
}
} // namespace
// index into HttpServer::status_pages_
enum {
IDX_200,
IDX_301,
IDX_304,
IDX_400,
IDX_404,
};
HttpServer::HttpServer(const Config *config) : config_(config) {
status_pages_ = std::vector<StatusPage>{
{"200", make_status_body(200, config_->port)},
{"301", make_status_body(301, config_->port)},
{"304", make_status_body(304, config_->port)},
{"400", make_status_body(400, config_->port)},
{"404", make_status_body(404, config_->port)},
};
}
namespace {
int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
@@ -1441,14 +1567,14 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
} // namespace
namespace {
int start_listen(struct ev_loop *loop, Sessions *sessions,
int start_listen(HttpServer *sv, struct ev_loop *loop, Sessions *sessions,
const Config *config) {
addrinfo hints;
int r;
bool ok = false;
const char *addr = nullptr;
auto acceptor = std::make_shared<AcceptHandler>(sessions, config);
auto acceptor = std::make_shared<AcceptHandler>(sv, sessions, config);
auto service = util::utos(config->port);
memset(&hints, 0, sizeof(addrinfo));
@@ -1643,8 +1769,8 @@ int HttpServer::run() {
auto loop = EV_DEFAULT;
Sessions sessions(loop, config_, ssl_ctx);
if (start_listen(loop, &sessions, config_) != 0) {
Sessions sessions(this, loop, config_, ssl_ctx);
if (start_listen(this, loop, &sessions, config_) != 0) {
std::cerr << "Could not listen" << std::endl;
return -1;
}
@@ -1655,4 +1781,22 @@ int HttpServer::run() {
const Config *HttpServer::get_config() const { return config_; }
const StatusPage *HttpServer::get_status_page(int status) const {
switch (status) {
case 200:
return &status_pages_[IDX_200];
case 301:
return &status_pages_[IDX_301];
case 304:
return &status_pages_[IDX_304];
case 400:
return &status_pages_[IDX_400];
case 404:
return &status_pages_[IDX_404];
default:
assert(0);
}
return nullptr;
}
} // namespace nghttp2

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