Compare commits

...

529 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
01313c1241 Update man pages 2015-01-25 23:00:43 +09:00
Tatsuhiro Tsujikawa
99afea05b9 Bump up version number to 0.7.3 2015-01-25 22:58:43 +09:00
Tatsuhiro Tsujikawa
b99b83812b nghttpd: RST_STREAM if te header field contains value other than trailers 2015-01-25 22:58:43 +09:00
Tatsuhiro Tsujikawa
0b48448270 nghttpx: RST_STREAM for invalid request header values 2015-01-25 22:58:43 +09:00
Tatsuhiro Tsujikawa
2a56a3d9ea nghttpx: Fix te request header handling
Checking against "trailers" is enough for now.
2015-01-25 22:58:43 +09:00
Tatsuhiro Tsujikawa
1883bdaf1d Bump up version number to 0.7.3-DEV 2015-01-25 22:53:34 +09:00
Tatsuhiro Tsujikawa
82cd23e40b Update man pages 2015-01-25 21:49:12 +09:00
Tatsuhiro Tsujikawa
d56e167c54 Bump up version number to 0.7.2, LT revision to 9:0:4 2015-01-25 21:48:36 +09:00
Tatsuhiro Tsujikawa
3e5765831f integration: Add missing alt-server.key and alt-server.crt to EXTRA_DIST 2015-01-25 21:35:45 +09:00
Tatsuhiro Tsujikawa
b9c6162cd5 nghttp: Use compatible cipher list 2015-01-25 17:53:17 +09:00
Tatsuhiro Tsujikawa
68510f1282 nghttpx: SpdyUpstream: Handle error from error_reply 2015-01-25 15:37:09 +09:00
Tatsuhiro Tsujikawa
4b58b25c19 nghttpx: Refactor code to build cert_tree, add SNI test 2015-01-25 15:36:14 +09:00
Tatsuhiro Tsujikawa
fbd9bcb00e Use _LDADD to specify libraries instead of _LDFLAGS
This is because _LDFLAGS comes before _LDADD.  If we specify a library
and another library in _LDADD depends on it, we get undefined
reference error.
2015-01-25 00:58:30 +09:00
Tatsuhiro Tsujikawa
682db00ba9 integration: Add tests for TE request header field 2015-01-24 16:02:03 +09:00
Tatsuhiro Tsujikawa
434e80dc7b nghttpx: Reset stream if TE header field contains other than trailer 2015-01-24 15:31:59 +09:00
Tatsuhiro Tsujikawa
5c93a113f3 Document about make itprep 2015-01-24 01:05:20 +09:00
Tatsuhiro Tsujikawa
6b4b7bef23 nghttpx: Reset stream if request header field name is malformed 2015-01-24 00:37:26 +09:00
Tatsuhiro Tsujikawa
8d5c893929 integration: Add Cookie crumbling tests 2015-01-24 00:27:12 +09:00
Tatsuhiro Tsujikawa
b943fbb002 integration: Add test for assembling Cookie works toward HTTP/1 link 2015-01-24 00:17:11 +09:00
Tatsuhiro Tsujikawa
9a89db575a nghttpx: Reject multiple Content-Length even if their values are identical 2015-01-24 00:07:28 +09:00
Tatsuhiro Tsujikawa
0fcfe16dc5 integration: Document each test cases 2015-01-24 00:01:14 +09:00
Tatsuhiro Tsujikawa
990f9ed4de integration: Split up single file to 3 based on frontend type 2015-01-23 23:37:11 +09:00
Tatsuhiro Tsujikawa
0f4b0966ef nghttpx: Merge all options settings in one SSL_CTX_set_options 2015-01-23 23:32:01 +09:00
Tatsuhiro Tsujikawa
ecfd593076 nghttpx: Call ConnectBlocker::on_success when connection is established 2015-01-23 23:00:18 +09:00
Tatsuhiro Tsujikawa
3c6b75fb2b Add make itprep target to go get dependencies 2015-01-23 22:55:42 +09:00
Tatsuhiro Tsujikawa
d1f06b09cd integration: Add TLS key and certificate for testing 2015-01-23 21:25:21 +09:00
Tatsuhiro Tsujikawa
3a94ad709c Merge branch 'acesso-patch-1' 2015-01-23 21:17:33 +09:00
acesso
7ea8037ee1 Use fcntl and FD_CLOEXEC if O_CLOEXEC is undefined
Same reported at #87 but at src/shrpx_config.cc src/instead of util.cc
2015-01-23 21:17:06 +09:00
Tatsuhiro Tsujikawa
064bfcc9d2 Fix test failure 2015-01-23 01:29:41 +09:00
Tatsuhiro Tsujikawa
a0028ea8ef nghttpx: Add logging when downstream connect is blocked by connect_blocker 2015-01-23 00:15:38 +09:00
Tatsuhiro Tsujikawa
d174ffeb00 memchunk: Rename append_cstr as append
We may later add append(const T &), where we require T for .size() and
.data().  We can coexist former append_cstr and new one.  If we pass
string literal, append(const (&)[N]) is selected.
2015-01-22 23:54:30 +09:00
Tatsuhiro Tsujikawa
5a93bedf72 nghttpx: Make error page modern 2015-01-22 23:51:22 +09:00
Tatsuhiro Tsujikawa
4a0dba08b9 nghttpx: Set Connection: close after graceful shutdown in HTTP/1 upstream 2015-01-22 23:46:35 +09:00
Tatsuhiro Tsujikawa
b685747643 Add nghttp2_submit_shutdown_notice() to start graceful shutdown
nghttp2_submit_shutdown_notice() is used to notify the client that
graceful shutdown is started.  We expect that after this call, the
server application should send another GOAWAY using
nghttp2_submit_goaway() with appropriate last_stream_id.  In this
commit, we also added nghttp2_session_get_last_proc_stream_id(), which
can be used as last_stream_id parameter.

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

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

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

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

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

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

Currently, HEADERS submitted by nghttp2_submit_headers is not attached
to stream.  This is because it may be used as non-final response
header and application may submit final response using
nghttp2_submit_response without checking non-final response header
transmission.
2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
5a48750e16 Assign default weight if NGHTTP2_MAX_DEP_TREE_LENGTH is exceeded 2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
ae93f6345c Allow PRIORITY frame at anytime.
Allowing PRIORITY frame at anytime so that PRIORITY frame to idle
stream can create anchor node in dependency tree.  In this change, we
open stream with new NGHTTP2_STREAM_IDLE state, which is linked in
session->closed_stream_head and is treated as if it is closed stream.
One difference is that if the stream is opened, we remove it from
linked list and change the state to the appropriate one.  To O(1)
removal from linked list, we change session->closed_stream_head to
doubly linked list.
2014-11-24 15:25:19 +09:00
Tatsuhiro Tsujikawa
9bba616426 nghttpx: Add $alpn variable to accesslog formatting
$alpn is a variable which represents ALPN identifier of the protocol
which generates the response.
2014-11-24 15:24:09 +09:00
Tatsuhiro Tsujikawa
1fe50f272b nghttpx: Add $pid to --accesslog-format variable
$pid refers to the PID of the running process.
2014-11-24 14:34:43 +09:00
Tatsuhiro Tsujikawa
93023acc6c nghttpx: Make --accesslog-format usage doc help2man friendly
This is unfortunate but help2man behaves badly when there is indented
lines in help messages in commnad-line args.  We removed indentations
to make help2man happy.
2014-11-24 14:16:48 +09:00
Tatsuhiro Tsujikawa
daf659c64e nghttpx: Note the conversion made in <VAR> 2014-11-24 14:04:37 +09:00
Tatsuhiro Tsujikawa
de2a855572 Implement faster formatting for format_iso8601 and format_common_log 2014-11-24 14:00:52 +09:00
Tatsuhiro Tsujikawa
df401f57a2 Merge branch 'LPardue-accesslog_port' 2014-11-24 13:35:47 +09:00
Lucas Pardue
6e178653a5 fixed conflict 2014-11-23 21:10:51 +00:00
Lucas Pardue
9cf1a0c77c Add features to logging, client and server port,
time_iso8601 and request_time.
2014-11-23 20:37:51 +00:00
Tatsuhiro Tsujikawa
ebdbe88bc0 Add contrib/.gitignore 2014-11-23 19:32:54 +09:00
Tatsuhiro Tsujikawa
74ec1d3377 nghttpx: Write accesslog when upstream connection is lost for HTTP/2 and SPDY 2014-11-23 17:24:23 +09:00
Tatsuhiro Tsujikawa
1e4f288a7c nghttpx: Remove misleading logging 2014-11-23 16:45:36 +09:00
Tatsuhiro Tsujikawa
6a21a6f148 Merge branch 'alagoutte-http_parser' 2014-11-22 23:16:40 +09:00
Tatsuhiro Tsujikawa
661b99ec17 Merge branch 'http_parser' of https://github.com/alagoutte/nghttp2 into alagoutte-http_parser 2014-11-22 23:14:44 +09:00
Tatsuhiro Tsujikawa
ecd143fcc2 nghttpx: Send RST_STREAM with NO_ERROR when closing upgraded connection 2014-11-22 23:13:29 +09:00
Tatsuhiro Tsujikawa
bd9389b956 nghttpx: Refactor http2_data_read_callback 2014-11-22 21:12:28 +09:00
Tatsuhiro Tsujikawa
1a09cef0ef nghttpx: Avoid 0-length DATA in HTTP/2 upstream 2014-11-22 21:12:28 +09:00
Alexis La Goutte
aa3a6d5916 Update Third Party lib (http-parser) 2014-11-21 19:45:55 +01:00
Tatsuhiro Tsujikawa
bded1d1115 h2load: Support ALPN 2014-11-22 01:13:18 +09:00
Tatsuhiro Tsujikawa
fa4f03525e nghttp: Fix compile error and warning with libc++ 2014-11-22 00:37:37 +09:00
Tatsuhiro Tsujikawa
4ee89e62fc nghttp2_hd: Refactor a bit 2014-11-21 01:59:20 +09:00
Tatsuhiro Tsujikawa
ee65dea8af nghttp: Fix compile error without libjansson 2014-11-19 21:18:31 +09:00
Tatsuhiro Tsujikawa
27609327ee nghttpx: Fix heap-after-free crash in https upstream
Add Upstream::on_handler_delete() hook to safely write log for
HttpsUpstream.
2014-11-19 01:59:09 +09:00
Tatsuhiro Tsujikawa
958cd0de64 nghttpx: Add configurable access logging format
This commit adds functionality to customize access logging format in
nghttpx.  The format variables are inspired by nginx.  The default
format is combined format.
2014-11-19 01:29:55 +09:00
Tatsuhiro Tsujikawa
1d7601edfb nghttpx: Better handling EOF from downstream connection to tunnel stream 2014-11-18 00:03:52 +09:00
Tatsuhiro Tsujikawa
8a0fdcfea9 nghttpd: Fix crash 2014-11-17 19:01:06 +09:00
Tatsuhiro Tsujikawa
75a1ad8bdb src: format_iso8601: Fix invalid millisecond formatting 2014-11-16 17:32:35 +09:00
Tatsuhiro Tsujikawa
5bac7f0ca6 python: Fix request is not sent without TLS 2014-11-16 17:31:11 +09:00
Tatsuhiro Tsujikawa
08fea5705a python: Fix bug that settings timer is started when SETTINGS with ACK is sent 2014-11-16 17:30:33 +09:00
Tatsuhiro Tsujikawa
8e5b5d00e1 Merge branch 'scoky-master' 2014-11-16 17:27:16 +09:00
Tatsuhiro Tsujikawa
97e8482348 Merge branch 'master' of https://github.com/scoky/nghttp2 into scoky-master 2014-11-16 16:48:07 +09:00
Kyle Schomp
0cc73e279e Pull of the client Python bindings 2014-11-15 16:37:41 +01:00
Tatsuhiro Tsujikawa
54232c6542 nghttp: Add --no-dep option to disable sending priority hints to server 2014-11-15 23:42:26 +09:00
Tatsuhiro Tsujikawa
ee2856f9bc nghttp: Update doc 2014-11-15 23:34:37 +09:00
Tatsuhiro Tsujikawa
737cea0b38 nghttp: Add -r, --har option to output HTTP transactions in HAR format 2014-11-15 23:34:10 +09:00
Tatsuhiro Tsujikawa
a8eeea0b18 Initialize frame header for upgrade SETTINGS frame 2014-11-15 11:30:01 +09:00
Tatsuhiro Tsujikawa
a2bc88f6db nghttpx: Check max length of ALPN field 2014-11-14 23:19:16 +09:00
Tatsuhiro Tsujikawa
5ce8ae79f0 nghttpx: Disable spdy/3 and spdy/2 by default 2014-11-14 23:16:06 +09:00
Tatsuhiro Tsujikawa
d98e9a63d0 src: Refactor code around ALPN setup 2014-11-14 23:14:39 +09:00
Tatsuhiro Tsujikawa
8e30adbca0 asio: Add http2::backlog API function 2014-11-10 23:26:01 +09:00
Tatsuhiro Tsujikawa
9adfd08848 asio_http2_handler: Use util::utos instead of std::to_string 2014-11-10 22:39:20 +09:00
Tatsuhiro Tsujikawa
2e3419ccbb nghttpd: Cache formatted date string 2014-11-10 22:35:08 +09:00
Tatsuhiro Tsujikawa
5b6b6dc1b7 src: Rewrite http_date 2014-11-10 21:53:19 +09:00
Tatsuhiro Tsujikawa
d0271a90b5 nghttpd: Use util::utos instead of slow util::to_str 2014-11-10 21:23:26 +09:00
Tatsuhiro Tsujikawa
20ffe2b2a0 tiny-nghttpd: Fix memory leak 2014-11-10 21:20:44 +09:00
Tatsuhiro Tsujikawa
94c80e2507 Bump up version number to 0.6.7-DEV 2014-11-08 23:40:23 +09:00
Tatsuhiro Tsujikawa
efa344be98 Add assert to ensure non-null dep_stream 2014-11-08 23:23:54 +09:00
Tatsuhiro Tsujikawa
2ba9a009fe nghttpd: Fix resource leak 2014-11-08 23:07:40 +09:00
Tatsuhiro Tsujikawa
c59ffa09e0 Update man pages 2014-11-08 22:55:24 +09:00
Tatsuhiro Tsujikawa
72f5e028d0 Bump up version number to 0.6.6, LT revision to 7:1:2 2014-11-08 22:52:45 +09:00
Tatsuhiro Tsujikawa
80b361dbb0 nghttpx: Use exit instead of abort for DIE macro 2014-11-08 21:38:57 +09:00
Tatsuhiro Tsujikawa
58254adb11 h2load: Print used SSL/TLS cipher name and parameters 2014-11-08 21:24:24 +09:00
Tatsuhiro Tsujikawa
7f60e8a307 Fix C++ lib sample 2014-11-08 16:52:03 +09:00
Tatsuhiro Tsujikawa
c31be5af4d Assign default priority if dep_stream in PRIORITY does not exist 2014-11-08 16:12:13 +09:00
Tatsuhiro Tsujikawa
292c01fda2 Add test to make sure that default priority is assigned 2014-11-08 11:37:53 +09:00
Tatsuhiro Tsujikawa
91f7d43e84 Assign default priority if dependency parent stream does not exist 2014-11-08 11:23:18 +09:00
Tatsuhiro Tsujikawa
ce71e65aee nghttpx: Replace WARNING with WARN for consistency 2014-11-08 10:51:56 +09:00
Tatsuhiro Tsujikawa
1119701071 nghttpx: Fix -L option help message
WARNING should be WARN.
2014-11-08 10:45:58 +09:00
Tatsuhiro Tsujikawa
42122c270a Don't reprioritize stream if it is not in dependency tree
Normally stream is in dependency tree, but sometimes it isn't.  For
example, client does not put pushed reserved stream in dependency
tree.
2014-11-08 10:31:53 +09:00
Tatsuhiro Tsujikawa
1348621d9e Fix bug that priority is ignored if dependency parent does not exist 2014-11-08 10:18:10 +09:00
Tatsuhiro Tsujikawa
8c5ea61376 Merge branch 'LPardue-log_notice' 2014-11-07 21:21:21 +09:00
Tatsuhiro Tsujikawa
c410f4055f Merge branch 'log_notice' of https://github.com/LPardue/nghttp2 into LPardue-log_notice 2014-11-07 21:15:02 +09:00
Tatsuhiro Tsujikawa
1e86635572 h2load: Make shutdown sequence simpler 2014-11-07 00:28:10 +09:00
Tatsuhiro Tsujikawa
62ede05c09 Fix heap-use-after-free due to duplicated push of DATA item 2014-11-06 23:47:41 +09:00
Lucas Pardue
a067eb02a5 Add LOG_NOTICE level logging for application lifecycle events 2014-11-06 14:32:56 +00:00
Tatsuhiro Tsujikawa
154876a17b nghttpx: Apply TLS record length limit to DATA frame payload
This is not obvious but it makes intermediaries flush and forward DATA
frame boundary without excessive buffering.  Since we have different
TCP connections frontend and backend, this may not work.  This is
still experimental.
2014-11-06 21:14:14 +09:00
Tatsuhiro Tsujikawa
f8c70993c0 nghttpx: Adjust TLS record size dynamically
Use the same behaviour the current Google server does: start with 1300
TLS record size and after transmitting 1MiB, change record size to
16384.  After 1 second idle time, reset to 1300.  Only applies to
HTTP/2 and SPDY upstream connections.
2014-11-06 02:36:53 +09:00
Tatsuhiro Tsujikawa
03a2828fcf src: Disable SSL_MODE_ENABLE_PARTIAL_WRITE for apps which use libevent 2014-11-05 01:15:38 +09:00
Tatsuhiro Tsujikawa
2fc0056ada nghttp: Allow multiple -v option to increase verbosity
Now the number of -v option specifies verbosity level.  Current all
verbose output are turned on for at lest one -v option, except for the
debug output for each data chunk which is only turned on more than one
-v options.
2014-11-05 00:42:12 +09:00
Tatsuhiro Tsujikawa
9a33116526 Fix bug in priority tree
This change fixes the bug that stream is out of dependency tree if the
number of nodes in a dependency tree which we add new node to is
already maximum (NGHTTP2_MAX_DEP_TREE_LENGTH) and the number of
maximum concurrent streams is more than more than
NGHTTP2_MAX_DEP_TREE_LENGTH.
2014-11-05 00:32:16 +09:00
Tatsuhiro Tsujikawa
29fcd7c946 nghttpd: Use http2::Headers 2014-11-02 23:33:04 +09:00
Tatsuhiro Tsujikawa
189f122dd7 nghttpd: Perform redirect if directory is requested 2014-11-02 23:27:38 +09:00
Tatsuhiro Tsujikawa
69c708be44 Bump up version number to 0.6.6-DEV 2014-11-02 23:27:16 +09:00
Tatsuhiro Tsujikawa
14e56fcd81 Update man pages 2014-10-31 00:11:38 +09:00
Tatsuhiro Tsujikawa
db67412511 Bump up version number to 0.6.5, LT revision to 7:0:2 2014-10-31 00:05:09 +09:00
Tatsuhiro Tsujikawa
76800dc8e7 Remove unused functions 2014-10-30 23:31:36 +09:00
Tatsuhiro Tsujikawa
7d282cd0bd Code cleanup 2014-10-30 23:31:28 +09:00
Tatsuhiro Tsujikawa
49b8d1d88c Rename max_header_set_size as max_header_list_size 2014-10-30 22:42:15 +09:00
Tatsuhiro Tsujikawa
4d93dd9d91 Upate to draft-15
* Add NGHTTP2_HTTP_1_1_REQUIRED error code
* Allow transmission of WINDOW_UPDATE on reserved (remote)
* Allow reception of WINDOW_UPDATE on reserved (local)
* Treat frame larger than MAX_FRAME_SIZE as FRAME_SIZE_ERROR

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

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

If this option is used with nonzero val, nghttp2 library checks first
24 bytes client connection preface. If it is not a valid one,
nghttp2_session_recv() and nghttp2_session_mem_recv() will return
error NGHTTP2_ERR_BAD_PREFACE, which is fatal error.
2014-09-13 19:50:44 +09:00
Tatsuhiro Tsujikawa
5847a56c40 Bump up version number to 0.6.2-DEV 2014-09-11 00:36:56 +09:00
269 changed files with 41774 additions and 28418 deletions

57
.clang-format Normal file
View File

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

7
.gitignore vendored
View File

@@ -21,6 +21,7 @@ install-sh
.libs
lib/includes/nghttp2/nghttp2ver.h
lib/libnghttp2.pc
src/libnghttp2_asio.pc
ltmain.sh
stamp-h1
.deps/
@@ -40,3 +41,9 @@ doc/h2load-howto.rst
doc/tutorial-hpack.rst
doc/python-apiref.rst
doc/building-android-binary.rst
doc/asio_http2.h.rst
doc/libnghttp2_asio.rst
doc/contribute.rst
python/setup.py
python/dist
python/MANIFEST

View File

@@ -3,8 +3,6 @@ compiler:
- clang
#Disable gcc build for the moment...
# - gcc
python:
- "3.4"
before_install:
- $CC --version
- sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
@@ -23,6 +21,7 @@ before_install:
libcunit1-dev
libssl-dev
libxml2-dev
libev-dev
libevent-dev
libjansson-dev
libjemalloc-dev

103
Dockerfile.android Normal file
View File

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

View File

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

View File

@@ -4,12 +4,14 @@ nghttp2 - HTTP/2 C Library
This is an implementation of Hypertext Transfer Protocol version 2
in C.
The framing layer of HTTP/2 is implemented as form of reusable C
The framing layer of HTTP/2 is implemented as a form of reusable C
library. On top of that, we have implemented HTTP/2 client, server
and proxy. Also we have developed load test/benchmarking tool for
and proxy. We have also developed load test and benchmarking tool for
HTTP/2 and SPDY.
HPACK encoding and decoding are available as public API.
HPACK encoder and decoder are available as public API.
The experimental high level C++ library is also available.
We have Python binding of this libary, but we have not covered
everything yet.
@@ -20,9 +22,7 @@ Development Status
We started to implement h2-14
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), the header
compression
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09)
and HTTP Alternative Services
(http://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-02).
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09).
The nghttp2 code base was forked from spdylay project.
@@ -32,7 +32,6 @@ HTTP/2 Features Support
Core frames handling Yes
Dependency Tree Yes
Large header (CONTINUATION) Yes
ALTSVC extension Yes
=========================== =======
Public Test Server
@@ -45,15 +44,11 @@ implementation.
NPN offer ``h2-14``, ``spdy/3.1`` and ``http/1.1``.
This endpoint requires TLSv1.2 and DHE or EDCHE with GCM cipher
suite for HTTP/2 connection.
This endpoint requires TLSv1.2 for HTTP/2 connection.
* http://nghttp2.org/ (Upgrade / Direct)
``h2c-14`` and ``http/1.1``. We configured this server to send
ALTSVC frame or Alt-Svc header field to announce that alternative
service is available at port 443.
``h2c-14`` and ``http/1.1``.
Requirements
------------
@@ -76,7 +71,7 @@ To build and run the application programs (``nghttp``, ``nghttpd`` and
required:
* OpenSSL >= 1.0.1
* libevent-openssl >= 2.0.8
* libev >= 4.15
* zlib >= 1.2.3
ALPN support requires unreleased version OpenSSL >= 1.0.2.
@@ -95,11 +90,20 @@ The HPACK tools require the following package:
* jansson >= 2.5
To build sources under examples directory, libevent is required:
* libevent-openssl >= 2.0.8
To mitigate heap fragmentation in long running server programs
(``nghttpd`` and ``nghttpx``), jemalloc is recommended:
* jemalloc
libnghttp2_asio C++ library requires the following packages:
* libboost-dev >= 1.54.0
* libboost-thread-dev >= 1.54.0
The Python bindings require the following packages:
* cython >= 0.19
@@ -108,6 +112,8 @@ The Python bindings require the following packages:
If you are using Ubuntu 14.04 LTS, you need the following packages
installed:
* make
* binutils
* autoconf
* automake
* autotools-dev
@@ -117,6 +123,7 @@ installed:
* libcunit1-dev
* libssl-dev
* libxml2-dev
* libev-dev
* libevent-dev
* libjansson-dev
* libjemalloc-dev
@@ -165,6 +172,34 @@ The generated documents will not be installed with ``make install``.
The online documentation is available at
https://nghttp2.org/documentation/
Unit tests
----------
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
its testing framework. We depend on the following libraries:
* https://github.com/bradfitz/http2
* https://github.com/tatsuhiro-t/go-nghttp2
* https://golang.org/x/net/spdy
To download the above packages, after settings ``GOPATH``, run the
following command under ``integration-tests`` directory::
$ make itprep
To run the tests, run the following command under
``integration-tests`` directory::
$ make it
Inside the tests, we use port 3009 to run test subject server.
Client, Server and Proxy programs
---------------------------------
@@ -275,8 +310,6 @@ The HTTP Upgrade is performed like this::
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
[ 0.024] recv ALTSVC frame <length=43, flags=0x00, stream_id=0>
(max-age=86400, port=443, protocol_id=h2-14, host=nghttp2.org, origin=http://nghttp2.org)
[ 0.024] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
@@ -429,7 +462,7 @@ 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 is needs to be configured to use
The ``Client`` in the above needs to be configured to use
``nghttpx`` as secure proxy.
At the time of this writing, Chrome is the only browser which supports
@@ -961,6 +994,45 @@ associated value includes the state of dynamic header table after the
corresponding header set was processed. The format is the same as
``deflatehd``.
libnghttp2_asio: High level HTTP/2 C++ library
----------------------------------------------
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
high level abstraction API to build HTTP/2 applications. It depends
on Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
provides server side API.
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
configure flag to build libnghttp2_asio. The required Boost libraries
are:
* Boost::Asio
* Boost::System
* Boost::Thread
Server API is designed to build HTTP/2 server very easily to utilize
C++11 anonymous function and closure. The bare minimum example of
HTTP/2 server looks like this:
.. code-block:: cpp
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
http2 server;
server.listen("*", 3000, [](const std::shared_ptr<request> &req,
const std::shared_ptr<response> &res) {
res->write_head(200);
res->end("hello, world");
});
}
For more details, see the documentation of libnghttp2_asio.
Python bindings
---------------
@@ -1098,3 +1170,7 @@ 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!
See `Contribution Guidelines
<https://nghttp2.org/documentation/contribute.html>`_ for more
details.

View File

@@ -39,9 +39,8 @@ PATH=$TOOLCHAIN/bin:$PATH
--without-libxml2 \
--disable-python-bindings \
--disable-examples \
--disable-threads \
CC=arm-linux-androideabi-clang \
CXX=arm-linux-androideabi-clang++ \
CC=clang \
CXX=clang++ \
CPPFLAGS="-I$PREFIX/include" \
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-L$PREFIX/lib"

View File

@@ -1,6 +1,6 @@
dnl nghttp2 - HTTP/2 C Library
dnl Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
dnl Copyright (c) 2012, 2013, 2014, 2015 Tatsuhiro Tsujikawa
dnl Permission is hereby granted, free of charge, to any person obtaining
dnl a copy of this software and associated documentation files (the
@@ -20,15 +20,19 @@ dnl NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
dnl LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
dnl OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
dnl WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
dnl Do not change user variables!
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
AC_PREREQ(2.61)
AC_INIT([nghttp2], [0.6.1], [t-tujikawa@users.sourceforge.net])
AC_INIT([nghttp2], [0.7.3], [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, 5)
AC_SUBST(LT_CURRENT, 9)
AC_SUBST(LT_REVISION, 0)
AC_SUBST(LT_AGE, 0)
AC_SUBST(LT_AGE, 4)
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"`
@@ -45,6 +49,9 @@ AC_CANONICAL_TARGET
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([subdir-objects])
# comment out for now since this requires automake 1.13 or higher and
# travis has older one.
# AM_EXTRA_RECURSIVE_TARGETS([it])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -76,6 +83,11 @@ AC_ARG_ENABLE([hpack-tools],
[Build HPACK tools [default=check]])],
[request_hpack_tools=$enableval], [request_hpack_tools=check])
AC_ARG_ENABLE([asio-lib],
[AS_HELP_STRING([--enable-asio-lib],
[Build C++ libnghttp2_asio library [default=no]])],
[request_asio_lib=$enableval], [request_asio_lib=no])
AC_ARG_ENABLE([examples],
[AS_HELP_STRING([--enable-examples],
[Build examples [default=check]])],
@@ -87,9 +99,9 @@ AC_ARG_ENABLE([python-bindings],
[request_python_bindings=$enableval], [request_python_bindings=check])
AC_ARG_ENABLE([failmalloc],
[AS_HELP_STRING([--enable-failmalloc],
[Build failmalloc test program [default=no]])],
[request_failmalloc=$enableval], [request_failmalloc=no])
[AS_HELP_STRING([--disable-failmalloc],
[Do not build failmalloc test program])],
[request_failmalloc=$enableval], [request_failmalloc=yes])
AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2],
@@ -135,6 +147,20 @@ else
AC_SUBST([CYTHON])
fi
#
# If we're running GCC or clang define _U_ to be "__attribute__((unused))"
# so we can use _U_ to flag unused function parameters and not get warnings
# about them. Otherwise, define _U_ to be an empty string so that _U_ used
# to flag an unused function parameters will compile with other compilers.
#
# XXX - similar hints for other compilers?
#
if test "x$GCC" = "xyes" -o "x$CC" = "xclang" ; then
AC_DEFINE([_U_], [__attribute__((unused))], [Hint to the compiler that a function parameters is not used])
else
AC_DEFINE([_U_], , [Hint to the compiler that a function parameters is not used])
fi
AX_CXX_COMPILE_STDCXX_11([noext], [optional])
AC_LANG_PUSH(C++)
@@ -174,46 +200,77 @@ std::vector<std::future<int>> v;
[have_std_future=no
AC_MSG_RESULT([no])])
# Check that thread_local is available.
AC_MSG_CHECKING([whether thread_local is available])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[
]],
[[
thread_local int n;
]])],
[AC_DEFINE([HAVE_THREAD_LOCAL], [1],
[Define to 1 if you have the `thread_local`.])
have_thread_local=yes
AC_MSG_RESULT([yes])],
[have_thread_local=no
AC_MSG_RESULT([no])])
# Check that std::map::emplace is available for g++-4.7.
AC_MSG_CHECKING([whether std::map::emplace is available])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[
#include <map>
]],
[[
std::map<int, int>().emplace(1, 2);
]])],
[AC_DEFINE([HAVE_STD_MAP_EMPLACE], [1],
[Define to 1 if you have the `std::map::emplace`.])
have_std_map_emplace=yes
AC_MSG_RESULT([yes])],
[have_std_map_emplace=no
AC_MSG_RESULT([no])])
AC_LANG_POP()
# Checks for libraries.
# Additional libraries required for tests.
TESTS_LIBS=
TESTLDADD=
# Additional libraries required for programs under src directory.
SRC_LIBS=
APPLDFLAGS=
LIBS_OLD=$LIBS
# Search for dlsym function, which is used in tests. Linux needs -ldl,
# but netbsd does not need it.
AC_SEARCH_LIBS([dlsym], [dl])
TESTS_LIBS="$LIBS $TESTS_LIBS"
TESTLDADD="$LIBS $TESTLDADD"
LIBS=$LIBS_OLD
LIBS_OLD=$LIBS
AC_SEARCH_LIBS([clock_gettime], [rt],
[AC_DEFINE([HAVE_CLOCK_GETTIME], [1],
[Define to 1 if you have the `clock_gettime`.])])
SRC_LIBS="$LIBS $SRC_LIBS"
APPLDFLAGS="$LIBS $APPLDFLAGS"
LIBS=$LIBS_OLD
case "$host" in
*android*)
android_build=yes
# android does not need -pthread, but needs followng 2 libs for C++
SRC_LIBS="$SRC_LIBS -lstdc++ -lsupc++"
# android does not need -pthread, but needs followng 3 libs for C++
APPLDFLAGS="$APPLDFLAGS -lstdc++ -latomic -lsupc++"
;;
*)
PTHREAD_LDFLAGS="-pthread"
SRC_LIBS="$SRC_LIBS $PTHREAD_LDFLAGS"
APPLDFLAGS="$APPLDFLAGS $PTHREAD_LDFLAGS"
;;
esac
# zlib
if test "x$android_build" = "xyes"; then
# Use zlib provided by NDK
SRC_LIBS="-lz $SRC_LIBS"
APPLDFLAGS="-lz $APPLDFLAGS"
have_zlib=yes
else
PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.3], [have_zlib=yes], [have_zlib=no])
@@ -252,6 +309,22 @@ fi
AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ])
# libev (for src)
# libev does not have pkg-config file. Check it in an old way.
LIBS_OLD=$LIBS
# android requires -lm for floor
AC_CHECK_LIB([ev], [ev_time], [have_libev=yes], [have_libev=no], [-lm])
if test "x${have_libev}" = "xyes"; then
AC_CHECK_HEADER([ev.h], [have_libev=yes], [have_libev=no])
if test "x${have_libev}" = "xyes"; then
LIBEV_LIBS=-lev
LIBEV_CFLAGS=
AC_SUBST([LIBEV_LIBS])
AC_SUBST([LIBEV_CFLAGS])
fi
fi
LIBS=$LIBS_OLD
# openssl (for src)
PKG_CHECK_MODULES([OPENSSL], [openssl >= 1.0.1],
[have_openssl=yes], [have_openssl=no])
@@ -259,7 +332,7 @@ if test "x${have_openssl}" = "xno"; then
AC_MSG_NOTICE($OPENSSL_PKG_ERRORS)
fi
# libevent_openssl (for src)
# libevent_openssl (for examples)
# 2.0.8 is required because we use evconnlistener_set_error_cb()
PKG_CHECK_MODULES([LIBEVENT_OPENSSL], [libevent_openssl >= 2.0.8],
[have_libevent_openssl=yes], [have_libevent_openssl=no])
@@ -267,10 +340,13 @@ if test "x${have_libevent_openssl}" = "xno"; then
AC_MSG_NOTICE($LIBEVENT_OPENSSL_PKG_ERRORS)
fi
# jansson (for hdtest/deflatehd and hdtest/inflatehd)
# jansson (for src/nghttp, src/deflatehd and src/inflatehd)
PKG_CHECK_MODULES([JANSSON], [jansson >= 2.5],
[have_jansson=yes], [have_jansson=no])
if test "x${have_jansson}" == "xno"; then
if test "x${have_jansson}" == "xyes"; then
AC_DEFINE([HAVE_JANSSON], [1],
[Define to 1 if you have `libjansson` library.])
else
AC_MSG_NOTICE($JANSSON_PKG_ERRORS)
fi
@@ -329,13 +405,32 @@ fi
AM_CONDITIONAL([HAVE_SPDYLAY], [ test "x${have_spdylay}" = "xyes" ])
# Check Boost Asio library
have_asio_lib=no
if test "x${request_asio_lib}" = "xyes"; then
AX_BOOST_BASE([1.54.0], [have_boost_base=yes], [have_boost_base=no])
if test "x${have_boost_base}" = "xyes"; then
AX_BOOST_ASIO()
AX_BOOST_SYSTEM()
AX_BOOST_THREAD()
if test "x${ax_cv_boost_asio}" = "xyes" &&
test "x${ax_cv_boost_system}" = "xyes" &&
test "x${ax_cv_boost_thread}" = "xyes"; then
have_asio_lib=yes
fi
fi
fi
# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL
# and libevent_openssl
# and libev
enable_app=no
if test "x${request_app}" != "xno" &&
test "x${have_zlib}" = "xyes" &&
test "x${have_openssl}" = "xyes" &&
test "x${have_libevent_openssl}" = "xyes"; then
test "x${have_libev}" = "xyes"; then
enable_app=yes
fi
@@ -345,7 +440,6 @@ if test "x${request_app}" = "xyes" &&
fi
AM_CONDITIONAL([ENABLE_APP], [ test "x${enable_app}" = "xyes" ])
AM_CONDITIONAL([ENABLE_H2LOAD], [ test "x${have_std_future}" = "xyes" ])
enable_hpack_tools=no
# HPACK tools requires jansson
@@ -361,6 +455,16 @@ fi
AM_CONDITIONAL([ENABLE_HPACK_TOOLS], [ test "x${enable_hpack_tools}" = "xyes" ])
# C++ library libnghttp2_asio
enable_asio_lib=no
if test "x${request_asio_lib}" != "xno" &&
test "x${have_asio_lib}" = "xyes"; then
enable_asio_lib=yes
fi
AM_CONDITIONAL([ENABLE_ASIO_LIB], [ test "x${enable_asio_lib}" = "xyes" ])
# The example programs depend on OpenSSL and libevent_openssl
enable_examples=no
if test "x${request_examples}" != "xno" &&
@@ -398,6 +502,11 @@ AM_CONDITIONAL([ENABLE_PYTHON_BINDINGS],
AM_CONDITIONAL([HAVE_CYTHON], [test "x${CYTHON}" != "x"])
# failmalloc tests
enable_failmalloc=no
if test "x${request_failmalloc}" = "xyes"; then
enable_failmalloc=yes
fi
AM_CONDITIONAL([ENABLE_FAILMALLOC], [ test "x${enable_failmalloc}" = "xyes" ])
# Checks for header files.
@@ -432,17 +541,40 @@ AC_CHECK_TYPES([ptrdiff_t])
AC_C_BIGENDIAN
AC_SYS_LARGEFILE
AC_CHECK_MEMBER([struct tm.tm_gmtoff], [have_struct_tm_tm_gmtoff=yes],
[have_struct_tm_tm_gmtoff=no], [[#include <time.h>]])
if test "x$have_struct_tm_tm_gmtoff" = "xyes"; then
AC_DEFINE([HAVE_STRUCT_TM_TM_GMTOFF], [1],
[Define to 1 if you have `struct tm.tm_gmtoff` member.])
fi
# Checks for library functions.
if test "x$cross_compiling" != "xyes"; then
AC_FUNC_MALLOC
fi
AC_CHECK_FUNCS([ \
_Exit \
accept4 \
getpwnam \
memmove \
memset \
timegm \
])
# timerfd_create was added in linux kernel 2.6.25
AC_CHECK_FUNC([timerfd_create],
[have_timerfd_create=yes], [have_timerfd_create=no])
# Checks for epoll availability, primarily for examples/tiny-nghttpd
AX_HAVE_EPOLL([have_epoll=yes], [have_epoll=no])
AM_CONDITIONAL([ENABLE_TINY_NGHTTPD],
[ test "x${have_epoll}" = "xyes" &&
test "x${have_timerfd_create}" = "xyes"])
dnl Windows library for winsock2
case "${host}" in
*mingw*)
@@ -450,6 +582,9 @@ case "${host}" in
;;
esac
ac_save_CFLAGS=$CFLAGS
CFLAGS=
if test "x$werror" != "xno"; then
AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"])
AX_CHECK_COMPILE_FLAG([-Wextra], [CFLAGS="$CFLAGS -Wextra"])
@@ -471,7 +606,6 @@ if test "x$werror" != "xno"; then
AX_CHECK_COMPILE_FLAG([-Wcast-align], [CFLAGS="$CFLAGS -Wcast-align"])
AX_CHECK_COMPILE_FLAG([-Wclobbered], [CFLAGS="$CFLAGS -Wclobbered"])
AX_CHECK_COMPILE_FLAG([-Wvla], [CFLAGS="$CFLAGS -Wvla"])
AX_CHECK_COMPILE_FLAG([-Wno-unused-parameter], [CFLAGS="$CFLAGS -Wno-unused-parameter"])
AX_CHECK_COMPILE_FLAG([-Wpragmas], [CFLAGS="$CFLAGS -Wpragmas"])
AX_CHECK_COMPILE_FLAG([-Wunreachable-code], [CFLAGS="$CFLAGS -Wunreachable-code"])
AX_CHECK_COMPILE_FLAG([-Waddress], [CFLAGS="$CFLAGS -Waddress"])
@@ -483,16 +617,27 @@ if test "x$werror" != "xno"; then
AX_CHECK_COMPILE_FLAG([-Wheader-guard], [CFLAGS="$CFLAGS -Wheader-guard"])
fi
WARNCFLAGS=$CFLAGS
CFLAGS=$ac_save_CFLAGS
AC_SUBST([WARNCFLAGS])
if test "x$debug" != "xno"; then
AC_DEFINE([DEBUGBUILD], [1], [Define to 1 to enable debug output.])
fi
if test "x$threads" != "xyes"; then
enable_threads=yes
# Some platform does not have working std::future or thread_local. We
# disable threading for those platforms.
if test "x$threads" != "xyes" ||
test "x$have_std_future" != "xyes" ||
test "x$have_thread_local" != "xyes"; then
enable_threads=no
AC_DEFINE([NOTHREADS], [1], [Define to 1 if you want to disable threads.])
fi
AC_SUBST([TESTS_LIBS])
AC_SUBST([SRC_LIBS])
AC_SUBST([TESTLDADD])
AC_SUBST([APPLDFLAGS])
AC_CONFIG_FILES([
Makefile
@@ -504,9 +649,14 @@ AC_CONFIG_FILES([
tests/testdata/Makefile
third-party/Makefile
src/Makefile
src/includes/Makefile
src/libnghttp2_asio.pc
examples/Makefile
python/Makefile
python/setup.py
integration-tests/Makefile
integration-tests/config.go
integration-tests/setenv
doc/Makefile
doc/conf.py
doc/index.rst
@@ -516,10 +666,14 @@ AC_CONFIG_FILES([
doc/tutorial-hpack.rst
doc/nghttpx-howto.rst
doc/h2load-howto.rst
doc/libnghttp2_asio.rst
doc/python-apiref.rst
doc/building-android-binary.rst
doc/nghttp2.h.rst
doc/nghttp2ver.h.rst
doc/asio_http2.h.rst
doc/contribute.rst
contrib/Makefile
])
AC_OUTPUT
@@ -530,6 +684,7 @@ AC_MSG_NOTICE([summary of build options:
Install prefix: ${prefix}
C compiler: ${CC}
CFLAGS: ${CFLAGS}
WARNCFLAGS: ${WARNCFLAGS}
LDFLAGS: ${LDFLAGS}
LIBS: ${LIBS}
CPPFLAGS: ${CPPFLAGS}
@@ -538,6 +693,7 @@ AC_MSG_NOTICE([summary of build options:
CXXFLAGS: ${CXXFLAGS}
CXXCPP: ${CXXCPP}
Library types: Shared=${enable_shared}, Static=${enable_static}
Python:
Python: ${PYTHON}
PYTHON_VERSION: ${PYTHON_VERSION}
pyexecdir: ${pyexecdir}
@@ -545,16 +701,27 @@ AC_MSG_NOTICE([summary of build options:
PYTHON_CPPFLAGS:${PYTHON_CPPFLAGS}
PYTHON_LDFLAGS: ${PYTHON_LDFLAGS}
Cython: ${CYTHON}
Test:
CUnit: ${have_cunit}
Failmalloc: ${enable_failmalloc}
Libs:
OpenSSL: ${have_openssl}
Libxml2: ${have_libxml2}
Libev: ${have_libev}
Libevent(SSL): ${have_libevent_openssl}
Spdylay: ${have_spdylay}
Jansson: ${have_jansson}
Jemalloc: ${have_jemalloc}
Boost CPPFLAGS: ${BOOST_CPPFLAGS}
Boost LDFLAGS: ${BOOST_LDFLAGS}
Boost::ASIO: ${BOOST_ASIO_LIB}
Boost::System: ${BOOST_SYSTEM_LIB}
Boost::Thread: ${BOOST_THREAD_LIB}
Features:
Applications: ${enable_app}
HPACK tools: ${enable_hpack_tools}
Libnghttp2_asio:${enable_asio_lib}
Examples: ${enable_examples}
Python bindings:${enable_python_bindings}
Failmalloc: ${request_failmalloc}
Threading: ${enable_threads}
])

1
contrib/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
nghttpx-init

39
contrib/Makefile.am Normal file
View File

@@ -0,0 +1,39 @@
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2014 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
EXTRA_DIST = nghttpx-init.in nghttpx-logrotate
edit = sed -e 's|@bindir[@]|$(bindir)|g'
nghttpx-init: Makefile
rm -f $@ $@.tmp
$(edit) $(srcdir)/$@.in > $@.tmp
chmod +x $@.tmp
mv $@.tmp $@
nghttpx-init: $(srcdir)/nghttpx-init.in
all-local: nghttpx-init
clean-local:
-rm -f nghttpx-init nghttpx-init.tmp

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

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

18
contrib/nghttpx-logrotate Normal file
View File

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

View File

@@ -37,8 +37,10 @@ EXTRA_DIST = \
sources/tutorial-hpack.rst \
sources/nghttpx-howto.rst \
sources/h2load-howto.rst \
sources/libnghttp2_asio.rst \
sources/python-apiref.rst \
sources/building-android-binary.rst \
sources/contribute.rst \
_themes/sphinx_rtd_theme/footer.html \
_themes/sphinx_rtd_theme/theme.conf \
_themes/sphinx_rtd_theme/layout_old.html \
@@ -174,7 +176,7 @@ text:
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
man: apiref.rst
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."

View File

@@ -28,5 +28,6 @@
</p>
</div>
{% trans %}<a href="https://github.com/snide/sphinx_rtd_theme">Sphinx theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}
{% 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 %}.
</footer>

View File

@@ -23,7 +23,7 @@
{% endif %}
{# CSS #}
<link href='https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
<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 %}
@@ -89,6 +89,7 @@
</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) %}
{% if toctree %}
{{ toctree }}
@@ -96,6 +97,7 @@
<!-- Local TOC -->
<div class="local-toc">{{ toc }}</div>
{% endif %}
{% endblock %}
</div>
&nbsp;
</nav>

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -26,6 +26,8 @@ do not send client connection preface
responsible to send it before sending any HTTP/2 frames using these
functions if :type:`nghttp2_session` is configured as client.
Similarly, `nghttp2_session_recv()` and `nghttp2_session_mem_recv()`
do not consume client connection preface. The applications are
responsible to receive it before calling these functions if
:type:`nghttp2_session` is configured as server.
do not consume client connection preface unless
`nghttp2_option_set_recv_client_preface()` is used with nonzero option
value. The applications are responsible to receive it before calling
these functions if :type:`nghttp2_session` is configured as server and
`nghttp2_option_set_recv_client_preface()` is not used.

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

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

View File

@@ -64,7 +64,7 @@ master_doc = 'index'
# General information about the project.
project = u'nghttp2'
copyright = u'2012, 2014, Tatsuhiro Tsujikawa'
copyright = u'2012, 2015, Tatsuhiro Tsujikawa'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -155,7 +155,7 @@ html_theme_path = ['@top_srcdir@/doc/_themes']
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
html_use_smartypants = False
# Custom sidebar templates, maps document names to template names.
html_sidebars = {
@@ -242,6 +242,12 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'nghttp2', u'nghttp2 Documentation',
('nghttp.1', 'nghttp', u'HTTP/2 experimental client',
[u'Tatsuhiro Tsujikawa'], 1),
('nghttpd.1', 'nghttpd', u'HTTP/2 experimental server',
[u'Tatsuhiro Tsujikawa'], 1),
('nghttpx.1', 'nghttpx', u'HTTP/2 experimental proxy',
[u'Tatsuhiro Tsujikawa'], 1),
('h2load.1', 'h2load', u'HTTP/2 benchmarking tool',
[u'Tatsuhiro Tsujikawa'], 1)
]

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

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

View File

@@ -1,61 +1,142 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
.TH H2LOAD "1" "September 2014" "h2load nghttp2/0.6.1" "User Commands"
.\" Man page generated from reStructuredText.
.
.TH "H2LOAD" "1" "January 25, 2015" "0.7.3" "nghttp2"
.SH NAME
h2load \- HTTP/2 benchmarking tool
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.B h2load
[\fI\,OPTIONS\/\fR]... \fI\,<URI>\/\fR...
.sp
\fBh2load\fP [OPTIONS]... [URI]...
.SH DESCRIPTION
.sp
benchmarking tool for HTTP/2 and SPDY server
.INDENT 0.0
.TP
<URI>
Specify URI to access. Multiple URIs can be
specified. URIs are used in this order for each
client. All URIs are used, then first URI is
used and then 2nd URI, and so on. The scheme,
host and port in the subsequent URIs, if present,
are ignored. Those in the first URI are used
solely.
.SH OPTIONS
.HP
\fB\-n\fR, \fB\-\-requests=\fR<N> Number of requests. Default: 1
.B <URI>
Specify URI to access. Multiple URIs can be specified.
URIs are used in this order for each client. All URIs
are used, then first URI is used and then 2nd URI, and
so on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the first URI
are used solely.
.UNINDENT
.SH OPTIONS:
.INDENT 0.0
.TP
\fB\-c\fR, \fB\-\-clients=\fR<N>
Number of concurrent clients. Default: 1
.B \-n, \-\-requests=<N>
Number of requests.
.sp
Default: \fB1\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-t\fR, \fB\-\-threads=\fR<N>
Number of native threads. Default: 1
.B \-c, \-\-clients=<N>
Number of concurrent clients.
.sp
Default: \fB1\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-m\fR, \fB\-\-max\-concurrent\-streams=\fR(auto|<N>)
Max concurrent streams to issue per session. If
"auto" is given, the number of given URIs is
used. Default: auto
.B \-t, \-\-threads=<N>
Number of native threads.
.sp
Default: \fB1\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-w\fR, \fB\-\-window\-bits=\fR<N>
Sets the stream level initial window size to
(2**<N>)\-1. For SPDY, 2**<N> is used instead.
.B \-i, \-\-input\-file=<FILE>
Path of a file with multiple URIs are seperated by EOLs.
This option will disable URIs getting from command\-line.
If \(aq\-\(aq is given as <FILE>, URIs will be read from stdin.
URIs are used in this order for each client. All URIs
are used, then first URI is used and then 2nd URI, and
so on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the first URI
are used solely.
.UNINDENT
.INDENT 0.0
.TP
\fB\-W\fR, \fB\-\-connection\-window\-bits=\fR<N>
.B \-m, \-\-max\-concurrent\-streams=(auto|<N>)
Max concurrent streams to issue per session. If "auto"
is given, the number of given URIs is used.
.sp
Default: \fBauto\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-w, \-\-window\-bits=<N>
Sets the stream level initial window size to (2**<N>)\-1.
For SPDY, 2**<N> is used instead.
.UNINDENT
.INDENT 0.0
.TP
.B \-W, \-\-connection\-window\-bits=<N>
Sets the connection level initial window size to
(2**<N>)\-1. For SPDY, if <N> is strictly less
than 16, this option is ignored. Otherwise
2**<N> is used for SPDY.
(2**<N>)\-1. For SPDY, if <N> is strictly less than 16,
this option is ignored. Otherwise 2**<N> is used for
SPDY.
.UNINDENT
.INDENT 0.0
.TP
\fB\-p\fR, \fB\-\-no\-tls\-proto=\fR<PROTOID>
Specify ALPN identifier of the protocol to be
used when accessing http URI without SSL/TLS.
Available protocols: spdy/2, spdy/3, spdy/3.1 and
h2c\-14
Default: h2c\-14
.B \-H, \-\-header=<HEADER>
Add/Override a header to the requests.
.UNINDENT
.INDENT 0.0
.TP
\fB\-v\fR, \fB\-\-verbose\fR
.B \-p, \-\-no\-tls\-proto=<PROTOID>
Specify ALPN identifier of the protocol to be used when
accessing http URI without SSL/TLS.
Available protocols: spdy/2, spdy/3, spdy/3.1 and h2c\-14
.sp
Default: \fBh2c\-14\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-v, \-\-verbose
Output debug information.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-version\fR
.B \-\-version
Display version information and exit.
.UNINDENT
.INDENT 0.0
.TP
\fB\-h\fR, \fB\-\-help\fR
.B \-h, \-\-help
Display this help and exit.
.SH "SEE ALSO"
nghttp(1), nghttpd(1), nghttpx(1)
.UNINDENT
.SH SEE ALSO
.sp
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fInghttpx(1)\fP
.SH AUTHOR
Tatsuhiro Tsujikawa
.SH COPYRIGHT
2012, 2015, Tatsuhiro Tsujikawa
.\" Generated by docutils manpage writer.
.

View File

@@ -1,93 +1,102 @@
.. program:: h2load
h2load(1)
=========
NAME
----
h2load - HTTP/2 benchmarking tool
SYNOPSIS
--------
**h2load** [OPTIONS]... <URI>...
**h2load** [OPTIONS]... [URI]...
DESCRIPTION
-----------
benchmarking tool for HTTP/2 and SPDY server
.. option:: URI
.. describe:: <URI>
Specify URI to access. Multiple URIs can be
specified. URIs are used in this order for each
client. All URIs are used, then first URI is
used and then 2nd URI, and so on. The scheme,
host and port in the subsequent URIs, if present,
are ignored. Those in the first URI are used
solely.
Specify URI to access. Multiple URIs can be specified.
URIs are used in this order for each client. All URIs
are used, then first URI is used and then 2nd URI, and
so on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the first URI
are used solely.
OPTIONS
-------
OPTIONS:
--------
.. option:: -n, --requests=<N>
Number of requests. Default: 1
Number of requests.
Default: ``1``
.. option:: -c, --clients=<N>
Number of concurrent clients.
Number of concurrent clients. Default: 1
Default: ``1``
.. option:: -t, --threads=<N>
Number of native threads.
Number of native threads. Default: 1
Default: ``1``
.. option:: -i, --input-file=<FILE>
Path of a file with multiple URIs are seperated by EOLs.
This option will disable URIs getting from command-line.
If '-' is given as <FILE>, URIs will be read from stdin.
URIs are used in this order for each client. All URIs
are used, then first URI is used and then 2nd URI, and
so on. The scheme, host and port in the subsequent
URIs, if present, are ignored. Those in the first URI
are used solely.
.. option:: -m, --max-concurrent-streams=(auto|<N>)
Max concurrent streams to issue per session. If "auto"
is given, the number of given URIs is used.
Max concurrent streams to issue per session. If
"auto" is given, the number of given URIs is
used. Default: auto
Default: ``auto``
.. option:: -w, --window-bits=<N>
Sets the stream level initial window size to
(2\*\*<N>)-1. For SPDY, 2\*\*<N> is used instead.
Sets the stream level initial window size to (2\*\*<N>)-1.
For SPDY, 2**<N> is used instead.
.. option:: -W, --connection-window-bits=<N>
Sets the connection level initial window size to
(2\*\*<N>)-1. For SPDY, if <N> is strictly less
than 16, this option is ignored. Otherwise
2\*\*<N> is used for SPDY.
(2**<N>)-1. For SPDY, if <N> is strictly less than 16,
this option is ignored. Otherwise 2\*\*<N> is used for
SPDY.
.. option:: -H, --header=<HEADER>
Add/Override a header to the requests.
.. option:: -p, --no-tls-proto=<PROTOID>
Specify ALPN identifier of the protocol to be used when
accessing http URI without SSL/TLS.
Available protocols: spdy/2, spdy/3, spdy/3.1 and h2c-14
Specify ALPN identifier of the protocol to be
used when accessing http URI without SSL/TLS.
Available protocols: spdy/2, spdy/3, spdy/3.1 and
h2c-14
Default: h2c-14
Default: ``h2c-14``
.. option:: -v, --verbose
Output debug information.
.. option:: --version
Display version information and exit.
.. option:: -h, --help
Display this help and exit.
SEE ALSO
--------
nghttp(1), nghttpd(1), nghttpx(1)
:manpage:`nghttp(1)`, :manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`

View File

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

4
doc/h2load.h2r Normal file
View File

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

View File

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

View File

@@ -1,108 +1,211 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
.TH NGHTTP "1" "September 2014" "nghttp nghttp2/0.6.1" "User Commands"
.\" Man page generated from reStructuredText.
.
.TH "NGHTTP" "1" "January 25, 2015" "0.7.3" "nghttp2"
.SH NAME
nghttp \- HTTP/2 experimental client
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.B nghttp
[\fI\,OPTIONS\/\fR]... \fI\,<URI>\/\fR...
.sp
\fBnghttp\fP [OPTIONS]... <URI>...
.SH DESCRIPTION
.sp
HTTP/2 experimental client
.INDENT 0.0
.TP
<URI>
.B <URI>
Specify URI to access.
.SH OPTIONS
.UNINDENT
.SH OPTIONS:
.INDENT 0.0
.TP
\fB\-v\fR, \fB\-\-verbose\fR
.B \-v, \-\-verbose
Print debug information such as reception and
transmission of frames and name/value pairs.
transmission of frames and name/value pairs. Specifying
this option multiple times increases verbosity.
.UNINDENT
.INDENT 0.0
.TP
\fB\-n\fR, \fB\-\-null\-out\fR
.B \-n, \-\-null\-out
Discard downloaded data.
.UNINDENT
.INDENT 0.0
.TP
\fB\-O\fR, \fB\-\-remote\-name\fR
.B \-O, \-\-remote\-name
Save download data in the current directory. The
filename is dereived from URI. If URI ends with
\&'/', 'index.html' is used as a filename. Not
implemented yet.
filename is dereived from URI. If URI ends with \(aq\fI/\fP\(aq,
\(aqindex.html\(aq is used as a filename. Not implemented
yet.
.UNINDENT
.INDENT 0.0
.TP
\fB\-t\fR, \fB\-\-timeout=\fR<N>
Timeout each request after <N> seconds.
.B \-t, \-\-timeout=<SEC>
Timeout each request after <SEC> seconds.
.UNINDENT
.INDENT 0.0
.TP
\fB\-w\fR, \fB\-\-window\-bits=\fR<N>
Sets the stream level initial window size to
2**<N>\-1.
.B \-w, \-\-window\-bits=<N>
Sets the stream level initial window size to 2**<N>\-1.
.UNINDENT
.INDENT 0.0
.TP
\fB\-W\fR, \fB\-\-connection\-window\-bits=\fR<N>
.B \-W, \-\-connection\-window\-bits=<N>
Sets the connection level initial window size to
2**<N>\-1.
.UNINDENT
.INDENT 0.0
.TP
\fB\-a\fR, \fB\-\-get\-assets\fR
Download assets such as stylesheets, images and
script files linked from the downloaded resource.
Only links whose origins are the same with the
linking resource will be downloaded.
.B \-a, \-\-get\-assets
Download assets such as stylesheets, images and script
files linked from the downloaded resource. Only links
whose origins are the same with the linking resource
will be downloaded. nghttp prioritizes resources using
HTTP/2 dependency based priority. The priority order,
from highest to lowest, is html itself, css, javascript
and images.
.UNINDENT
.INDENT 0.0
.TP
\fB\-s\fR, \fB\-\-stat\fR
.B \-s, \-\-stat
Print statistics.
.UNINDENT
.INDENT 0.0
.TP
\fB\-H\fR, \fB\-\-header\fR
Add a header to the requests.
.B \-H, \-\-header=<HEADER>
Add a header to the requests. Example: \fI\%\-H\fP\(aq:method: PUT\(aq
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-cert=\fR<CERT>
Use the specified client certificate file. The
file must be in PEM format.
.B \-\-cert=<CERT>
Use the specified client certificate file. The file
must be in PEM format.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-key=\fR<KEY>
Use the client private key file. The file must
be in PEM format.
.B \-\-key=<KEY>
Use the client private key file. The file must be in
PEM format.
.UNINDENT
.INDENT 0.0
.TP
\fB\-d\fR, \fB\-\-data=\fR<FILE>
Post FILE to server. If '\-' is given, data will
be read from stdin.
.B \-d, \-\-data=<FILE>
Post FILE to server. If \(aq\-\(aq is given, data will be read
from stdin.
.UNINDENT
.INDENT 0.0
.TP
\fB\-m\fR, \fB\-\-multiply=\fR<N> Request each URI <N> times.
By default, same URI
is not requested twice. This option disables it
too.
.B \-m, \-\-multiply=<N>
Request each URI <N> times. By default, same URI is not
requested twice. This option disables it too.
.UNINDENT
.INDENT 0.0
.TP
\fB\-u\fR, \fB\-\-upgrade\fR
Perform HTTP Upgrade for HTTP/2. This option is
ignored if the request URI has https scheme. If
\fB\-d\fR is used, the HTTP upgrade request is performed
with OPTIONS method.
.B \-u, \-\-upgrade
Perform HTTP Upgrade for HTTP/2. This option is ignored
if the request URI has https scheme. If \fI\-d\fP is used, the
HTTP upgrade request is performed with OPTIONS method.
.UNINDENT
.INDENT 0.0
.TP
\fB\-p\fR, \fB\-\-weight=\fR<WEIGHT>
Sets priority group weight. The valid value
range is [1, 256], inclusive.
Default: 16
.B \-p, \-\-weight=<WEIGHT>
Sets priority group weight. The valid value range is
[1, 256], inclusive.
.sp
Default: \fB16\fP
.UNINDENT
.INDENT 0.0
.TP
\fB\-M\fR, \fB\-\-peer\-max\-concurrent\-streams=\fR<N>
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value
of remote endpoint as if it is received in
SETTINGS frame. The default is large enough as
it is seen as unlimited.
.B \-M, \-\-peer\-max\-concurrent\-streams=<N>
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value of
remote endpoint as if it is received in SETTINGS frame.
The default is large enough as it is seen as unlimited.
.UNINDENT
.INDENT 0.0
.TP
\fB\-c\fR, \fB\-\-header\-table\-size=\fR<N>
.B \-c, \-\-header\-table\-size=<SIZE>
Specify decoder header table size.
.UNINDENT
.INDENT 0.0
.TP
\fB\-b\fR, \fB\-\-padding=\fR<N>
Add at most <N> bytes to a frame payload as
padding. Specify 0 to disable padding.
.B \-b, \-\-padding=<N>
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-color\fR
.B \-r, \-\-har=<FILE>
Output HTTP transactions <FILE> in HAR format. If \(aq\-\(aq
is given, data is written to stdout.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-color
Force colored log output.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-continuation\fR
.B \-\-continuation
Send large header to test CONTINUATION.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-no\-content\-length\fR
Don't send content\-length header field.
.B \-\-no\-content\-length
Don\(aqt send content\-length header field.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-version\fR
.B \-\-no\-dep
Don\(aqt send dependency based priority hint to server.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-dep\-idle
Use idle streams as anchor nodes to express priority.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-version
Display version information and exit.
.UNINDENT
.INDENT 0.0
.TP
\fB\-h\fR, \fB\-\-help\fR
.B \-h, \-\-help
Display this help and exit.
.SH "SEE ALSO"
nghttpd(1), nghttpx(1), h2load(1)
.UNINDENT
.sp
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).
.SH SEE ALSO
.sp
\fInghttpd(1)\fP, \fInghttpx(1)\fP, \fIh2load(1)\fP
.SH AUTHOR
Tatsuhiro Tsujikawa
.SH COPYRIGHT
2012, 2015, Tatsuhiro Tsujikawa
.\" Generated by docutils manpage writer.
.

View File

@@ -1,166 +1,158 @@
.. program:: nghttp
nghttp(1)
=========
NAME
----
nghttp - HTTP/2 experimental client
SYNOPSIS
--------
**nghttp** [OPTIONS]... <URI>...
DESCRIPTION
-----------
HTTP/2 experimental client
.. option:: URI
.. describe:: <URI>
Specify URI to access.
OPTIONS
-------
OPTIONS:
--------
.. option:: -v, --verbose
Print debug information such as reception and
transmission of frames and name/value pairs.
transmission of frames and name/value pairs. Specifying
this option multiple times increases verbosity.
.. option:: -n, --null-out
Discard downloaded data.
.. option:: -O, --remote-name
Save download data in the current directory. The
filename is dereived from URI. If URI ends with
\&'/', 'index.html' is used as a filename. Not
implemented yet.
filename is dereived from URI. If URI ends with '*/*',
'index.html' is used as a filename. Not implemented
yet.
.. option:: -t, --timeout=<N>
.. option:: -t, --timeout=<SEC>
Timeout each request after <N> seconds.
Timeout each request after <SEC> seconds.
.. option:: -w, --window-bits=<N>
Sets the stream level initial window size to
2\*\*<N>-1.
Sets the stream level initial window size to 2\*\*<N>-1.
.. option:: -W, --connection-window-bits=<N>
Sets the connection level initial window size to
2\*\*<N>-1.
.. option:: -a, --get-assets
Download assets such as stylesheets, images and
script files linked from the downloaded resource.
Only links whose origins are the same with the
linking resource will be downloaded.
Download assets such as stylesheets, images and script
files linked from the downloaded resource. Only links
whose origins are the same with the linking resource
will be downloaded. nghttp prioritizes resources using
HTTP/2 dependency based priority. The priority order,
from highest to lowest, is html itself, css, javascript
and images.
.. option:: -s, --stat
Print statistics.
.. option:: -H, --header
.. option:: -H, --header=<HEADER>
Add a header to the requests.
Add a header to the requests. Example: :option:`-H`\':method: PUT'
.. option:: --cert=<CERT>
Use the specified client certificate file. The
file must be in PEM format.
Use the specified client certificate file. The file
must be in PEM format.
.. option:: --key=<KEY>
Use the client private key file. The file must
be in PEM format.
Use the client private key file. The file must be in
PEM format.
.. option:: -d, --data=<FILE>
Post FILE to server. If '-' is given, data will
be read from stdin.
Post FILE to server. If '-' is given, data will be read
from stdin.
.. option:: -m, --multiply=<N>
Request each URI <N> times.
By default, same URI
is not requested twice. This option disables it
too.
Request each URI <N> times. By default, same URI is not
requested twice. This option disables it too.
.. option:: -u, --upgrade
Perform HTTP Upgrade for HTTP/2. This option is
ignored if the request URI has https scheme. If
:option:`-d` is used, the HTTP upgrade request is performed
with OPTIONS method.
Perform HTTP Upgrade for HTTP/2. This option is ignored
if the request URI has https scheme. If :option:`-d` is used, the
HTTP upgrade request is performed with OPTIONS method.
.. option:: -p, --weight=<WEIGHT>
Sets priority group weight. The valid value range is
[1, 256], inclusive.
Sets priority group weight. The valid value
range is [1, 256], inclusive.
Default: 16
Default: ``16``
.. option:: -M, --peer-max-concurrent-streams=<N>
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value of
remote endpoint as if it is received in SETTINGS frame.
The default is large enough as it is seen as unlimited.
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value
of remote endpoint as if it is received in
SETTINGS frame. The default is large enough as
it is seen as unlimited.
.. option:: -c, --header-table-size=<N>
.. option:: -c, --header-table-size=<SIZE>
Specify decoder header table size.
.. option:: -b, --padding=<N>
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
Add at most <N> bytes to a frame payload as
padding. Specify 0 to disable padding.
.. option:: -r, --har=<FILE>
Output HTTP transactions <FILE> in HAR format. If '-'
is given, data is written to stdout.
.. option:: --color
Force colored log output.
.. option:: --continuation
Send large header to test CONTINUATION.
.. option:: --no-content-length
Don't send content-length header field.
.. option:: --version
.. option:: --no-dep
Don't send dependency based priority hint to server.
.. option:: --dep-idle
Use idle streams as anchor nodes to express priority.
.. option:: --version
Display version information and exit.
.. option:: -h, --help
Display this help and exit.
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).
SEE ALSO
--------
nghttpd(1), nghttpx(1), h2load(1)
:manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`

View File

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

4
doc/nghttp.h2r Normal file
View File

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

View File

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

View File

@@ -1,136 +1,117 @@
.. program:: nghttpd
nghttpd(1)
==========
NAME
----
nghttpd - HTTP/2 experimental server
SYNOPSIS
--------
**nghttpd** [OPTION]... <PORT> <PRIVATE_KEY> <CERT>
**nghttpd** --no-tls [OPTION]... <PORT>
**nghttpd** [OPTION]... <PORT> [<PRIVATE_KEY> <CERT>]
DESCRIPTION
-----------
HTTP/2 experimental server
.. option:: PORT
.. describe:: <PORT>
Specify listening port number.
.. option:: PRIVATE_KEY
.. describe:: <PRIVATE_KEY>
Set path to server's private key. Required
unless :option:`--no-tls` is specified.
.. option:: CERT
Set path to server's private key. Required unless
:option:`--no-tls` is specified.
Set path to server's certificate. Required
unless :option:`--no-tls` is specified.
.. describe:: <CERT>
OPTIONS
-------
Set path to server's certificate. Required unless
:option:`--no-tls` is specified.
OPTIONS:
--------
.. option:: -D, --daemon
Run in a background. If :option:`-D` is used, the current
working directory is changed to '/'. Therefore
if this option is used, :option:`-d` option must be
specified.
Run in a background. If :option:`-D` is used, the current working
directory is changed to '*/*'. Therefore if this option
is used, :option:`-d` option must be specified.
.. option:: -V, --verify-client
The server sends a client certificate request.
If the client did not return a certificate, the
handshake is terminated. Currently, this option
just requests a client certificate and does not
verify it.
The server sends a client certificate request. If the
client did not return a certificate, the handshake is
terminated. Currently, this option just requests a
client certificate and does not verify it.
.. option:: -d, --htdocs=<PATH>
Specify document root. If this option is not
specified, the document root is the current
working directory.
Specify document root. If this option is not specified,
the document root is the current working directory.
.. option:: -v, --verbose
Print debug information such as reception/
transmission of frames and name/value pairs.
Print debug information such as reception/ transmission
of frames and name/value pairs.
.. option:: --no-tls
Disable SSL/TLS.
.. option:: -c, --header-table-size=<N>
.. option:: -c, --header-table-size=<SIZE>
Specify decoder header table size.
.. option:: --color
Force colored log output.
.. option:: -p, --push=<PATH>=<PUSH_PATH,...>
Push resources <PUSH_PATH>s when <PATH> is
requested. This option can be used repeatedly to
specify multiple push configurations. <PATH> and
<PUSH_PATH>s are relative to document root. See
:option:`--htdocs` option. Example: -p/=/foo.png
-p/doc=/bar.css
Push resources <PUSH_PATH>s when <PATH> is requested.
This option can be used repeatedly to specify multiple
push configurations. <PATH> and <PUSH_PATH>s are
relative to document root. See :option:`--htdocs` option.
Example: :option:`-p`\/=/foo.png :option:`-p`\/doc=/bar.css
.. option:: -b, --padding=<N>
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
Add at most <N> bytes to a frame payload as
padding. Specify 0 to disable padding.
.. option:: -n, --workers=<CORE>
.. option:: -n, --workers=<N>
Set the number of worker threads.
Default: 1
Default: ``1``
.. option:: -e, --error-gzip
Make error response gzipped.
.. option:: --dh-param-file=<PATH>
Path to file that contains DH parameters in PEM
format. Without this option, DHE cipher suites
are not available.
Path to file that contains DH parameters in PEM format.
Without this option, DHE cipher suites are not
available.
.. option:: --early-response
Start sending response when request HEADERS is
received, rather than complete request is
received.
Start sending response when request HEADERS is received,
rather than complete request is received.
.. option:: --version
Display version information and exit.
.. option:: -h, --help
Display this help and exit.
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).
SEE ALSO
--------
nghttp(1), nghttpx(1), h2load(1)
:manpage:`nghttp(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`

View File

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

4
doc/nghttpd.h2r Normal file
View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

48
doc/nghttpx.h2r Normal file
View File

@@ -0,0 +1,48 @@
FILES
-----
*/etc/nghttpx/nghttpx.conf*
The default configuration file path nghttpx searches at startup.
The configuration file path can be changed using :option:`--conf`
option.
Those lines which are staring ``#`` are treated as comment.
The option name in the configuration file is the long command-line
option name with leading ``--`` stripped (e.g., ``frontend``). Put
``=`` between option name and value. Don't put extra leading or
trailing spaces.
The options which do not take argument in the command-line *take*
argument in the configuration file. Specify ``yes`` as an argument
(e.g., ``http2-proxy=yes``). If other string is given, it is
ignored.
To specify private key and certificate file which are given as
positional arguments in commnad-line, use ``private-key-file`` and
``certificate-file``.
:option:`--conf` option cannot be used in the configuration file and
will be ignored if specified.
SIGNALS
-------
SIGQUIT
Shutdown gracefully. First accept pending connections and stop
accepting connection. After all connections are handled, nghttpx
exits.
SIGUSR1
Reopen log files.
SIGUSR2
Fork and execute nghttpx. It will execute the binary in the same
path with same command-line arguments and environment variables.
After new process comes up, sending SIGQUIT to the original process
to perform hot swapping.
SEE ALSO
--------
:manpage:`nghttp(1)`, :manpage:`nghttpd(1)`, :manpage:`h2load(1)`

View File

@@ -5,6 +5,11 @@ In this article, we briefly describe how to build Android binary using
`Android NDK <http://developer.android.com/tools/sdk/ndk/index.html>`_
cross-compiler on Debian Linux.
The easiest way to build android binary is use Dockerfile.android.
See Dockerfile.android for more details. If you cannot use
Dockerfile.android for whatever reason, continue to read the rest of
this article.
We offer ``android-config`` and ``android-make`` scripts to make the
build easier. To make these script work, NDK toolchain must be
installed in the following way. First, let us introduce
@@ -16,8 +21,9 @@ unpacked::
$ build/tools/make-standalone-toolchain.sh \
--install-dir=$ANDROID_HOME/toolchain \
--toolchain=arm-linux-androideabi-4.8 \
--llvm-version=3.4
--toolchain=arm-linux-androideabi-4.9 \
--llvm-version=3.5 \
--platform=android-16
The additional flag ``--system=linux-x86_64`` may be required if you
are using x86_64 system.
@@ -25,7 +31,7 @@ are using x86_64 system.
The platform level is not important here because we don't use Android
specific C/C++ API.
The dependent libraries, such as OpenSSL and libevent should be built
The dependent libraries, such as OpenSSL and libev should be built
with the toolchain and installed under ``$ANDROID_HOME/usr/local``.
We recommend to build these libraries as static library to make the
deployment easier. libxml2 support is currently disabled.
@@ -42,7 +48,9 @@ correct path. Also add ``$ANDROID_HOME/toolchain/bin`` to ``PATH``::
$ export PATH=$PATH:$ANDROID_HOME/toolchain/bin
To configure OpenSSL, use the following script::
To configure OpenSSL, use the following script:
.. code-block:: sh
#!/bin/sh
@@ -59,7 +67,12 @@ To configure OpenSSL, use the following script::
And run ``make install`` to build and install.
To configure libevent, use the following script::
We cannot compile libev without modification. Apply `this patch
<https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed>`_ before
configuring libev. This patch is for libev-4.19. After applying the
patch, to configure libev, use the following script:
.. code-block:: sh
#!/bin/sh
@@ -82,7 +95,9 @@ To configure libevent, use the following script::
And run ``make install`` to build and install.
To configure spdylay, use the following script::
To configure spdylay, use the following script:
.. code-block:: sh
if [ -z "$ANDROID_HOME" ]; then
echo 'No $ANDROID_HOME specified.'

View File

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

View File

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

View File

@@ -0,0 +1,228 @@
libnghttp2_asio: High level HTTP/2 C++ library
==============================================
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
high level abstraction API to build HTTP/2 applications. It depends
on Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
provides server side API.
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
configure flag to build libnghttp2_asio. The required Boost libraries
are:
* Boost::Asio
* Boost::System
* Boost::Thread
To use libnghttp2_asio, first include following header file:
.. code-block:: cpp
#include <nghttp2/asio_http2.h>
Also take a look at that header file :doc:`asio_http2.h`.
Server API
----------
Server API is designed to build HTTP/2 server very easily to utilize
C++11 anonymous function and closure. The bare minimum example of
HTTP/2 server looks like this:
.. code-block:: cpp
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
http2 server;
server.listen("*", 3000, [](const std::shared_ptr<request> &req,
const std::shared_ptr<response> &res) {
res->write_head(200);
res->end("hello, world");
});
}
First we instantiate ``nghttp2::asio_http2::server::http2`` object.
Then call ``nghttp2::asio_http2::server::http2::listen`` function with
address and port to listen to and callback function, namely "request
callback", invoked when request arrives.
The ``req`` and ``res`` represent HTTP request and response
respectively. ``nghttp2::asio_http2_::server::response::write_head``
constructs HTTP response header fields. The first argument is HTTP
status code, in the above example, which is 200. The second argument,
which is omitted in the above example, is additional header fields to
send.
``nghttp2::asio_http2::server::response::end`` sends responde body.
In the above example, we send string "hello, world".
Serving static files and enabling SSL/TLS
+++++++++++++++++++++++++++++++++++++++++
In this example, we serve a couple of static files and also enable
SSL/TLS.
.. code-block:: cpp
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
http2 server;
server.tls("server.key", "server.crt");
server.listen("*", 3000, [](const std::shared_ptr<request> &req,
const std::shared_ptr<response> &res) {
if (req->path() == "/" || req->path() == "/index.html") {
res->write_head(200);
res->end(file_reader("index.html"));
} else {
res->write_head(404);
res->end("<html><head><title>404</title></head>"
"<body>404 Not Found</body></html>");
}
});
}
Specifying path to private key file and certificate file in
``nghttp2::asio_http2::server::http2::tls`` will enable SSL/TLS. Both
files must be in PEM format.
In the above example, if request path is either "/" or "/index.html",
we serve index.html file in the current working directory.
``nghttp2::asio_http2::server::response::end`` has overload to take
function of type ``nghttp2::asio_http2::read_cb`` and application pass
its implementation to generate response body. For the convenience,
libnghttp2_asio library provides ``nghttp2::asio_http2::file_reader``
function to generate function to server static file.
Server push
+++++++++++
Server push is also supported.
.. code-block:: cpp
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
http2 server;
server.tls("server.key", "server.crt");
server.listen("*", 3000, [](const std::shared_ptr<request> &req,
const std::shared_ptr<response> &res) {
if (req->path() == "/") {
req->push("GET", "/my.css");
res->write_head(200);
res->end(file_reader("index.html"));
return;
}
if (req->path() == "/my.css") {
res->write_head(200);
res->end(file_reader("my.css"));
return;
}
res->write_head(404);
res->end("<html><head><title>404</title></head>"
"<body>404 Not Found</body></html>");
});
}
When client requested "/", we push "/my.css". To push resource, call
``nghttp2::asio_http2::server::request::push`` function with desired
method and path. Later, the callback will be called with the pushed
resource "/my.css".
Enable multi-threading
++++++++++++++++++++++
Enabling multi-threading is very easy. Just call
``nghttp2::asio_http2::server::http2::num_threads`` function with the
desired number of threads:
.. code-block:: cpp
http2 server;
// Use 4 native threads
server.num_threads(4);
Run blocking tasks in background thread
+++++++++++++++++++++++++++++++++++++++
The request callback is called in the same thread where HTTP request
is handled. And many connections shares the same thread, we cannot
directly run blocking tasks in request callback.
To run blocking tasks, use
``nghttp2::asio_http2::server::request::run_task``. The passed
callback will be executed in the different thread from the thread
where request callback was executed. So application can perform
blocking task there. The example follows:
.. code-block:: cpp
#include <unistd.h>
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
http2 server;
server.num_concurrent_tasks(16);
server.listen("*", 3000, [](const std::shared_ptr<request> &req,
const std::shared_ptr<response> &res) {
req->run_task([res](channel &channel) {
// executed in different thread than the thread where
// request callback was executed.
// using res directly here is not safe. Capturing it by
// value is safe because it is std::shared_ptr.
sleep(1);
channel.post([res]() {
// executed in the same thread where request callback
// was executed.
res->write_head(200);
res->end("hello, world");
});
});
});
}
First we set the number of background threads which run tasks. By
default it is set to 1. In this example, we set it to 16, so at most
16 tasks can be executed concurrently without blocking handling new
requests.
We call ``req->run_task()`` to execute task in background thread. In
the passed callback, we just simply sleeps 1 second. After sleep is
over, we schedule another callback to send response to the client.
Since the callback passed to ``req->run_task()`` is executed in the
different thread from the thread where request callback is called,
using ``req`` or ``res`` object directly there may cause undefined
behaviour. To avoid this issue, we can use
``nghttp2::asio_http2::channel::post`` by supplying a callback which
in turn get called in the same thread where request callback was
called.

View File

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

View File

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

View File

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

View File

@@ -29,17 +29,17 @@ time::
static unsigned char next_proto_list[256];
static size_t next_proto_list_len;
static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
void *arg)
{
static int next_proto_cb(SSL *s _U_, const unsigned char **data,
unsigned int *len, void *arg _U_) {
*data = next_proto_list;
*len = (unsigned int)next_proto_list_len;
return SSL_TLSEXT_ERR_OK;
}
static SSL_CTX* create_ssl_ctx(const char *key_file, const char *cert_file)
{
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
SSL_CTX *ssl_ctx;
EC_KEY *ecdh;
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
...
@@ -79,7 +79,6 @@ We use the ``http2_session_data`` structure to store session-level
app_context *app_ctx;
nghttp2_session *session;
char *client_addr;
size_t handshake_leftlen;
} http2_session_data;
We use the ``http2_stream_data`` structure to store stream-level data::
@@ -91,24 +90,21 @@ We use the ``http2_stream_data`` structure to store stream-level data::
int fd;
} http2_stream_data;
A single HTTP/2 session can have multiple streams. We manage these multiple
streams with a doubly linked list. The first element of this list is pointed
to by the ``root->next`` in ``http2_session_data``. Initially, ``root->next``
is ``NULL``. The ``handshake_leftlen`` member of ``http2_session_data`` is
used to track the number of bytes remaining when receiving the first client
connection preface (:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`), which is a 24
bytes long magic string from the client. We use libevent's bufferevent
structure to perform network I/O. Note that the bufferevent object is kept in
``http2_session_data`` and not in ``http2_stream_data``. This is because
``http2_stream_data`` is just a logical stream multiplexed over the single
connection managed by bufferevent in ``http2_session_data``.
A single HTTP/2 session can have multiple streams. We manage these
multiple streams with a doubly linked list. The first element of this
list is pointed to by the ``root->next`` in ``http2_session_data``.
Initially, ``root->next`` is ``NULL``. We use libevent's bufferevent
structure to perform network I/O. Note that the bufferevent object is
kept in ``http2_session_data`` and not in ``http2_stream_data``. This
is because ``http2_stream_data`` is just a logical stream multiplexed
over the single connection managed by bufferevent in
``http2_session_data``.
We first create a listener object to accept incoming connections. We use
libevent's ``struct evconnlistener`` for this purpose::
static void start_listen(struct event_base *evbase, const char *service,
app_context *app_ctx)
{
app_context *app_ctx) {
int rv;
struct addrinfo hints;
struct addrinfo *res, *rp;
@@ -119,19 +115,20 @@ libevent's ``struct evconnlistener`` for this purpose::
hints.ai_flags = AI_PASSIVE;
#ifdef AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG;
#endif // AI_ADDRCONFIG
#endif /* AI_ADDRCONFIG */
rv = getaddrinfo(NULL, service, &hints, &res);
if(rv != 0) {
if (rv != 0) {
errx(1, NULL);
}
for(rp = res; rp; rp = rp->ai_next) {
for (rp = res; rp; rp = rp->ai_next) {
struct evconnlistener *listener;
listener = evconnlistener_new_bind(evbase, acceptcb, app_ctx,
LEV_OPT_CLOSE_ON_FREE |
LEV_OPT_REUSEABLE, -1,
rp->ai_addr, rp->ai_addrlen);
if(listener) {
listener = evconnlistener_new_bind(
evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
16, rp->ai_addr, rp->ai_addrlen);
if (listener) {
freeaddrinfo(res);
return;
}
}
@@ -141,134 +138,113 @@ libevent's ``struct evconnlistener`` for this purpose::
We specify the ``acceptcb`` callback which is called when a new connection is
accepted::
static void acceptcb(struct evconnlistener *listener, int fd,
struct sockaddr *addr, int addrlen, void *arg)
{
app_context *app_ctx = (app_context*)arg;
static void acceptcb(struct evconnlistener *listener _U_, int fd,
struct sockaddr *addr, int addrlen, void *arg) {
app_context *app_ctx = (app_context *)arg;
http2_session_data *session_data;
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
bufferevent_setcb(session_data->bev, handshake_readcb, NULL, eventcb,
session_data);
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data);
}
Here we create the ``http2_session_data`` object. The bufferevent for this
connection is also initialized at this time. We specify two callbacks for the
bufferevent: ``handshake_readcb`` and ``eventcb``.
Here we create the ``http2_session_data`` object. The bufferevent for
this connection is also initialized at this time. We specify three
callbacks for the bufferevent: ``readcb``, ``writecb`` and
``eventcb``.
The ``eventcb()`` callback is invoked by the libevent event loop when an event
(e.g., connection has been established, timeout, etc) happens on the
underlying network socket::
static void eventcb(struct bufferevent *bev, short events, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(events & BEV_EVENT_CONNECTED) {
static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (events & BEV_EVENT_CONNECTED) {
fprintf(stderr, "%s connected\n", session_data->client_addr);
initialize_nghttp2_session(session_data);
if (send_server_connection_header(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
if(events & BEV_EVENT_EOF) {
return;
}
if (events & BEV_EVENT_EOF) {
fprintf(stderr, "%s EOF\n", session_data->client_addr);
} else if(events & BEV_EVENT_ERROR) {
} else if (events & BEV_EVENT_ERROR) {
fprintf(stderr, "%s network error\n", session_data->client_addr);
} else if(events & BEV_EVENT_TIMEOUT) {
} else if (events & BEV_EVENT_TIMEOUT) {
fprintf(stderr, "%s timeout\n", session_data->client_addr);
}
delete_http2_session_data(session_data);
}
For the ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR`` and ``BEV_EVENT_TIMEOUT``
events, we just simply tear down the connection. The
``delete_http2_session_data()`` function destroys the ``http2_session_data``
object and thus also its bufferevent member. As a result, the underlying
connection is closed. The ``BEV_EVENT_CONNECTED`` event is invoked when
SSL/TLS handshake is finished successfully.
``handshake_readcb()`` is a callback function to handle a 24 bytes magic byte
string coming from a client, since the nghttp2 library does not handle it::
static void handshake_readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
uint8_t data[24];
struct evbuffer *input = bufferevent_get_input(session_data->bev);
int readlen = evbuffer_remove(input, data, session_data->handshake_leftlen);
const char *conhead = NGHTTP2_CLIENT_CONNECTION_PREFACE;
if(memcmp(conhead + NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
- session_data->handshake_leftlen, data, readlen) != 0) {
delete_http2_session_data(session_data);
return;
}
session_data->handshake_leftlen -= readlen;
if(session_data->handshake_leftlen == 0) {
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, ptr);
/* Process pending data in buffer since they are not notified
further */
initialize_nghttp2_session(session_data);
if(send_server_connection_header(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
if(session_recv(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
}
}
We check that the received byte string matches
:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`. When they match, the connection
state is ready to start the HTTP/2 communication. First we change the callback
functions for the bufferevent object. We use the same ``eventcb`` callback as
before, but we specify new ``readcb`` and ``writecb`` functions to handle the
HTTP/2 communication. These two functions are described later.
For the ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR`` and
``BEV_EVENT_TIMEOUT`` events, we just simply tear down the connection.
The ``delete_http2_session_data()`` function destroys the
``http2_session_data`` object and thus also its bufferevent member.
As a result, the underlying connection is closed. The
``BEV_EVENT_CONNECTED`` event is invoked when SSL/TLS handshake is
finished successfully. Now we are ready to start the HTTP/2
communication.
We initialize a nghttp2 session object which is done in
``initialize_nghttp2_session()``::
static void initialize_nghttp2_session(http2_session_data *session_data)
{
static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_option *option;
nghttp2_session_callbacks *callbacks;
nghttp2_option_new(&option);
/* Tells nghttp2_session object that it handles client connection
preface */
nghttp2_option_set_recv_client_preface(option, 1);
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback
(callbacks, on_frame_recv_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback
(callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback
(callbacks, on_header_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback
(callbacks, on_begin_headers_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
nghttp2_session_server_new(&session_data->session, callbacks, session_data);
nghttp2_session_server_new2(&session_data->session, callbacks, session_data,
option);
nghttp2_session_callbacks_del(callbacks);
nghttp2_option_del(option);
}
Since we are creating a server, the nghttp2 session object is created using
`nghttp2_session_server_new()` function. We registers five callbacks for
nghttp2 session object. We'll talk about these callbacks later.
Since we are creating a server and uses options, the nghttp2 session
object is created using `nghttp2_session_server_new2()` function. We
registers five callbacks for nghttp2 session object. We'll talk about
these callbacks later. Our server only speaks HTTP/2. In this case,
we use `nghttp2_option_set_recv_client_preface()` to make
:type:`nghttp2_session` object handle client connection preface, which
saves some lines of application code.
After initialization of the nghttp2 session object, we are going to send
a server connection header in ``send_server_connection_header()``::
static int send_server_connection_header(http2_session_data *session_data)
{
static int send_server_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = {
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
};
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE,
iv, ARRLEN(iv));
if(rv != 0) {
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv));
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -289,23 +265,22 @@ have to process them here since libevent won't invoke callback functions for
this pending data. To process the received data, we call the
``session_recv()`` function::
static int session_recv(http2_session_data *session_data)
{
static int session_recv(http2_session_data *session_data) {
ssize_t readlen;
struct evbuffer *input = bufferevent_get_input(session_data->bev);
size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
if(readlen < 0) {
if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
return -1;
}
if(evbuffer_drain(input, readlen) != 0) {
if (evbuffer_drain(input, readlen) != 0) {
warnx("Fatal error: evbuffer_drain failed");
return -1;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
return -1;
}
return 0;
@@ -318,11 +293,10 @@ nghttp2 callbacks and also queue outgoing frames. Since there may be pending
outgoing frames, we call ``session_send()`` function to send off those
frames. The ``session_send()`` function is defined as follows::
static int session_send(http2_session_data *session_data)
{
static int session_send(http2_session_data *session_data) {
int rv;
rv = nghttp2_session_send(session_data->session);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -334,14 +308,12 @@ format and calls ``send_callback()`` of type
:type:`nghttp2_send_callback`. The ``send_callback()`` is defined as
follows::
static ssize_t send_callback(nghttp2_session *session,
const uint8_t *data, size_t length,
int flags, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
size_t length, int flags _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev;
/* Avoid excessive buffering in server side. */
if(evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
OUTPUT_WOULDBLOCK_THRESHOLD) {
return NGHTTP2_ERR_WOULDBLOCK;
}
@@ -367,10 +339,9 @@ calling send_callback.
The next bufferevent callback is ``readcb()``, which is invoked when
data is available to read in the bufferevent input buffer::
static void readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(session_recv(session_data) != 0) {
static void readcb(struct bufferevent *bev _U_, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (session_recv(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
@@ -382,18 +353,17 @@ data.
The third bufferevent callback is ``writecb()``, which is invoked when all
data in the bufferevent output buffer has been sent::
static void writecb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
static void writecb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
return;
}
if(nghttp2_session_want_read(session_data->session) == 0 &&
if (nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0) {
delete_http2_session_data(session_data);
return;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
@@ -424,12 +394,11 @@ a header block in HEADERS or PUSH_PROMISE frame is started::
static int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
if(frame->hd.type != NGHTTP2_HEADERS ||
if (frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
@@ -453,26 +422,26 @@ emitted via ``on_header_callback`` function, which is called after
``on_begin_headers_callback()``::
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
void *user_data)
{
const nghttp2_frame *frame, const uint8_t *name,
size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags _U_,
void *user_data _U_) {
http2_stream_data *stream_data;
const char PATH[] = ":path";
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
break;
}
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if(!stream_data || stream_data->request_path) {
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (!stream_data || stream_data->request_path) {
break;
}
if(namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
size_t j;
for(j = 0; j < valuelen && value[j] != '?'; ++j);
for (j = 0; j < valuelen && value[j] != '?'; ++j)
;
stream_data->request_path = percent_decode(value, j);
}
break;
@@ -489,20 +458,19 @@ The ``on_frame_recv_callback()`` function is invoked when a frame is
fully received::
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
const nghttp2_frame *frame, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_DATA:
case NGHTTP2_HEADERS:
/* Check that the client request has finished */
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
/* For DATA and HEADERS frame, this callback may be called after
on_stream_close_callback. Check that stream still alive. */
if(!stream_data) {
if (!stream_data) {
return 0;
}
return on_request_recv(session, session_data, stream_data);
@@ -525,15 +493,14 @@ header.
Sending the content of the file is done in ``send_response()`` function::
static int send_response(nghttp2_session *session, int32_t stream_id,
nghttp2_nv *nva, size_t nvlen, int fd)
{
nghttp2_nv *nva, size_t nvlen, int fd) {
int rv;
nghttp2_data_provider data_prd;
data_prd.source.fd = fd;
data_prd.read_callback = file_read_callback;
rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -547,18 +514,19 @@ intended to be used as file descriptor. In this example server, we use
the file descriptor. We also set the ``file_read_callback()`` callback
function to read the contents of the file::
static ssize_t file_read_callback
(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length, uint32_t *data_flags,
nghttp2_data_source *source, void *user_data)
{
static ssize_t file_read_callback(nghttp2_session *session _U_,
int32_t stream_id _U_, uint8_t *buf,
size_t length, uint32_t *data_flags,
nghttp2_data_source *source,
void *user_data _U_) {
int fd = source->fd;
ssize_t r;
while((r = read(fd, buf, length)) == -1 && errno == EINTR);
if(r == -1) {
while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
;
if (r == -1) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if(r == 0) {
if (r == 0) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
}
return r;
@@ -576,16 +544,13 @@ remote peer.
The ``on_stream_close_callback()`` function is invoked when the stream
is about to close::
static int on_stream_close_callback(nghttp2_session *session,
int32_t stream_id,
nghttp2_error_code error_code,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
if(!stream_data) {
if (!stream_data) {
return 0;
}
remove_stream(session_data, stream_data);

4
examples/.gitignore vendored
View File

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

View File

@@ -23,20 +23,20 @@
if ENABLE_EXAMPLES
AM_CFLAGS = $(WARNCFLAGS)
AM_CPPFLAGS = \
-Wall \
-I$(top_srcdir)/lib/includes \
-I$(top_builddir)/lib/includes \
-I$(top_srcdir)/src/includes \
-I$(top_srcdir)/third-party \
@LIBEVENT_OPENSSL_CFLAGS@ \
@OPENSSL_CFLAGS@ \
@DEFS@
AM_LDFLAGS = \
LDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/libhttp-parser.la \
@LIBEVENT_OPENSSL_LIBS@ \
@OPENSSL_LIBS@
LDADD = \
$(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/libhttp-parser.la
noinst_PROGRAMS = client libevent-client libevent-server deflate
@@ -48,4 +48,33 @@ libevent_server_SOURCES = libevent-server.c
deflate_SOURCES = deflate.c
if ENABLE_TINY_NGHTTPD
noinst_PROGRAMS += tiny-nghttpd
tiny_nghttpd_SOURCES = tiny-nghttpd.c
endif # ENABLE_TINY_NGHTTPD
if ENABLE_ASIO_LIB
noinst_PROGRAMS += asio-sv asio-sv2 asio-sv3
ASIOCPPFLAGS = ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
ASIOLDADD = $(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@
asio_sv_SOURCES = asio-sv.cc
asio_sv_CPPFLAGS = ${ASIOCPPFLAGS}
asio_sv_LDADD = ${ASIOLDADD}
asio_sv2_SOURCES = asio-sv2.cc
asio_sv2_CPPFLAGS = ${ASIOCPPFLAGS}
asio_sv2_LDADD = ${ASIOLDADD}
asio_sv3_SOURCES = asio-sv3.cc
asio_sv3_CPPFLAGS = ${ASIOCPPFLAGS}
asio_sv3_LDADD = ${ASIOLDADD}
endif # ENABLE_ASIO_LIB
endif # ENABLE_EXAMPLES

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

@@ -0,0 +1,75 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// We wrote this code based on the original code which has the
// following license:
//
// main.cpp
// ~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <iostream>
#include <string>
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
try {
// Check command line arguments.
if (argc < 3) {
std::cerr << "Usage: asio-sv <port> <threads> <private-key-file> "
<< "<cert-file>\n";
return 1;
}
uint16_t port = std::stoi(argv[1]);
std::size_t num_threads = std::stoi(argv[2]);
http2 server;
server.num_threads(num_threads);
if (argc >= 5) {
server.tls(argv[3], argv[4]);
}
server.listen("*", port, [](const std::shared_ptr<request> &req,
const std::shared_ptr<response> &res) {
res->write_head(200, {header{"foo", "bar"}});
res->end("hello, world");
});
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}

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

@@ -0,0 +1,107 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// We wrote this code based on the original code which has the
// following license:
//
// main.cpp
// ~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#include <string>
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
try {
// Check command line arguments.
if (argc < 4) {
std::cerr << "Usage: asio-sv2 <port> <threads> <doc-root> "
<< "<private-key-file> <cert-file>\n";
return 1;
}
uint16_t port = std::stoi(argv[1]);
std::size_t num_threads = std::stoi(argv[2]);
std::string docroot = argv[3];
http2 server;
server.num_threads(num_threads);
if (argc >= 6) {
server.tls(argv[4], argv[5]);
}
server.listen("*", port, [&docroot](const std::shared_ptr<request> &req,
const std::shared_ptr<response> &res) {
auto path = percent_decode(req->path());
if (!check_path(path)) {
res->write_head(404);
res->end();
return;
}
if (path == "/") {
path = "/index.html";
}
path = docroot + path;
auto fd = open(path.c_str(), O_RDONLY);
if (fd == -1) {
res->write_head(404);
res->end();
return;
}
auto headers = std::vector<header>();
struct stat stbuf;
if (stat(path.c_str(), &stbuf) == 0) {
headers.push_back(
header{"content-length", std::to_string(stbuf.st_size)});
headers.push_back(
header{"last-modified", http_date(stbuf.st_mtim.tv_sec)});
}
res->write_head(200, std::move(headers));
res->end(file_reader_from_fd(fd));
});
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}

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

@@ -0,0 +1,142 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// We wrote this code based on the original code which has the
// following license:
//
// main.cpp
// ~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <unistd.h>
#include <iostream>
#include <string>
#include <deque>
#include <nghttp2/asio_http2.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
try {
// Check command line arguments.
if (argc < 4) {
std::cerr << "Usage: asio-sv3 <port> <threads> <tasks> "
<< " <private-key-file> <cert-file>\n";
return 1;
}
uint16_t port = std::stoi(argv[1]);
std::size_t num_threads = std::stoi(argv[2]);
std::size_t num_concurrent_tasks = std::stoi(argv[3]);
http2 server;
server.num_threads(num_threads);
if (argc >= 5) {
server.tls(argv[4], argv[5]);
}
server.num_concurrent_tasks(num_concurrent_tasks);
server.listen("*", port, [](const std::shared_ptr<request> &req,
const std::shared_ptr<response> &res) {
res->write_head(200);
auto msgq = std::make_shared<std::deque<std::string>>();
res->end([msgq](uint8_t * buf, std::size_t len)
-> std::pair<ssize_t, bool> {
if (msgq->empty()) {
// if msgq is empty, tells the library that don't call
// this callback until we call res->resume(). This is
// done by returing std::make_pair(0, false).
return std::make_pair(0, false);
}
auto msg = std::move(msgq->front());
msgq->pop_front();
if (msg.empty()) {
// The empty message signals the end of response in
// this simple protocol.
return std::make_pair(0, true);
}
auto nwrite = std::min(len, msg.size());
std::copy(std::begin(msg), std::begin(msg) + nwrite, buf);
if (msg.size() > nwrite) {
msgq->push_front(msg.substr(nwrite));
}
return std::make_pair(nwrite, false);
});
req->run_task([res, msgq](channel &channel) {
// executed in different thread from request callback
// was called.
// Using res and msgq is not safe inside this callback.
// But using them in callback passed to channel::post is
// safe.
// We just emit simple message "message N\n" in every 1
// second and 3 times in total.
for (std::size_t i = 0; i < 3; ++i) {
msgq->push_back("message " + std::to_string(i + 1) + "\n");
channel.post([res]() {
// executed in same thread where
// request callback was called.
// Tells library we have new message.
res->resume();
});
sleep(1);
}
// Send empty message to signal the end of response
// body.
msgq->push_back("");
channel.post([res]() {
// executed in same thread where request
// callback was called.
res->resume();
});
});
});
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}

View File

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

View File

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

View File

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

View File

@@ -22,6 +22,10 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* !HAVE_CONFIG_H */
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
@@ -47,11 +51,13 @@
#define OUTPUT_WOULDBLOCK_THRESHOLD (1 << 16)
#define ARRLEN(x) (sizeof(x)/sizeof(x[0]))
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
#define MAKE_NV(NAME, VALUE) \
{ (uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE }
{ \
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
struct app_context;
typedef struct app_context app_context;
@@ -69,7 +75,6 @@ typedef struct http2_session_data {
app_context *app_ctx;
nghttp2_session *session;
char *client_addr;
size_t handshake_leftlen;
} http2_session_data;
struct app_context {
@@ -80,32 +85,40 @@ struct app_context {
static unsigned char next_proto_list[256];
static size_t next_proto_list_len;
static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
void *arg)
{
static int next_proto_cb(SSL *s _U_, const unsigned char **data,
unsigned int *len, void *arg _U_) {
*data = next_proto_list;
*len = (unsigned int)next_proto_list_len;
return SSL_TLSEXT_ERR_OK;
}
/* Create SSL_CTX. */
static SSL_CTX* create_ssl_ctx(const char *key_file, const char *cert_file)
{
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
SSL_CTX *ssl_ctx;
EC_KEY *ecdh;
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if(!ssl_ctx) {
if (!ssl_ctx) {
errx(1, "Could not create SSL/TLS context: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION |
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
if(SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file,
SSL_FILETYPE_PEM) != 1) {
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (!ecdh) {
errx(1, "EC_KEY_new_by_curv_name failed: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
EC_KEY_free(ecdh);
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
errx(1, "Could not read private key file %s", key_file);
}
if(SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
errx(1, "Could not read certificate file %s", cert_file);
}
@@ -119,11 +132,10 @@ static SSL_CTX* create_ssl_ctx(const char *key_file, const char *cert_file)
}
/* Create SSL object */
static SSL* create_ssl(SSL_CTX *ssl_ctx)
{
static SSL *create_ssl(SSL_CTX *ssl_ctx) {
SSL *ssl;
ssl = SSL_new(ssl_ctx);
if(!ssl) {
if (!ssl) {
errx(1, "Could not create SSL/TLS session object: %s",
ERR_error_string(ERR_get_error(), NULL));
}
@@ -131,28 +143,25 @@ static SSL* create_ssl(SSL_CTX *ssl_ctx)
}
static void add_stream(http2_session_data *session_data,
http2_stream_data *stream_data)
{
http2_stream_data *stream_data) {
stream_data->next = session_data->root.next;
session_data->root.next = stream_data;
stream_data->prev = &session_data->root;
if(stream_data->next) {
if (stream_data->next) {
stream_data->next->prev = stream_data;
}
}
static void remove_stream(http2_session_data *session_data,
http2_stream_data *stream_data)
{
static void remove_stream(http2_session_data *session_data _U_,
http2_stream_data *stream_data) {
stream_data->prev->next = stream_data->next;
if(stream_data->next) {
if (stream_data->next) {
stream_data->next->prev = stream_data->prev;
}
}
static http2_stream_data* create_http2_stream_data
(http2_session_data *session_data, int32_t stream_id)
{
static http2_stream_data *
create_http2_stream_data(http2_session_data *session_data, int32_t stream_id) {
http2_stream_data *stream_data;
stream_data = malloc(sizeof(http2_stream_data));
memset(stream_data, 0, sizeof(http2_stream_data));
@@ -163,20 +172,18 @@ static http2_stream_data* create_http2_stream_data
return stream_data;
}
static void delete_http2_stream_data(http2_stream_data *stream_data)
{
if(stream_data->fd != -1) {
static void delete_http2_stream_data(http2_stream_data *stream_data) {
if (stream_data->fd != -1) {
close(stream_data->fd);
}
free(stream_data->request_path);
free(stream_data);
}
static http2_session_data* create_http2_session_data(app_context *app_ctx,
static http2_session_data *create_http2_session_data(app_context *app_ctx,
int fd,
struct sockaddr *addr,
int addrlen)
{
int addrlen) {
int rv;
http2_session_data *session_data;
SSL *ssl;
@@ -188,13 +195,11 @@ static http2_session_data* create_http2_session_data(app_context *app_ctx,
memset(session_data, 0, sizeof(http2_session_data));
session_data->app_ctx = app_ctx;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
session_data->bev = bufferevent_openssl_socket_new
(app_ctx->evbase, fd, ssl,
BUFFEREVENT_SSL_ACCEPTING,
session_data->bev = bufferevent_openssl_socket_new(
app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
session_data->handshake_leftlen = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN;
rv = getnameinfo(addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
if(rv != 0) {
if (rv != 0) {
session_data->client_addr = strdup("(unknown)");
} else {
session_data->client_addr = strdup(host);
@@ -203,17 +208,16 @@ static http2_session_data* create_http2_session_data(app_context *app_ctx,
return session_data;
}
static void delete_http2_session_data(http2_session_data *session_data)
{
static void delete_http2_session_data(http2_session_data *session_data) {
http2_stream_data *stream_data;
SSL *ssl = bufferevent_openssl_get_ssl(session_data->bev);
fprintf(stderr, "%s disconnected\n", session_data->client_addr);
if(ssl) {
if (ssl) {
SSL_shutdown(ssl);
}
bufferevent_free(session_data->bev);
nghttp2_session_del(session_data->session);
for(stream_data = session_data->root.next; stream_data;) {
for (stream_data = session_data->root.next; stream_data;) {
http2_stream_data *next = stream_data->next;
delete_http2_stream_data(stream_data);
stream_data = next;
@@ -224,11 +228,10 @@ static void delete_http2_session_data(http2_session_data *session_data)
/* Serialize the frame and send (or buffer) the data to
bufferevent. */
static int session_send(http2_session_data *session_data)
{
static int session_send(http2_session_data *session_data) {
int rv;
rv = nghttp2_session_send(session_data->session);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -239,36 +242,33 @@ static int session_send(http2_session_data *session_data)
function. Invocation of nghttp2_session_mem_recv() may make
additional pending frames, so call session_send() at the end of the
function. */
static int session_recv(http2_session_data *session_data)
{
static int session_recv(http2_session_data *session_data) {
ssize_t readlen;
struct evbuffer *input = bufferevent_get_input(session_data->bev);
size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
if(readlen < 0) {
if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
return -1;
}
if(evbuffer_drain(input, readlen) != 0) {
if (evbuffer_drain(input, readlen) != 0) {
warnx("Fatal error: evbuffer_drain failed");
return -1;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
return -1;
}
return 0;
}
static ssize_t send_callback(nghttp2_session *session,
const uint8_t *data, size_t length,
int flags, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
size_t length, int flags _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev;
/* Avoid excessive buffering in server side. */
if(evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
OUTPUT_WOULDBLOCK_THRESHOLD) {
return NGHTTP2_ERR_WOULDBLOCK;
}
@@ -277,26 +277,24 @@ static ssize_t send_callback(nghttp2_session *session,
}
/* Returns nonzero if the string |s| ends with the substring |sub| */
static int ends_with(const char *s, const char *sub)
{
static int ends_with(const char *s, const char *sub) {
size_t slen = strlen(s);
size_t sublen = strlen(sub);
if(slen < sublen) {
if (slen < sublen) {
return 0;
}
return memcmp(s + slen - sublen, sub, sublen) == 0;
}
/* Returns int value of hex string character |c| */
static uint8_t hex_to_uint(uint8_t c)
{
if('0' <= c && c <= '9') {
static uint8_t hex_to_uint(uint8_t c) {
if ('0' <= c && c <= '9') {
return c - '0';
}
if('A' <= c && c <= 'F') {
if ('A' <= c && c <= 'F') {
return c - 'A' + 10;
}
if('a' <= c && c <= 'f') {
if ('a' <= c && c <= 'f') {
return c - 'a' + 10;
}
return 0;
@@ -306,16 +304,15 @@ static uint8_t hex_to_uint(uint8_t c)
and returns the decoded byte string in allocated buffer. The return
value is NULL terminated. The caller must free the returned
string. */
static char* percent_decode(const uint8_t *value, size_t valuelen)
{
static char *percent_decode(const uint8_t *value, size_t valuelen) {
char *res;
res = malloc(valuelen + 1);
if(valuelen > 3) {
if (valuelen > 3) {
size_t i, j;
for(i = 0, j = 0; i < valuelen - 2;) {
if(value[i] != '%' ||
!isxdigit(value[i + 1]) || !isxdigit(value[i + 2])) {
for (i = 0, j = 0; i < valuelen - 2;) {
if (value[i] != '%' || !isxdigit(value[i + 1]) ||
!isxdigit(value[i + 2])) {
res[j++] = value[i++];
continue;
}
@@ -331,33 +328,33 @@ static char* percent_decode(const uint8_t *value, size_t valuelen)
return res;
}
static ssize_t file_read_callback
(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length, uint32_t *data_flags,
nghttp2_data_source *source, void *user_data)
{
static ssize_t file_read_callback(nghttp2_session *session _U_,
int32_t stream_id _U_, uint8_t *buf,
size_t length, uint32_t *data_flags,
nghttp2_data_source *source,
void *user_data _U_) {
int fd = source->fd;
ssize_t r;
while((r = read(fd, buf, length)) == -1 && errno == EINTR);
if(r == -1) {
while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
;
if (r == -1) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if(r == 0) {
if (r == 0) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
}
return r;
}
static int send_response(nghttp2_session *session, int32_t stream_id,
nghttp2_nv *nva, size_t nvlen, int fd)
{
nghttp2_nv *nva, size_t nvlen, int fd) {
int rv;
nghttp2_data_provider data_prd;
data_prd.source.fd = fd;
data_prd.read_callback = file_read_callback;
rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -368,22 +365,19 @@ const char ERROR_HTML[] = "<html><head><title>404</title></head>"
"<body><h1>404 Not Found</h1></body></html>";
static int error_reply(nghttp2_session *session,
http2_stream_data *stream_data)
{
http2_stream_data *stream_data) {
int rv;
ssize_t writelen;
int pipefd[2];
nghttp2_nv hdrs[] = {
MAKE_NV(":status", "404")
};
nghttp2_nv hdrs[] = {MAKE_NV(":status", "404")};
rv = pipe(pipefd);
if(rv != 0) {
if (rv != 0) {
warn("Could not create pipe");
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
stream_data->stream_id,
NGHTTP2_INTERNAL_ERROR);
if(rv != 0) {
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -393,14 +387,14 @@ static int error_reply(nghttp2_session *session,
writelen = write(pipefd[1], ERROR_HTML, sizeof(ERROR_HTML) - 1);
close(pipefd[1]);
if(writelen != sizeof(ERROR_HTML) - 1) {
if (writelen != sizeof(ERROR_HTML) - 1) {
close(pipefd[0]);
return -1;
}
stream_data->fd = pipefd[0];
if(send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs),
if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs),
pipefd[0]) != 0) {
close(pipefd[0]);
return -1;
@@ -411,27 +405,26 @@ static int error_reply(nghttp2_session *session,
/* nghttp2_on_header_callback: Called when nghttp2 library emits
single header name/value pair. */
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
uint8_t flags,
void *user_data)
{
const nghttp2_frame *frame, const uint8_t *name,
size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags _U_,
void *user_data _U_) {
http2_stream_data *stream_data;
const char PATH[] = ":path";
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
break;
}
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if(!stream_data || stream_data->request_path) {
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (!stream_data || stream_data->request_path) {
break;
}
if(namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
size_t j;
for(j = 0; j < valuelen && value[j] != '?'; ++j);
for (j = 0; j < valuelen && value[j] != '?'; ++j)
;
stream_data->request_path = percent_decode(value, j);
}
break;
@@ -441,12 +434,11 @@ static int on_header_callback(nghttp2_session *session,
static int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
if(frame->hd.type != NGHTTP2_HEADERS ||
if (frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
@@ -458,52 +450,47 @@ static int on_begin_headers_callback(nghttp2_session *session,
/* Minimum check for directory traversal. Returns nonzero if it is
safe. */
static int check_path(const char *path)
{
static int check_path(const char *path) {
/* We don't like '\' in url. */
return path[0] && path[0] == '/' &&
strchr(path, '\\') == NULL &&
strstr(path, "/../") == NULL &&
strstr(path, "/./") == NULL &&
return path[0] && path[0] == '/' && strchr(path, '\\') == NULL &&
strstr(path, "/../") == NULL && strstr(path, "/./") == NULL &&
!ends_with(path, "/..") && !ends_with(path, "/.");
}
static int on_request_recv(nghttp2_session *session,
http2_session_data *session_data,
http2_stream_data *stream_data)
{
http2_stream_data *stream_data) {
int fd;
nghttp2_nv hdrs[] = {
MAKE_NV(":status", "200")
};
nghttp2_nv hdrs[] = {MAKE_NV(":status", "200")};
char *rel_path;
if(!stream_data->request_path) {
if(error_reply(session, stream_data) != 0) {
if (!stream_data->request_path) {
if (error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
fprintf(stderr, "%s GET %s\n", session_data->client_addr,
stream_data->request_path);
if(!check_path(stream_data->request_path)) {
if(error_reply(session, stream_data) != 0) {
if (!check_path(stream_data->request_path)) {
if (error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
for(rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path);
for (rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path)
;
fd = open(rel_path, O_RDONLY);
if(fd == -1) {
if(error_reply(session, stream_data) != 0) {
if (fd == -1) {
if (error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
stream_data->fd = fd;
if(send_response(session, stream_data->stream_id, hdrs,
ARRLEN(hdrs), fd) != 0) {
if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs), fd) !=
0) {
close(fd);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
@@ -511,20 +498,19 @@ static int on_request_recv(nghttp2_session *session,
}
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
const nghttp2_frame *frame, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
switch(frame->hd.type) {
switch (frame->hd.type) {
case NGHTTP2_DATA:
case NGHTTP2_HEADERS:
/* Check that the client request has finished */
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
/* For DATA and HEADERS frame, this callback may be called after
on_stream_close_callback. Check that stream still alive. */
if(!stream_data) {
if (!stream_data) {
return 0;
}
return on_request_recv(session, session_data, stream_data);
@@ -536,16 +522,13 @@ static int on_frame_recv_callback(nghttp2_session *session,
return 0;
}
static int on_stream_close_callback(nghttp2_session *session,
int32_t stream_id,
nghttp2_error_code error_code,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
if(!stream_data) {
if (!stream_data) {
return 0;
}
remove_stream(session_data, stream_data);
@@ -553,43 +536,49 @@ static int on_stream_close_callback(nghttp2_session *session,
return 0;
}
static void initialize_nghttp2_session(http2_session_data *session_data)
{
static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_option *option;
nghttp2_session_callbacks *callbacks;
nghttp2_option_new(&option);
/* Tells nghttp2_session object that it handles client connection
preface */
nghttp2_option_set_recv_client_preface(option, 1);
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback
(callbacks, on_frame_recv_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback
(callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback
(callbacks, on_header_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback
(callbacks, on_begin_headers_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
nghttp2_session_server_new(&session_data->session, callbacks, session_data);
nghttp2_session_server_new2(&session_data->session, callbacks, session_data,
option);
nghttp2_session_callbacks_del(callbacks);
nghttp2_option_del(option);
}
/* Send HTTP/2 client connection header, which includes 24 bytes
magic octets and SETTINGS frame */
static int send_server_connection_header(http2_session_data *session_data)
{
static int send_server_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = {
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
};
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE,
iv, ARRLEN(iv));
if(rv != 0) {
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv));
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
@@ -598,10 +587,9 @@ static int send_server_connection_header(http2_session_data *session_data)
/* readcb for bufferevent after client connection header was
checked. */
static void readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(session_recv(session_data) != 0) {
static void readcb(struct bufferevent *bev _U_, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (session_recv(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
@@ -615,88 +603,60 @@ static void readcb(struct bufferevent *bev, void *ptr)
process pending data in the output buffer. This is necessary
because we have a threshold on the buffer size to avoid too much
buffering. See send_callback(). */
static void writecb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
static void writecb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
return;
}
if(nghttp2_session_want_read(session_data->session) == 0 &&
if (nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0) {
delete_http2_session_data(session_data);
return;
}
if(session_send(session_data) != 0) {
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
}
/* eventcb for bufferevent */
static void eventcb(struct bufferevent *bev, short events, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
if(events & BEV_EVENT_CONNECTED) {
static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (events & BEV_EVENT_CONNECTED) {
fprintf(stderr, "%s connected\n", session_data->client_addr);
initialize_nghttp2_session(session_data);
if (send_server_connection_header(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
if(events & BEV_EVENT_EOF) {
return;
}
if (events & BEV_EVENT_EOF) {
fprintf(stderr, "%s EOF\n", session_data->client_addr);
} else if(events & BEV_EVENT_ERROR) {
} else if (events & BEV_EVENT_ERROR) {
fprintf(stderr, "%s network error\n", session_data->client_addr);
} else if(events & BEV_EVENT_TIMEOUT) {
} else if (events & BEV_EVENT_TIMEOUT) {
fprintf(stderr, "%s timeout\n", session_data->client_addr);
}
delete_http2_session_data(session_data);
}
/* readcb for bufferevent to check first 24 bytes client connection
header. */
static void handshake_readcb(struct bufferevent *bev, void *ptr)
{
http2_session_data *session_data = (http2_session_data*)ptr;
uint8_t data[24];
struct evbuffer *input = bufferevent_get_input(session_data->bev);
int readlen = evbuffer_remove(input, data, session_data->handshake_leftlen);
const char *conhead = NGHTTP2_CLIENT_CONNECTION_PREFACE;
if(memcmp(conhead + NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
- session_data->handshake_leftlen, data, readlen) != 0) {
delete_http2_session_data(session_data);
return;
}
session_data->handshake_leftlen -= readlen;
if(session_data->handshake_leftlen == 0) {
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, ptr);
/* Process pending data in buffer since they are not notified
further */
initialize_nghttp2_session(session_data);
if(send_server_connection_header(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
if(session_recv(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
}
}
/* callback for evconnlistener */
static void acceptcb(struct evconnlistener *listener, int fd,
struct sockaddr *addr, int addrlen, void *arg)
{
app_context *app_ctx = (app_context*)arg;
static void acceptcb(struct evconnlistener *listener _U_, int fd,
struct sockaddr *addr, int addrlen, void *arg) {
app_context *app_ctx = (app_context *)arg;
http2_session_data *session_data;
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
bufferevent_setcb(session_data->bev, handshake_readcb, NULL, eventcb,
session_data);
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data);
}
static void start_listen(struct event_base *evbase, const char *service,
app_context *app_ctx)
{
app_context *app_ctx) {
int rv;
struct addrinfo hints;
struct addrinfo *res, *rp;
@@ -710,16 +670,15 @@ static void start_listen(struct event_base *evbase, const char *service,
#endif /* AI_ADDRCONFIG */
rv = getaddrinfo(NULL, service, &hints, &res);
if(rv != 0) {
if (rv != 0) {
errx(1, NULL);
}
for(rp = res; rp; rp = rp->ai_next) {
for (rp = res; rp; rp = rp->ai_next) {
struct evconnlistener *listener;
listener = evconnlistener_new_bind(evbase, acceptcb, app_ctx,
LEV_OPT_CLOSE_ON_FREE |
LEV_OPT_REUSEABLE, 16,
rp->ai_addr, rp->ai_addrlen);
if(listener) {
listener = evconnlistener_new_bind(
evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
16, rp->ai_addr, rp->ai_addrlen);
if (listener) {
freeaddrinfo(res);
return;
@@ -729,16 +688,14 @@ static void start_listen(struct event_base *evbase, const char *service,
}
static void initialize_app_context(app_context *app_ctx, SSL_CTX *ssl_ctx,
struct event_base *evbase)
{
struct event_base *evbase) {
memset(app_ctx, 0, sizeof(app_context));
app_ctx->ssl_ctx = ssl_ctx;
app_ctx->evbase = evbase;
}
static void run(const char *service,
const char *key_file, const char *cert_file)
{
static void run(const char *service, const char *key_file,
const char *cert_file) {
SSL_CTX *ssl_ctx;
app_context app_ctx;
struct event_base *evbase;
@@ -754,11 +711,10 @@ static void run(const char *service,
SSL_CTX_free(ssl_ctx);
}
int main(int argc, char **argv)
{
int main(int argc, char **argv) {
struct sigaction act;
if(argc < 4) {
if (argc < 4) {
fprintf(stderr, "Usage: libevent-server PORT KEY_FILE CERT_FILE\n");
exit(EXIT_FAILURE);
}

1301
examples/tiny-nghttpd.c Normal file

File diff suppressed because it is too large Load Diff

30
gendowncasetbl.py Executable file
View File

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

98
genheaderfunc.py Executable file
View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python
HEADERS = [
':authority',
':method',
':path',
':scheme',
':status',
':host', # for spdy
'expect',
'host',
'if-modified-since',
"te",
"cookie",
"http2-settings",
"server",
"via",
"x-forwarded-for",
"x-forwarded-proto",
"alt-svc",
"content-length",
"location",
"trailer",
# disallowed h1 headers
'connection',
'keep-alive',
'proxy-connection',
'transfer-encoding',
'upgrade'
]
def to_enum_hd(k):
res = 'HD_'
for c in k.upper():
if c == ':' or c == '-':
res += '_'
continue
res += c
return res
def build_header(headers):
res = {}
for k in headers:
size = len(k)
if size not in res:
res[size] = {}
ent = res[size]
c = k[-1]
if c not in ent:
ent[c] = []
ent[c].append(k)
return res
def gen_enum():
print '''\
enum {'''
for k in sorted(HEADERS):
print '''\
{},'''.format(to_enum_hd(k))
print '''\
HD_MAXIDX,
};'''
def gen_index_header():
print '''\
int lookup_token(const uint8_t *name, size_t namelen) {
switch (namelen) {'''
b = build_header(HEADERS)
for size in sorted(b.keys()):
ents = b[size]
print '''\
case {}:'''.format(size)
print '''\
switch (name[namelen - 1]) {'''
for c in sorted(ents.keys()):
headers = sorted(ents[c])
print '''\
case '{}':'''.format(c)
for k in headers:
print '''\
if (util::streq("{}", name, {})) {{
return {};
}}'''.format(k[:-1], size - 1, to_enum_hd(k))
print '''\
break;'''
print '''\
}
break;'''
print '''\
}
return -1;
}'''
if __name__ == '__main__':
gen_enum()
print ''
gen_index_header()

0
gennmchartbl.py Normal file → Executable file
View File

0
genvchartbl.py Normal file → Executable file
View File

484
git-clang-format Executable file
View File

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

178
help2rst.py Executable file
View File

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

View File

@@ -0,0 +1,43 @@
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2015 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
EXTRA_DIST = \
nghttpx_http1_test.go \
nghttpx_http2_test.go \
nghttpx_spdy_test.go \
server_tester.go \
server.key \
server.crt \
alt-server.key \
alt-server.crt \
setenv
.PHONY: itprep it
itprep:
go get -d -v github.com/bradfitz/http2
go get -d -v github.com/tatsuhiro-t/go-nghttp2
go get -d -v golang.org/x/net/spdy
it:
sh setenv go test -v

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,211 @@
package nghttp2
import (
"bufio"
"fmt"
"github.com/bradfitz/http2/hpack"
"io"
"net/http"
"syscall"
"testing"
)
// TestH1H1PlainGET tests whether simple HTTP/1 GET request works.
func TestH1H1PlainGET(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1PlainGET",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
want := 200
if got := res.status; got != want {
t.Errorf("status = %v; want %v", got, want)
}
}
// TestH1H1PlainGETClose tests whether simple HTTP/1 GET request with
// Connetion: close request header field works.
func TestH1H1PlainGETClose(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1PlainGETClose",
header: []hpack.HeaderField{
pair("Connection", "close"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
want := 200
if got := res.status; got != want {
t.Errorf("status = %v; want %v", got, want)
}
}
// TestH1H1MultipleRequestCL tests that server rejects request which
// contains multiple Content-Length header fields.
func TestH1H1MultipleRequestCL(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
if _, err := io.WriteString(st.conn, fmt.Sprintf(`GET / HTTP/1.1
Host: %v
Test-Case: TestH1H1MultipleRequestCL
Content-Length: 0
Content-Length: 0
`, st.authority)); err != nil {
t.Fatalf("Error io.WriteString() = %v", err)
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err)
}
want := 400
if got := resp.StatusCode; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/1 backend failed.
func TestH1H1ConnectFailure(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
// shutdown backend server to simulate backend connect failure
st.ts.Close()
res, err := st.http1(requestParam{
name: "TestH1H1ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H1GracefulShutdown tests graceful shutdown.
func TestH1H1GracefulShutdown(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1GracefulShutdown-1",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
st.cmd.Process.Signal(syscall.SIGQUIT)
res, err = st.http1(requestParam{
name: "TestH1H1GracefulShutdown-2",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
if got, want := res.connClose, true; got != want {
t.Errorf("res.connClose: %v; want %v", got, want)
}
want := io.EOF
if _, err := st.conn.Read(nil); err == nil || err != want {
t.Errorf("st.conn.Read(): %v; want %v", err, want)
}
}
// TestH1H2ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/2 backend failed.
func TestH1H2ConnectFailure(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, noopHandler)
defer st.Close()
// simulate backend connect attempt failure
st.ts.Close()
res, err := st.http1(requestParam{
name: "TestH1H2ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H2NoHost tests that server rejects request without Host
// header field for HTTP/2 backend.
func TestH1H2NoHost(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
// without Host header field, we expect 400 response
if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H2NoHost\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err)
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err)
}
want := 400
if got := resp.StatusCode; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH1H2CrumbleCookie tests that Cookies are crumbled and assembled
// when forwarding to HTTP/2 backend link. go-nghttp2 server
// concatenates crumbled Cookies automatically, so this test is not
// much effective now.
func TestH1H2CrumbleCookie(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
t.Errorf("Cookie: %v; want %v", got, want)
}
})
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H2CrumbleCookie",
header: []hpack.HeaderField{
pair("Cookie", "alpha; bravo; charlie"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}

View File

@@ -0,0 +1,515 @@
package nghttp2
import (
"crypto/tls"
"fmt"
"github.com/bradfitz/http2"
"github.com/bradfitz/http2/hpack"
"io"
"io/ioutil"
"net/http"
"syscall"
"testing"
)
// TestH1H2PlainGET tests whether simple HTTP/2 GET request works.
func TestH2H1PlainGET(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1PlainGET",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 200
if res.status != want {
t.Errorf("status = %v; want %v", res.status, want)
}
}
// TestH2H1AddXff tests that server generates X-Forwarded-For header
// field when forwarding request to backend.
func TestH2H1AddXff(t *testing.T) {
st := newServerTester([]string{"--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For")
want := "127.0.0.1"
if xff != want {
t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1AddXff",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1AddXff2 tests that server appends X-Forwarded-For header
// field to existing one when forwarding request to backend.
func TestH2H1AddXff2(t *testing.T) {
st := newServerTester([]string{"--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For")
want := "host, 127.0.0.1"
if xff != want {
t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1AddXff2",
header: []hpack.HeaderField{
pair("x-forwarded-for", "host"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1StripXff tests that --strip-incoming-x-forwarded-for
// option.
func TestH2H1StripXff(t *testing.T) {
st := newServerTester([]string{"--strip-incoming-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
if xff, found := r.Header["X-Forwarded-For"]; found {
t.Errorf("X-Forwarded-For = %v; want nothing", xff)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1StripXff1",
header: []hpack.HeaderField{
pair("x-forwarded-for", "host"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1StripAddXff tests that --strip-incoming-x-forwarded-for and
// --add-x-forwarded-for options.
func TestH2H1StripAddXff(t *testing.T) {
args := []string{
"--strip-incoming-x-forwarded-for",
"--add-x-forwarded-for",
}
st := newServerTester(args, t, func(w http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For")
want := "127.0.0.1"
if xff != want {
t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1StripAddXff",
header: []hpack.HeaderField{
pair("x-forwarded-for", "host"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1BadRequestCL tests that server rejects request whose
// content-length header field value does not match its request body
// size.
func TestH2H1BadRequestCL(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
// we set content-length: 1024, but the actual request body is
// 3 bytes.
res, err := st.http2(requestParam{
name: "TestH2H1BadRequestCL",
method: "POST",
header: []hpack.HeaderField{
pair("content-length", "1024"),
},
body: []byte("foo"),
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := http2.ErrCodeProtocol
if res.errCode != want {
t.Errorf("res.errCode = %v; want %v", res.errCode, want)
}
}
// TestH2H1BadResponseCL tests that server returns error when
// content-length response header field value does not match its
// response body size.
func TestH2H1BadResponseCL(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
// we set content-length: 1024, but only send 3 bytes.
w.Header().Add("Content-Length", "1024")
w.Write([]byte("foo"))
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1BadResponseCL",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := http2.ErrCodeProtocol
if res.errCode != want {
t.Errorf("res.errCode = %v; want %v", res.errCode, want)
}
}
// TestH2H1LocationRewrite tests location header field rewriting
// works.
func TestH2H1LocationRewrite(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
// TODO we cannot get st.ts's port number here.. 8443
// is just a place holder. We ignore it on rewrite.
w.Header().Add("Location", "http://127.0.0.1:8443/p/q?a=b#fragment")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1LocationRewrite",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := fmt.Sprintf("http://127.0.0.1:%v/p/q?a=b#fragment", serverPort)
if got := res.header.Get("Location"); got != want {
t.Errorf("Location: %v; want %v", got, want)
}
}
// TestH2H1ChunkedRequestBody tests that chunked request body works.
func TestH2H1ChunkedRequestBody(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
want := "[chunked]"
if got := fmt.Sprint(r.TransferEncoding); got != want {
t.Errorf("Transfer-Encoding: %v; want %v", got, want)
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Fatalf("Error reading r.body: %v", err)
}
want = "foo"
if got := string(body); got != want {
t.Errorf("body: %v; want %v", got, want)
}
})
defer st.Close()
_, err := st.http2(requestParam{
name: "TestH2H1ChunkedRequestBody",
method: "POST",
body: []byte("foo"),
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
}
// TestH2H1MultipleRequestCL tests that server rejects request with
// multiple Content-Length request header fields.
func TestH2H1MultipleRequestCL(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1MultipleRequestCL",
header: []hpack.HeaderField{
pair("content-length", "1"),
pair("content-length", "1"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 400
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1InvalidRequestCL tests that server rejects request with
// Content-Length which cannot be parsed as a number.
func TestH2H1InvalidRequestCL(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1InvalidRequestCL",
header: []hpack.HeaderField{
pair("content-length", ""),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 400
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/1 backend failed.
func TestH2H1ConnectFailure(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
// shutdown backend server to simulate backend connect failure
st.ts.Close()
res, err := st.http2(requestParam{
name: "TestH2H1ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1AssembleCookies tests that crumbled cookies in HTTP/2
// request is assembled into 1 when forwarding to HTTP/1 backend link.
func TestH2H1AssembleCookies(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
t.Errorf("Cookie: %v; want %v", got, want)
}
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1AssembleCookies",
header: []hpack.HeaderField{
pair("cookie", "alpha"),
pair("cookie", "bravo"),
pair("cookie", "charlie"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1TETrailers tests that server accepts TE request header
// field if it has trailers only.
func TestH2H1TETrailers(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1TETrailers",
header: []hpack.HeaderField{
pair("te", "trailers"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H1TEGzip tests that server resets stream if TE request header
// field contains gzip.
func TestH2H1TEGzip(t *testing.T) {
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
t.Error("server should not forward bad request")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1TEGzip",
header: []hpack.HeaderField{
pair("te", "gzip"),
},
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
t.Errorf("res.errCode = %v; want %v", res.errCode, want)
}
}
func TestH2H1SNI(t *testing.T) {
st := newServerTesterTLSConfig([]string{"--subcert=" + testDir + "/alt-server.key:" + testDir + "/alt-server.crt"}, t, noopHandler, &tls.Config{
ServerName: "alt-domain",
})
defer st.Close()
tlsConn := st.conn.(*tls.Conn)
connState := tlsConn.ConnectionState()
cert := connState.PeerCertificates[0]
if got, want := cert.Subject.CommonName, "alt-domain"; got != want {
t.Errorf("CommonName: %v; want %v", got, want)
}
}
// TestH2H1GracefulShutdown tests graceful shutdown.
func TestH2H1GracefulShutdown(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
fmt.Fprint(st.conn, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
if err := st.fr.WriteSettings(); err != nil {
t.Fatalf("st.fr.WriteSettings(): %v", err)
}
header := []hpack.HeaderField{
pair(":method", "GET"),
pair(":scheme", "http"),
pair(":authority", st.authority),
pair(":path", "/"),
}
for _, h := range header {
_ = st.enc.WriteField(h)
}
if err := st.fr.WriteHeaders(http2.HeadersFrameParam{
StreamID: 1,
EndStream: false,
EndHeaders: true,
BlockFragment: st.headerBlkBuf.Bytes(),
}); err != nil {
t.Fatalf("st.fr.WriteHeaders(): %v", err)
}
// send SIGQUIT signal to nghttpx to perform graceful shutdown
st.cmd.Process.Signal(syscall.SIGQUIT)
// after signal, finish request body
if err := st.fr.WriteData(1, true, nil); err != nil {
t.Fatalf("st.fr.WriteData(): %v", err)
}
numGoAway := 0
for {
fr, err := st.readFrame()
if err != nil {
if err == io.EOF {
want := 2
if got := numGoAway; got != want {
t.Fatalf("numGoAway: %v; want %v", got, want)
}
return
}
t.Fatalf("st.readFrame(): %v", err)
}
switch f := fr.(type) {
case *http2.GoAwayFrame:
numGoAway += 1
want := http2.ErrCodeNo
if got := f.ErrCode; got != want {
t.Fatalf("f.ErrCode(%v): %v; want %v", numGoAway, got, want)
}
switch numGoAway {
case 1:
want := (uint32(1) << 31) - 1
if got := f.LastStreamID; got != want {
t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want)
}
case 2:
want := uint32(1)
if got := f.LastStreamID; got != want {
t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want)
}
case 3:
t.Fatalf("too many GOAWAYs received")
}
}
}
}
// TestH2H2MultipleResponseCL tests that server returns error if
// multiple Content-Length response header fields are received.
func TestH2H2MultipleResponseCL(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("content-length", "1")
w.Header().Add("content-length", "1")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H2MultipleResponseCL",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 502
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H2InvalidResponseCL tests that server returns error if
// Content-Length response header field value cannot be parsed as a
// number.
func TestH2H2InvalidResponseCL(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("content-length", "")
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H2InvalidResponseCL",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 502
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestH2H2ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/2 backend failed.
func TestH2H2ConnectFailure(t *testing.T) {
st := newServerTester([]string{"--http2-bridge"}, t, noopHandler)
defer st.Close()
// simulate backend connect attempt failure
st.ts.Close()
res, err := st.http2(requestParam{
name: "TestH2H2ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}

View File

@@ -0,0 +1,121 @@
package nghttp2
import (
"github.com/bradfitz/http2/hpack"
"golang.org/x/net/spdy"
"net/http"
"testing"
)
// TestS3H1PlainGET tests whether simple SPDY GET request works.
func TestS3H1PlainGET(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, noopHandler)
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1PlainGET",
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := 200
if got := res.status; got != want {
t.Errorf("status = %v; want %v", got, want)
}
}
// TestS3H1BadRequestCL tests that server rejects request whose
// content-length header field value does not match its request body
// size.
func TestS3H1BadRequestCL(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, noopHandler)
defer st.Close()
// we set content-length: 1024, but the actual request body is
// 3 bytes.
res, err := st.spdy(requestParam{
name: "TestS3H1BadRequestCL",
method: "POST",
header: []hpack.HeaderField{
pair("content-length", "1024"),
},
body: []byte("foo"),
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := spdy.ProtocolError
if got := res.spdyRstErrCode; got != want {
t.Errorf("res.spdyRstErrCode = %v; want %v", got, want)
}
}
// TestS3H1MultipleRequestCL tests that server rejects request with
// multiple Content-Length request header fields.
func TestS3H1MultipleRequestCL(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1MultipleRequestCL",
header: []hpack.HeaderField{
pair("content-length", "1"),
pair("content-length", "1"),
},
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := 400
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestS3H1InvalidRequestCL tests that server rejects request with
// Content-Length which cannot be parsed as a number.
func TestS3H1InvalidRequestCL(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
t.Errorf("server should not forward bad request")
})
defer st.Close()
res, err := st.spdy(requestParam{
name: "TestS3H1InvalidRequestCL",
header: []hpack.HeaderField{
pair("content-length", ""),
},
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := 400
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}
// TestS3H2ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/2 backend failed.
func TestS3H2ConnectFailure(t *testing.T) {
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--http2-bridge"}, t, noopHandler)
defer st.Close()
// simulate backend connect attempt failure
st.ts.Close()
res, err := st.spdy(requestParam{
name: "TestS3H2ConnectFailure",
})
if err != nil {
t.Fatalf("Error st.spdy() = %v", err)
}
want := 503
if got := res.status; got != want {
t.Errorf("status: %v; want %v", got, want)
}
}

View File

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

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDLiEGUSP4gWsT0
401hnprfLQhH82VsbiFt4WP4CIcCQ3x9km6LqwYdbPb6nKoQaub5qJHX1UFwJzS4
yBtboVpnB7jZyqxOYVPNjeovUbJrjOU0Eb4bGph64uBvhFyTLvRqhTLKPIOzFqUU
hin/vIH4wFTcHwhxYrvKAXDJst5eeDBR4ES0r3gDIYjwdHt15Z6a+dm0v6Bk8ecp
8D4AaRJ9ha6U+Gf2iwi8yf8rIDR/AVxIe5/7+8TN73eYK6gdN/a3eSaMZVr6fuF6
cyqebqWqpjnFVKuKQ0hVEN8Ogvr992dziukGqJ+xjMS791LN2+z2d9Qi6FiUdqNz
kp1Hzv4FAgMBAAECggEACG26GYP0Ui6wHVwUZkiFLVzWDPS9bIIbDEvbMfhYbvWQ
gDrCLTKF7E4I5FP8jvV+XzRl5cRFE3nsKwLObzr9XWrqcsp73DsXl1mbKx58/ws0
qrVZZBHz4pLmrHeUxduZ75dYhRuAcLgtWe48awTJdR2x5fO7C8cE89afbxrjLpJE
tVyiw6vVB0GfWTZodxtAFMTX1KVm4bTngXfg0NF1FBNHAX3Cm6t4YCE41hKSc0IQ
Jr3C4e9uj8poze1B17k79bGB8HNMbbc8Ws0sdbxi5xnY+HUA/mYQrmGXo8sdqiYC
EYCMqPm3iJrCmmpHukGf2Vt9k1aLlJ+lxOclSwFO+QKBgQDoRmoprfdmU20LyxYH
eVeVqggqmhNohwnuhIvOAyrWGUkbDsssqx2Vv82z0WHAAkwEvQ984UzaYWCCL3m3
+JzpF2dz6aKhXIaYnXBlk3STMGUCDT5ysPvsin9z/unzkffh3vrbDBARGFYWG18x
eUyTDOVVeTZNHUJXGjRyiftCkwKBgQDgUkR6dHU4ciSt7Y0UkyAgtZ7POR41T05L
bcxbjJeqm6qlj+oP9WUk7JxeSEFUbrMiROABLPPqTwmGo4xrDRx/e7WrqN6QBKC+
Y8CfalrKRb0np60x7Mxx0kbmHp5cwv9QDKznKViOYSgKxFrOFZyMAEXQdZ3FvjXF
OQWrw86kBwKBgQDXuxa9MWO3uUJtkqkaNfw/+FVvY/0kt09lJdxHci+l/IQmyl2w
Vhm7TRK7sXvtfvSl7gblgMgFiC2/nGKbmR/7ag5e3R98aVhlhMywuvyp/GfEORLI
KVNChfwMezVFUUx+j8BEFHcTuZuzGqcWZ0fUyER0V4k0pDlKdv9BZqBkWwKBgCdP
o3qGQCilMDJex/OMGPxCd9M+4kFbZZAobMC6cbXPU+dxwgYL7i67XGfVZ8WBJNlj
kpICK7irIzM6JBh6krzwlBTCIkbA2N6kopQNUl3SPOTfKKXwJp/nxs77HKuK7K09
m2tjPoatFhRU9sjY1rdeMN3oTr7hp5CpfonsZaEvAoGAEPsZcDd4N9ap5bgaeDy9
NOfLsIyaxT5k6moRIiy83QPihvCuECP16+r6M5tiSfgt/PtCimdjhRiqXzIHNRhh
Nfsv13vUtZgt8cYXuTdI4a8feKI7Q4876ME8Qp3WM5/UNZWq6/sWCuZFqbXUhqM0
mwNEi5Zddzf8VsSL2gCraQg=
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,561 @@
package nghttp2
import (
"bufio"
"bytes"
"crypto/tls"
"errors"
"fmt"
"github.com/bradfitz/http2"
"github.com/bradfitz/http2/hpack"
"github.com/tatsuhiro-t/go-nghttp2"
"golang.org/x/net/spdy"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"net/url"
"os/exec"
"strconv"
"strings"
"testing"
"time"
)
const (
serverBin = buildDir + "/src/nghttpx"
serverPort = 3009
testDir = buildDir + "/integration-tests"
)
func pair(name, value string) hpack.HeaderField {
return hpack.HeaderField{
Name: name,
Value: value,
}
}
type serverTester struct {
args []string // command-line arguments
cmd *exec.Cmd // test frontend server process, which is test subject
url string // test frontend server URL
t *testing.T
ts *httptest.Server // backend server
conn net.Conn // connection to frontend server
h2PrefaceSent bool // HTTP/2 preface was sent in conn
nextStreamID uint32 // next stream ID
fr *http2.Framer // HTTP/2 framer
spdyFr *spdy.Framer // SPDY/3.1 framer
headerBlkBuf bytes.Buffer // buffer to store encoded header block
enc *hpack.Encoder // HTTP/2 HPACK encoder
header http.Header // received header fields
dec *hpack.Decoder // HTTP/2 HPACK decoder
authority string // server's host:port
frCh chan http2.Frame // used for incoming HTTP/2 frame
spdyFrCh chan spdy.Frame // used for incoming SPDY frame
errCh chan error
}
// newServerTester creates test context for plain TCP frontend
// connection.
func newServerTester(args []string, t *testing.T, handler http.HandlerFunc) *serverTester {
return newServerTesterInternal(args, t, handler, false, nil)
}
// newServerTester creates test context for TLS frontend connection.
func newServerTesterTLS(args []string, t *testing.T, handler http.HandlerFunc) *serverTester {
return newServerTesterInternal(args, t, handler, true, nil)
}
// newServerTester creates test context for TLS frontend connection
// with given clientConfig
func newServerTesterTLSConfig(args []string, t *testing.T, handler http.HandlerFunc, clientConfig *tls.Config) *serverTester {
return newServerTesterInternal(args, t, handler, true, clientConfig)
}
// newServerTesterInternal creates test context. If frontendTLS is
// true, set up TLS frontend connection.
func newServerTesterInternal(args []string, t *testing.T, handler http.HandlerFunc, frontendTLS bool, clientConfig *tls.Config) *serverTester {
ts := httptest.NewUnstartedServer(handler)
backendTLS := false
for _, k := range args {
switch k {
case "--http2-bridge":
backendTLS = true
}
}
if backendTLS {
nghttp2.ConfigureServer(ts.Config, &nghttp2.Server{})
// According to httptest/server.go, we have to set
// NextProtos separately for ts.TLS. NextProtos set
// in nghttp2.ConfigureServer is effectively ignored.
ts.TLS = new(tls.Config)
ts.TLS.NextProtos = append(ts.TLS.NextProtos, "h2-14")
ts.StartTLS()
args = append(args, "-k")
} else {
ts.Start()
}
scheme := "http"
if frontendTLS {
scheme = "https"
args = append(args, testDir+"/server.key", testDir+"/server.crt")
} else {
args = append(args, "--frontend-no-tls")
}
backendURL, err := url.Parse(ts.URL)
if err != nil {
t.Fatalf("Error parsing URL from httptest.Server: %v", err)
}
// URL.Host looks like "127.0.0.1:8080", but we want
// "127.0.0.1,8080"
b := "-b" + strings.Replace(backendURL.Host, ":", ",", -1)
args = append(args, fmt.Sprintf("-f127.0.0.1,%v", serverPort), b,
"--errorlog-file="+testDir+"/log.txt", "-LINFO")
authority := fmt.Sprintf("127.0.0.1:%v", serverPort)
st := &serverTester{
cmd: exec.Command(serverBin, args...),
t: t,
ts: ts,
url: fmt.Sprintf("%v://%v", scheme, authority),
nextStreamID: 1,
authority: authority,
frCh: make(chan http2.Frame),
spdyFrCh: make(chan spdy.Frame),
errCh: make(chan error),
}
if err := st.cmd.Start(); err != nil {
st.t.Fatalf("Error starting %v: %v", serverBin, err)
}
retry := 0
for {
var conn net.Conn
var err error
if frontendTLS {
var tlsConfig *tls.Config
if clientConfig == nil {
tlsConfig = new(tls.Config)
} else {
tlsConfig = clientConfig
}
tlsConfig.InsecureSkipVerify = true
tlsConfig.NextProtos = []string{"h2-14", "spdy/3.1"}
conn, err = tls.Dial("tcp", authority, tlsConfig)
} else {
conn, err = net.Dial("tcp", authority)
}
if err != nil {
retry += 1
if retry >= 100 {
st.Close()
st.t.Fatalf("Error server is not responding too long; server command-line arguments may be invalid")
}
time.Sleep(150 * time.Millisecond)
continue
}
if frontendTLS {
tlsConn := conn.(*tls.Conn)
cs := tlsConn.ConnectionState()
if !cs.NegotiatedProtocolIsMutual {
st.Close()
st.t.Fatalf("Error negotiated next protocol is not mutual")
}
}
st.conn = conn
break
}
st.fr = http2.NewFramer(st.conn, st.conn)
spdyFr, err := spdy.NewFramer(st.conn, st.conn)
if err != nil {
st.Close()
st.t.Fatalf("Error spdy.NewFramer: %v", err)
}
st.spdyFr = spdyFr
st.enc = hpack.NewEncoder(&st.headerBlkBuf)
st.dec = hpack.NewDecoder(4096, func(f hpack.HeaderField) {
st.header.Add(f.Name, f.Value)
})
return st
}
func (st *serverTester) Close() {
if st.conn != nil {
st.conn.Close()
}
if st.cmd != nil {
st.cmd.Process.Kill()
st.cmd.Wait()
}
if st.ts != nil {
st.ts.Close()
}
}
func (st *serverTester) readFrame() (http2.Frame, error) {
go func() {
f, err := st.fr.ReadFrame()
if err != nil {
st.errCh <- err
return
}
st.frCh <- f
}()
select {
case f := <-st.frCh:
return f, nil
case err := <-st.errCh:
return nil, err
case <-time.After(5 * time.Second):
return nil, errors.New("timeout waiting for frame")
}
}
func (st *serverTester) readSpdyFrame() (spdy.Frame, error) {
go func() {
f, err := st.spdyFr.ReadFrame()
if err != nil {
st.errCh <- err
return
}
st.spdyFrCh <- f
}()
select {
case f := <-st.spdyFrCh:
return f, nil
case err := <-st.errCh:
return nil, err
case <-time.After(2 * time.Second):
return nil, errors.New("timeout waiting for frame")
}
}
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
}
func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
method := "GET"
if rp.method != "" {
method = rp.method
}
var body io.Reader
if rp.body != nil {
body = bytes.NewBuffer(rp.body)
}
req, err := http.NewRequest(method, st.url, body)
if err != nil {
return nil, err
}
for _, h := range rp.header {
req.Header.Add(h.Name, h.Value)
}
req.Header.Add("Test-Case", rp.name)
if err := req.Write(st.conn); err != nil {
return nil, err
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), req)
if err != nil {
return nil, err
}
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
resp.Body.Close()
res := &serverResponse{
status: resp.StatusCode,
header: resp.Header,
body: respBody,
connClose: resp.Close,
}
return res, nil
}
func (st *serverTester) spdy(rp requestParam) (*serverResponse, error) {
res := &serverResponse{}
var id spdy.StreamId
if rp.streamID != 0 {
id = spdy.StreamId(rp.streamID)
if id >= spdy.StreamId(st.nextStreamID) && id%2 == 1 {
st.nextStreamID = uint32(id) + 2
}
} else {
id = spdy.StreamId(st.nextStreamID)
st.nextStreamID += 2
}
method := "GET"
if rp.method != "" {
method = rp.method
}
scheme := "http"
if rp.scheme != "" {
scheme = rp.scheme
}
host := st.authority
if rp.authority != "" {
host = rp.authority
}
path := "/"
if rp.path != "" {
path = rp.path
}
header := make(http.Header)
header.Add(":method", method)
header.Add(":scheme", scheme)
header.Add(":host", host)
header.Add(":path", path)
header.Add(":version", "HTTP/1.1")
header.Add("test-case", rp.name)
for _, h := range rp.header {
header.Add(h.Name, h.Value)
}
var synStreamFlags spdy.ControlFlags
if len(rp.body) == 0 {
synStreamFlags = spdy.ControlFlagFin
}
if err := st.spdyFr.WriteFrame(&spdy.SynStreamFrame{
CFHeader: spdy.ControlFrameHeader{
Flags: synStreamFlags,
},
StreamId: id,
Headers: header,
}); err != nil {
return nil, err
}
if len(rp.body) != 0 {
if err := st.spdyFr.WriteFrame(&spdy.DataFrame{
StreamId: id,
Flags: spdy.DataFlagFin,
Data: rp.body,
}); err != nil {
return nil, err
}
}
loop:
for {
fr, err := st.readSpdyFrame()
if err != nil {
return res, err
}
switch f := fr.(type) {
case *spdy.SynReplyFrame:
if f.StreamId != id {
break
}
res.header = cloneHeader(f.Headers)
if _, err := fmt.Sscan(res.header.Get(":status"), &res.status); err != nil {
return res, fmt.Errorf("Error parsing status code: %v", err)
}
if f.CFHeader.Flags&spdy.ControlFlagFin != 0 {
break loop
}
case *spdy.DataFrame:
if f.StreamId != id {
break
}
res.body = append(res.body, f.Data...)
if f.Flags&spdy.DataFlagFin != 0 {
break loop
}
case *spdy.RstStreamFrame:
if f.StreamId != id {
break
}
res.spdyRstErrCode = f.Status
break loop
case *spdy.GoAwayFrame:
if f.Status == spdy.GoAwayOK {
break
}
res.spdyGoAwayErrCode = f.Status
break loop
}
}
return res, nil
}
func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
res := &serverResponse{}
st.headerBlkBuf.Reset()
st.header = make(http.Header)
var id uint32
if rp.streamID != 0 {
id = rp.streamID
if id >= st.nextStreamID && id%2 == 1 {
st.nextStreamID = id + 2
}
} else {
id = st.nextStreamID
st.nextStreamID += 2
}
if !st.h2PrefaceSent {
st.h2PrefaceSent = true
fmt.Fprint(st.conn, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
if err := st.fr.WriteSettings(); err != nil {
return nil, err
}
}
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,
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, true, rp.body); err != nil {
return nil, err
}
}
loop:
for {
fr, err := st.readFrame()
if err != nil {
return res, err
}
switch f := fr.(type) {
case *http2.HeadersFrame:
_, err := st.dec.Write(f.HeaderBlockFragment())
if err != nil {
return res, err
}
if f.FrameHeader.StreamID != id {
st.header = make(http.Header)
break
}
res.header = cloneHeader(st.header)
var status int
status, err = strconv.Atoi(res.header.Get(":status"))
if err != nil {
return res, fmt.Errorf("Error parsing status code: %v", err)
}
res.status = status
if f.StreamEnded() {
break loop
}
case *http2.DataFrame:
if f.FrameHeader.StreamID != id {
break
}
res.body = append(res.body, f.Data()...)
if f.StreamEnded() {
break loop
}
case *http2.RSTStreamFrame:
if f.FrameHeader.StreamID != id {
break
}
res.errCode = f.ErrCode
break loop
case *http2.GoAwayFrame:
if f.ErrCode == http2.ErrCodeNo {
break
}
res.errCode = f.ErrCode
res.connErr = true
break loop
case *http2.SettingsFrame:
if f.IsAck() {
break
}
if err := st.fr.WriteSettingsAck(); err != nil {
return res, err
}
// TODO handle PUSH_PROMISE as well, since it alters HPACK context
}
}
return res, nil
}
type serverResponse struct {
status int // HTTP status code
header http.Header // response header fields
body []byte // response body
errCode http2.ErrCode // error code received in HTTP/2 RST_STREAM or GOAWAY
connErr bool // true if HTTP/2 connection error
spdyGoAwayErrCode spdy.GoAwayStatus // status code received in SPDY RST_STREAM
spdyRstErrCode spdy.RstStreamStatus // status code received in SPDY GOAWAY
connClose bool // Conection: close is included in response header in HTTP/1 test
}
func cloneHeader(h http.Header) http.Header {
h2 := make(http.Header, len(h))
for k, vv := range h {
vv2 := make([]string, len(vv))
copy(vv2, vv)
h2[k] = vv2
}
return h2
}
func noopHandler(w http.ResponseWriter, r *http.Request) {}

View File

@@ -0,0 +1,6 @@
#!/bin/sh -e
export CGO_CFLAGS="-I@abs_top_srcdir@/lib/includes -I@abs_top_builddir@/lib/includes"
export CGO_LDFLAGS="-L@abs_top_builddir@/lib/.libs"
export LD_LIBRARY_PATH="@abs_top_builddir@/lib/.libs"
"$@"

View File

@@ -22,7 +22,9 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = includes
AM_CFLAGS = -Wall
EXTRA_DIST = Makefile.msvc
AM_CFLAGS = $(WARNCFLAGS)
AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes @DEFS@
pkgconfigdir = $(libdir)/pkgconfig
@@ -42,7 +44,8 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_version.c \
nghttp2_priority_spec.c \
nghttp2_option.c \
nghttp2_callbacks.c
nghttp2_callbacks.c \
nghttp2_mem.c
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_frame.h \
@@ -54,7 +57,8 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_hd.h nghttp2_hd_huffman.h \
nghttp2_priority_spec.h \
nghttp2_option.h \
nghttp2_callbacks.h
nghttp2_callbacks.h \
nghttp2_mem.h
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
libnghttp2_la_LDFLAGS = -no-undefined \

File diff suppressed because it is too large Load Diff

View File

@@ -28,8 +28,7 @@
#include "nghttp2_helper.h"
void nghttp2_buf_init(nghttp2_buf *buf)
{
void nghttp2_buf_init(nghttp2_buf *buf) {
buf->begin = NULL;
buf->end = NULL;
buf->pos = NULL;
@@ -37,37 +36,34 @@ void nghttp2_buf_init(nghttp2_buf *buf)
buf->mark = NULL;
}
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial)
{
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem) {
nghttp2_buf_init(buf);
return nghttp2_buf_reserve(buf, initial);
return nghttp2_buf_reserve(buf, initial, mem);
}
void nghttp2_buf_free(nghttp2_buf *buf)
{
if(buf == NULL) {
void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem) {
if (buf == NULL) {
return;
}
free(buf->begin);
nghttp2_mem_free(mem, buf->begin);
buf->begin = NULL;
}
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
{
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem) {
uint8_t *ptr;
size_t cap;
cap = nghttp2_buf_cap(buf);
if(cap >= new_cap) {
if (cap >= new_cap) {
return 0;
}
new_cap = nghttp2_max(new_cap, cap * 2);
ptr = realloc(buf->begin, new_cap);
if(ptr == NULL) {
ptr = nghttp2_mem_realloc(mem, buf->begin, new_cap);
if (ptr == NULL) {
return NGHTTP2_ERR_NOMEM;
}
@@ -80,80 +76,67 @@ int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
return 0;
}
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap)
{
return nghttp2_buf_reserve(buf, nghttp2_buf_pos_offset(buf) + new_rel_cap);
}
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap)
{
return nghttp2_buf_reserve(buf, nghttp2_buf_last_offset(buf) + new_rel_cap);
}
void nghttp2_buf_reset(nghttp2_buf *buf)
{
void nghttp2_buf_reset(nghttp2_buf *buf) {
buf->pos = buf->last = buf->mark = buf->begin;
}
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len)
{
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
buf->begin = buf->pos = buf->last = buf->mark = begin;
buf->end = begin + len;
}
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length)
{
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
nghttp2_mem *mem) {
int rv;
*chain = malloc(sizeof(nghttp2_buf_chain));
if(*chain == NULL) {
*chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
if (*chain == NULL) {
return NGHTTP2_ERR_NOMEM;
}
(*chain)->next = NULL;
rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length);
if(rv != 0) {
free(*chain);
rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length, mem);
if (rv != 0) {
nghttp2_mem_free(mem, *chain);
return NGHTTP2_ERR_NOMEM;
}
return 0;
}
static void buf_chain_del(nghttp2_buf_chain *chain)
{
nghttp2_buf_free(&chain->buf);
free(chain);
static void buf_chain_del(nghttp2_buf_chain *chain, nghttp2_mem *mem) {
nghttp2_buf_free(&chain->buf, mem);
nghttp2_mem_free(mem, chain);
}
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk)
{
return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0);
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
nghttp2_mem *mem) {
return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0, mem);
}
int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t offset)
{
return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset);
size_t max_chunk, size_t offset, nghttp2_mem *mem) {
return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset,
mem);
}
int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t chunk_keep, size_t offset)
{
size_t max_chunk, size_t chunk_keep, size_t offset,
nghttp2_mem *mem) {
int rv;
nghttp2_buf_chain *chain;
if(chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
rv = buf_chain_new(&chain, chunk_length);
if(rv != 0) {
rv = buf_chain_new(&chain, chunk_length, mem);
if (rv != 0) {
return rv;
}
bufs->mem = mem;
bufs->offset = offset;
bufs->head = chain;
@@ -169,17 +152,16 @@ int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
return 0;
}
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length)
{
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length) {
int rv;
nghttp2_buf_chain *chain;
if(chunk_length < bufs->offset) {
if (chunk_length < bufs->offset) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
rv = buf_chain_new(&chain, chunk_length);
if(rv != 0) {
rv = buf_chain_new(&chain, chunk_length, bufs->mem);
if (rv != 0) {
return rv;
}
@@ -196,18 +178,17 @@ int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length)
return 0;
}
void nghttp2_bufs_free(nghttp2_bufs *bufs)
{
void nghttp2_bufs_free(nghttp2_bufs *bufs) {
nghttp2_buf_chain *chain, *next_chain;
if(bufs == NULL) {
if (bufs == NULL) {
return;
}
for(chain = bufs->head; chain;) {
for (chain = bufs->head; chain;) {
next_chain = chain->next;
buf_chain_del(chain);
buf_chain_del(chain, bufs->mem);
chain = next_chain;
}
@@ -215,12 +196,12 @@ void nghttp2_bufs_free(nghttp2_bufs *bufs)
bufs->head = NULL;
}
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len)
{
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
nghttp2_mem *mem) {
nghttp2_buf_chain *chain;
chain = malloc(sizeof(nghttp2_buf_chain));
if(chain == NULL) {
chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
if (chain == NULL) {
return NGHTTP2_ERR_NOMEM;
}
@@ -228,6 +209,7 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len)
nghttp2_buf_wrap_init(&chain->buf, begin, len);
bufs->mem = mem;
bufs->offset = 0;
bufs->head = chain;
@@ -241,22 +223,20 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len)
return 0;
}
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs)
{
if(bufs == NULL) {
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) {
if (bufs == NULL) {
return;
}
free(bufs->head);
nghttp2_mem_free(bufs->mem, bufs->head);
bufs->head = NULL;
}
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs)
{
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) {
nghttp2_buf_chain *ci;
for(ci = bufs->cur; ci; ci = ci->next) {
if(nghttp2_buf_len(&ci->buf) == 0) {
for (ci = bufs->cur; ci; ci = ci->next) {
if (nghttp2_buf_len(&ci->buf) == 0) {
return;
} else {
bufs->cur = ci;
@@ -264,42 +244,40 @@ void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs)
}
}
ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs)
{
ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs) {
nghttp2_buf_chain *ci;
ssize_t len;
len = 0;
for(ci = bufs->head; ci; ci = ci->next) {
for (ci = bufs->head; ci; ci = ci->next) {
len += nghttp2_buf_len(&ci->buf);
}
return len;
}
static ssize_t bufs_avail(nghttp2_bufs *bufs)
{
static ssize_t bufs_avail(nghttp2_bufs *bufs) {
return (ssize_t)(nghttp2_buf_avail(&bufs->cur->buf) +
(bufs->chunk_length - bufs->offset) * (bufs->max_chunk - bufs->chunk_used));
(bufs->chunk_length - bufs->offset) *
(bufs->max_chunk - bufs->chunk_used));
}
static int bufs_alloc_chain(nghttp2_bufs *bufs)
{
static int bufs_alloc_chain(nghttp2_bufs *bufs) {
int rv;
nghttp2_buf_chain *chain;
if(bufs->cur->next) {
if (bufs->cur->next) {
bufs->cur = bufs->cur->next;
return 0;
}
if(bufs->max_chunk == bufs->chunk_used) {
if (bufs->max_chunk == bufs->chunk_used) {
return NGHTTP2_ERR_BUFFER_ERROR;
}
rv = buf_chain_new(&chain, bufs->chunk_length);
if(rv != 0) {
rv = buf_chain_new(&chain, bufs->chunk_length, bufs->mem);
if (rv != 0) {
return rv;
}
@@ -317,26 +295,25 @@ static int bufs_alloc_chain(nghttp2_bufs *bufs)
return 0;
}
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len)
{
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) {
int rv;
size_t nwrite;
nghttp2_buf *buf;
const uint8_t *p;
if(bufs_avail(bufs) < (ssize_t)len) {
if (bufs_avail(bufs) < (ssize_t)len) {
return NGHTTP2_ERR_BUFFER_ERROR;
}
p = data;
while(len) {
while (len) {
buf = &bufs->cur->buf;
nwrite = nghttp2_min((size_t)nghttp2_buf_avail(buf), len);
if(nwrite == 0) {
if (nwrite == 0) {
rv = bufs_alloc_chain(bufs);
if(rv != 0) {
if (rv != 0) {
return rv;
}
continue;
@@ -350,31 +327,29 @@ int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len)
return 0;
}
static int bufs_ensure_addb(nghttp2_bufs *bufs)
{
static int bufs_ensure_addb(nghttp2_bufs *bufs) {
int rv;
nghttp2_buf *buf;
buf = &bufs->cur->buf;
if(nghttp2_buf_avail(buf) > 0) {
if (nghttp2_buf_avail(buf) > 0) {
return 0;
}
rv = bufs_alloc_chain(bufs);
if(rv != 0) {
if (rv != 0) {
return rv;
}
return 0;
}
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b)
{
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b) {
int rv;
rv = bufs_ensure_addb(bufs);
if(rv != 0) {
if (rv != 0) {
return rv;
}
@@ -383,12 +358,11 @@ int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b)
return 0;
}
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b)
{
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b) {
int rv;
rv = bufs_ensure_addb(bufs);
if(rv != 0) {
if (rv != 0) {
return rv;
}
@@ -397,12 +371,11 @@ int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b)
return 0;
}
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b)
{
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b) {
int rv;
rv = bufs_ensure_addb(bufs);
if(rv != 0) {
if (rv != 0) {
return rv;
}
@@ -411,12 +384,11 @@ int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b)
return 0;
}
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b)
{
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b) {
int rv;
rv = bufs_ensure_addb(bufs);
if(rv != 0) {
if (rv != 0) {
return rv;
}
@@ -425,8 +397,7 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b)
return 0;
}
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out)
{
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
size_t len;
nghttp2_buf_chain *chain;
nghttp2_buf *buf;
@@ -435,28 +406,27 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out)
len = 0;
for(chain = bufs->head; chain; chain = chain->next) {
for (chain = bufs->head; chain; chain = chain->next) {
len += nghttp2_buf_len(&chain->buf);
}
if(!len) {
if (!len) {
res = NULL;
} else {
res = malloc(len);
res = nghttp2_mem_malloc(bufs->mem, len);
if(res == NULL) {
if (res == NULL) {
return NGHTTP2_ERR_NOMEM;
}
}
nghttp2_buf_wrap_init(&resbuf, res, len);
for(chain = bufs->head; chain; chain = chain->next) {
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));
if (resbuf.last) {
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
}
nghttp2_buf_reset(buf);
@@ -470,30 +440,29 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out)
return (ssize_t)len;
}
void nghttp2_bufs_reset(nghttp2_bufs *bufs)
{
void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
nghttp2_buf_chain *chain, *ci;
size_t k;
k = bufs->chunk_keep;
for(ci = bufs->head; ci; ci = ci->next) {
for (ci = bufs->head; ci; ci = ci->next) {
nghttp2_buf_reset(&ci->buf);
nghttp2_buf_shift_right(&ci->buf, bufs->offset);
if(--k == 0) {
if (--k == 0) {
break;
}
}
if(ci) {
if (ci) {
chain = ci->next;
ci->next = NULL;
for(ci = chain; ci;) {
for (ci = chain; ci;) {
chain = ci->next;
buf_chain_del(ci);
buf_chain_del(ci, bufs->mem);
ci = chain;
}
@@ -504,17 +473,12 @@ void nghttp2_bufs_reset(nghttp2_bufs *bufs)
bufs->cur = bufs->head;
}
int nghttp2_bufs_advance(nghttp2_bufs *bufs)
{
return bufs_alloc_chain(bufs);
}
int nghttp2_bufs_advance(nghttp2_bufs *bufs) { return bufs_alloc_chain(bufs); }
int nghttp2_bufs_next_present(nghttp2_bufs *bufs)
{
int nghttp2_bufs_next_present(nghttp2_bufs *bufs) {
nghttp2_buf_chain *chain;
chain = bufs->cur->next;
return chain && nghttp2_buf_len(&chain->buf);
}

View File

@@ -26,12 +26,13 @@
#define NGHTTP2_BUF_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_int.h"
#include "nghttp2_mem.h"
typedef struct {
/* This points to the beginning of the buffer. The effective range
@@ -62,13 +63,13 @@ typedef struct {
do { \
(BUF)->pos += AMT; \
(BUF)->last += AMT; \
} while(0)
} while (0)
#define nghttp2_buf_shift_left(BUF, AMT) \
do { \
(BUF)->pos -= AMT; \
(BUF)->last -= AMT; \
} while(0)
} while (0)
/*
* Initializes the |buf|. No memory is allocated in this function. Use
@@ -76,7 +77,6 @@ typedef struct {
*/
void nghttp2_buf_init(nghttp2_buf *buf);
/*
* Initializes the |buf| and allocates at least |initial| bytes of
* memory.
@@ -87,12 +87,12 @@ void nghttp2_buf_init(nghttp2_buf *buf);
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial);
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem);
/*
* Frees buffer in |buf|.
*/
void nghttp2_buf_free(nghttp2_buf *buf);
void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);
/*
* Extends buffer so that nghttp2_buf_cap() returns at least
@@ -105,23 +105,7 @@ void nghttp2_buf_free(nghttp2_buf *buf);
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap);
/*
* This function behaves like nghttp2_buf_reserve(), but new capacity
* is calculated as nghttp2_buf_pos_offset(buf) + new_rel_cap. In
* other words, this function reserves memory at least |new_rel_cap|
* bytes from buf->pos.
*/
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap);
/*
* This function behaves like nghttp2_buf_reserve(), but new capacity
* is calculated as nghttp2_buf_last_offset(buf) + new_rel_cap. In
* other words, this function reserves memory at least |new_rel_cap|
* bytes from buf->last.
*/
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap);
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem);
/*
* Resets pos, last, mark member of |buf| to buf->begin.
@@ -152,6 +136,8 @@ typedef struct {
nghttp2_buf_chain *head;
/* Buffer pointer where write occurs. */
nghttp2_buf_chain *cur;
/* Memory allocator */
nghttp2_mem *mem;
/* The buffer capacity of each buf */
size_t chunk_length;
/* The maximum number of nghttp2_buf_chain */
@@ -170,15 +156,15 @@ typedef struct {
* This is the same as calling nghttp2_bufs_init2 with the given
* arguments and offset = 0.
*/
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk);
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
nghttp2_mem *mem);
/*
* This is the same as calling nghttp2_bufs_init3 with the given
* arguments and chunk_keep = max_chunk.
*/
int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t offset);
size_t max_chunk, size_t offset, nghttp2_mem *mem);
/*
* Initializes |bufs|. Each buffer size is given in the
@@ -200,7 +186,8 @@ int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
* long.
*/
int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t chunk_keep, size_t offset);
size_t max_chunk, size_t chunk_keep, size_t offset,
nghttp2_mem *mem);
/*
* Frees any related resources to the |bufs|.
@@ -220,7 +207,8 @@ void nghttp2_bufs_free(nghttp2_bufs *bufs);
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len);
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
nghttp2_mem *mem);
/*
* Frees any related resource to the |bufs|. This function does not
@@ -283,12 +271,12 @@ int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b);
#define nghttp2_bufs_fast_addb(BUFS, B) \
do { \
*(BUFS)->cur->buf.last++ = B; \
} while(0)
} while (0)
#define nghttp2_bufs_fast_addb_hold(BUFS, B) \
do { \
*(BUFS)->cur->buf.last = B; \
} while(0)
} while (0)
/*
* Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers
@@ -313,12 +301,12 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
#define nghttp2_bufs_fast_orb(BUFS, B) \
do { \
*(BUFS)->cur->buf.last++ |= B; \
} while(0)
} while (0)
#define nghttp2_bufs_fast_orb_hold(BUFS, B) \
do { \
*(BUFS)->cur->buf.last |= B; \
} while(0)
} while (0)
/*
* Copies all data stored in |bufs| to the contagious buffer. This
@@ -361,7 +349,7 @@ int nghttp2_bufs_advance(nghttp2_bufs *bufs);
#define nghttp2_bufs_rewind(BUFS) \
do { \
(BUFS)->cur = (BUFS)->head; \
} while(0)
} while (0)
/*
* Move bufs->cur, from the current position, using next member, to

View File

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

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_CALLBACKS_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_FRAME_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
@@ -57,7 +57,8 @@
/* The default length of DATA frame payload. This should be small enough
* for the data payload and the header to fit into 1 TLS record */
#define NGHTTP2_DATA_PAYLOADLEN ((NGHTTP2_MAX_FRAME_SIZE_MIN) - (NGHTTP2_FRAME_HDLEN))
#define NGHTTP2_DATA_PAYLOADLEN \
((NGHTTP2_MAX_FRAME_SIZE_MIN) - (NGHTTP2_FRAME_HDLEN))
/* Maximum headers payload length, calculated in compressed form.
This applies to transmission only. */
@@ -72,68 +73,22 @@
/* Length of priority related fields in HEADERS/PRIORITY frames */
#define NGHTTP2_PRIORITY_SPECLEN 5
/* Length of fixed part in ALTSVC frame, that is the sum of fields of
Max-Age, Port and Proto-Len. */
#define NGHTTP2_ALTSVC_FIXED_PARTLEN 7
/* Minimum length of ALTSVC extension frame payload.
NGHTTP2_ALTSVC_FIXED_PARTLEN + Host-Len. */
#define NGHTTP2_ALTSVC_MINLEN 8
/* Maximum length of padding in bytes. */
#define NGHTTP2_MAX_PADLEN 256
/* Category of frames. */
typedef enum {
/* non-DATA frame */
NGHTTP2_CAT_CTRL,
/* DATA frame */
NGHTTP2_CAT_DATA
} nghttp2_frame_category;
/* Union of extension frame payload */
typedef union {
nghttp2_ext_altsvc altsvc;
} nghttp2_ext_frame_payload;
/**
* @struct
*
* The DATA frame used in the library privately. It has the following
* members:
*/
typedef struct {
nghttp2_frame_hd hd;
/**
* The data to be sent for this DATA frame.
*/
nghttp2_data_provider data_prd;
/**
* The number of bytes added as padding. This includes Pad Length
* field (1 byte).
*/
size_t padlen;
/**
* The flag to indicate whether EOF was reached or not. Initially
* |eof| is 0. It becomes 1 after all data were read. This is used
* exclusively by nghttp2 library and not in the spec.
*/
uint8_t eof;
} nghttp2_private_data;
int nghttp2_frame_is_data_frame(uint8_t *head);
typedef union { nghttp2_ext_altsvc altsvc; } nghttp2_ext_frame_payload;
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf);
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf);
/**
* Initializes frame header |hd| with given parameters. Reserved bit
* is set to 0.
*/
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length,
uint8_t type, uint8_t flags,
int32_t stream_id);
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
uint8_t flags, int32_t stream_id);
/**
* Returns the number of priority field depending on the |flags|. If
@@ -156,8 +111,7 @@ void nghttp2_frame_pack_priority_spec(uint8_t *buf,
* assumes the |payload| contains whole priority specification.
*/
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
uint8_t flags,
const uint8_t *payload,
uint8_t flags, const uint8_t *payload,
size_t payloadlen);
/*
@@ -186,8 +140,7 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
nghttp2_headers *frame,
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
nghttp2_hd_deflater *deflater);
/*
@@ -210,8 +163,7 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
*
* This function always succeeds and returns 0.
*/
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs,
nghttp2_priority *frame);
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
/*
* Unpacks PRIORITY wire format into |frame|.
@@ -279,7 +231,7 @@ void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
*/
int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
nghttp2_settings_entry *iv,
size_t niv);
size_t niv, nghttp2_mem *mem);
/*
* Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
@@ -296,7 +248,7 @@ int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
size_t *niv_ptr,
const uint8_t *payload,
size_t payloadlen);
size_t payloadlen, nghttp2_mem *mem);
/*
* Packs PUSH_PROMISE frame |frame| in wire format and store it in
@@ -399,7 +351,7 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
*/
int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
const uint8_t *payload,
size_t payloadlen);
size_t payloadlen, nghttp2_mem *mem);
/*
* Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
@@ -420,71 +372,24 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
const uint8_t *payload,
size_t payloadlen);
/*
* Packs ALTSVC frame |frame| in wire format and store it in |bufs|.
* This function expands |bufs| as necessary to store frame.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* The caller must make sure that frame->payload points to
* nghttp2_ext_altsvc object.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The length of the frame is too large.
*/
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame);
/*
* Unpacks ALTSVC frame byte sequence into |frame|.
* The |payload| of length |payloadlen| contains first 8 bytes of
* payload. The |var_gift_payload| of length |var_gift_payloadlen|
* contains remaining payload and its buffer is gifted to the function
* and then |frame|. The |var_gift_payloadlen| must be freed by
* nghttp2_frame_altsvc_free().
*
* The caller must make sure that frame->payload points to
* nghttp2_ext_altsvc object.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
*
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The |var_gift_payload| does not contain required data.
*/
int nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
const uint8_t *payload,
size_t payloadlen,
uint8_t *var_gift_payload,
size_t var_gift_payloadlen);
/*
* Initializes HEADERS frame |frame| with given values. |frame| takes
* ownership of |nva|, so caller must not free it. If |stream_id| is
* not assigned yet, it must be -1.
*/
void nghttp2_frame_headers_init(nghttp2_headers *frame,
uint8_t flags, int32_t stream_id,
nghttp2_headers_category cat,
void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
int32_t stream_id, nghttp2_headers_category cat,
const nghttp2_priority_spec *pri_spec,
nghttp2_nv *nva, size_t nvlen);
void nghttp2_frame_headers_free(nghttp2_headers *frame);
void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem);
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
const nghttp2_priority_spec *pri_spec);
void nghttp2_frame_priority_free(nghttp2_priority *frame);
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame,
int32_t stream_id,
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
uint32_t error_code);
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
@@ -493,12 +398,13 @@ void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
* Initializes PUSH_PROMISE frame |frame| with given values. |frame|
* takes ownership of |nva|, so caller must not free it.
*/
void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame,
uint8_t flags, int32_t stream_id,
void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
int32_t stream_id,
int32_t promised_stream_id,
nghttp2_nv *nva, size_t nvlen);
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame);
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame,
nghttp2_mem *mem);
/*
* Initializes SETTINGS frame |frame| with given values. |frame| takes
@@ -508,7 +414,7 @@ void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame);
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
nghttp2_settings_entry *iv, size_t niv);
void nghttp2_frame_settings_free(nghttp2_settings *frame);
void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem);
/*
* Initializes PING frame |frame| with given values. If the
@@ -527,40 +433,17 @@ void nghttp2_frame_ping_free(nghttp2_ping *frame);
* free it. If the |opaque_data_len| is 0, opaque_data could be NULL.
*/
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
uint32_t error_code,
uint8_t *opaque_data, size_t opaque_data_len);
uint32_t error_code, uint8_t *opaque_data,
size_t opaque_data_len);
void nghttp2_frame_goaway_free(nghttp2_goaway *frame);
void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem);
void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
uint8_t flags,
int32_t stream_id,
uint8_t flags, int32_t stream_id,
int32_t window_size_increment);
void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
/* protocol_id, host and origin must be allocated to the one chunk of
memory region and protocol_id must point to it. We only free
protocol_id. This means that |protocol_id| is not NULL even if
|protocol_id_len| == 0 and |host_len| + |origin_len| > 0. If
|protocol_id_len|, |host_len| and |origin_len| are all zero,
|protocol_id| can be NULL. */
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
uint32_t max_age,
uint16_t port,
uint8_t *protocol_id,
size_t protocol_id_len,
uint8_t *host, size_t host_len,
uint8_t *origin, size_t origin_len);
/*
* Frees resources used by |frame|. This function does not free
* frame->payload itself.
*/
void nghttp2_frame_altsvc_free(nghttp2_extension *frame);
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
/*
* Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does
@@ -568,20 +451,18 @@ void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
*/
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
uint8_t flags,
int32_t stream_id,
const nghttp2_data_provider *data_prd);
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
int32_t stream_id);
void nghttp2_frame_private_data_free(nghttp2_private_data *frame);
void nghttp2_frame_data_free(nghttp2_data *frame);
/*
* Makes copy of |iv| and return the copy. The |niv| is the number of
* entries in |iv|. This function returns the pointer to the copy if
* it succeeds, or NULL.
*/
nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
size_t niv);
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
size_t niv, nghttp2_mem *mem);
/*
* Sorts the |nva| in ascending order of name and value. If names are
@@ -602,8 +483,8 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr,
const nghttp2_nv *nva, size_t nvlen);
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
size_t nvlen, nghttp2_mem *mem);
/*
* Returns nonzero if the name/value pair |a| equals to |b|. The name
@@ -615,7 +496,7 @@ int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b);
/*
* Frees |nva|.
*/
void nghttp2_nv_array_del(nghttp2_nv *nva);
void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem);
/*
* Checks that the |iv|, which includes |niv| entries, does not have

File diff suppressed because it is too large Load Diff

View File

@@ -26,13 +26,14 @@
#define NGHTTP2_HD_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_hd_huffman.h"
#include "nghttp2_buf.h"
#include "nghttp2_mem.h"
#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE
#define NGHTTP2_HD_ENTRY_OVERHEAD 32
@@ -73,6 +74,11 @@ typedef struct {
uint8_t flags;
} nghttp2_hd_entry;
typedef struct {
nghttp2_hd_entry ent;
size_t index;
} nghttp2_hd_static_entry;
typedef struct {
nghttp2_hd_entry **buffer;
size_t mask;
@@ -104,6 +110,8 @@ typedef enum {
typedef struct {
/* dynamic header table */
nghttp2_hd_ringbuf hd_table;
/* Memory allocator */
nghttp2_mem *mem;
/* Abstract buffer size of hd_table as described in the spec. This
is the sum of length of name/value in hd_table +
NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */
@@ -178,12 +186,12 @@ struct nghttp2_hd_inflater {
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
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);
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);
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent, nghttp2_mem *mem);
/*
* Initializes |deflater| for deflating name/values pairs.
@@ -199,7 +207,7 @@ void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater);
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem);
/*
* Initializes |deflater| for deflating name/values pairs.
@@ -215,7 +223,8 @@ int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater);
* Out of memory.
*/
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
size_t deflate_hd_table_bufsize_max);
size_t deflate_hd_table_bufsize_max,
nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |deflater|.
@@ -243,8 +252,8 @@ void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater);
* Out of buffer space.
*/
int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
nghttp2_bufs *bufs,
const nghttp2_nv *nva, size_t nvlen);
nghttp2_bufs *bufs, const nghttp2_nv *nva,
size_t nvlen);
/*
* Initializes |inflater| for inflating name/values pairs.
@@ -255,7 +264,7 @@ int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater);
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |inflater|.
@@ -274,13 +283,13 @@ int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
/* For unittesting purpose */
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
nghttp2_hd_entry *nghttp2_hd_table_get(nghttp2_hd_context *context,
size_t index);
/* For unittesting purpose */
ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *final,
uint32_t initial, size_t shift,
uint8_t *in, uint8_t *last, size_t prefix);
uint32_t initial, size_t shift, uint8_t *in,
uint8_t *last, size_t prefix);
/* Huffman encoding/decoding functions */
@@ -305,8 +314,8 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs,
const uint8_t *src, size_t srclen);
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
size_t srclen);
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
@@ -334,7 +343,7 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
* Decoding process has failed.
*/
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_bufs *bufs,
const uint8_t *src, size_t srclen, int final);
nghttp2_bufs *bufs, const uint8_t *src,
size_t srclen, int final);
#endif /* NGHTTP2_HD_H */

View File

@@ -41,78 +41,90 @@ extern const nghttp2_huff_decode huff_decode_table[][16];
* unfilled bits in the pointed location is returned.
*/
static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr,
size_t rembits,
const nghttp2_huff_sym *sym)
{
size_t rembits, const nghttp2_huff_sym *sym) {
int rv;
size_t nbits = sym->nbits;
uint32_t code = sym->code;
for(;;) {
if(rembits > nbits) {
if(*avail_ptr) {
nghttp2_bufs_fast_orb_hold(bufs, sym->code << (rembits - nbits));
} else {
rv = nghttp2_bufs_orb_hold(bufs, sym->code << (rembits - nbits));
if(rv != 0) {
return rv;
/* We assume that sym->nbits <= 32 */
if (rembits > nbits) {
nghttp2_bufs_fast_orb_hold(bufs, code << (rembits - nbits));
return (ssize_t)(rembits - nbits);
}
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
}
rembits -= nbits;
break;
}
if(*avail_ptr) {
nghttp2_bufs_fast_orb(bufs, sym->code >> (nbits - rembits));
if (rembits == nbits) {
nghttp2_bufs_fast_orb(bufs, code);
--*avail_ptr;
} else {
rv = nghttp2_bufs_orb(bufs, sym->code >> (nbits - rembits));
if(rv != 0) {
return rv;
return 8;
}
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
}
nghttp2_bufs_fast_orb(bufs, code >> (nbits - rembits));
--*avail_ptr;
nbits -= rembits;
rembits = 8;
if(nbits == 0) {
break;
if (nbits & 0x7) {
/* align code to MSB byte boundary */
code <<= 8 - (nbits & 0x7);
}
if(*avail_ptr) {
nghttp2_bufs_fast_addb_hold(bufs, 0);
} else {
rv = nghttp2_bufs_addb_hold(bufs, 0);
if(rv != 0) {
/* we lose at most 3 bytes, but it is not critical in practice */
if (*avail_ptr < (nbits + 7) / 8) {
rv = nghttp2_bufs_advance(bufs);
if (rv != 0) {
return rv;
}
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
/* we assume that we at least 3 buffer space available */
assert(*avail_ptr >= 3);
}
/* fast path, since most code is less than 8 */
if (nbits < 8) {
nghttp2_bufs_fast_addb_hold(bufs, code);
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
return (ssize_t)(8 - nbits);
}
return (ssize_t)rembits;
/* handle longer code path */
if (nbits > 24) {
nghttp2_bufs_fast_addb(bufs, code >> 24);
nbits -= 8;
}
if (nbits > 16) {
nghttp2_bufs_fast_addb(bufs, code >> 16);
nbits -= 8;
}
if (nbits > 8) {
nghttp2_bufs_fast_addb(bufs, code >> 8);
nbits -= 8;
}
if (nbits == 8) {
nghttp2_bufs_fast_addb(bufs, code);
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
return 8;
}
nghttp2_bufs_fast_addb_hold(bufs, code);
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
return (ssize_t)(8 - nbits);
}
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len)
{
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) {
size_t i;
size_t nbits = 0;
for(i = 0; i < len; ++i) {
for (i = 0; i < len; ++i) {
nbits += huff_sym_table[src[i]].nbits;
}
/* pad the prefix of EOS (256) */
return (nbits + 7) / 8;
}
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs,
const uint8_t *src, size_t srclen)
{
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
size_t srclen) {
int rv;
ssize_t rembits = 8;
size_t i;
@@ -120,52 +132,45 @@ int nghttp2_hd_huff_encode(nghttp2_bufs *bufs,
avail = nghttp2_bufs_cur_avail(bufs);
for(i = 0; i < srclen; ++i) {
for (i = 0; i < srclen; ++i) {
const nghttp2_huff_sym *sym = &huff_sym_table[src[i]];
if(rembits == 8) {
if(avail) {
if (rembits == 8) {
if (avail) {
nghttp2_bufs_fast_addb_hold(bufs, 0);
} else {
rv = nghttp2_bufs_addb_hold(bufs, 0);
if(rv != 0) {
if (rv != 0) {
return rv;
}
avail = nghttp2_bufs_cur_avail(bufs);
}
}
rembits = huff_encode_sym(bufs, &avail, rembits, sym);
if(rembits < 0) {
if (rembits < 0) {
return (int)rembits;
}
}
/* 256 is special terminal symbol, pad with its prefix */
if(rembits < 8) {
if (rembits < 8) {
/* if rembits < 8, we should have at least 1 buffer space
available */
const nghttp2_huff_sym *sym = &huff_sym_table[256];
assert(avail);
/* Caution we no longer adjust avail here */
if(avail) {
nghttp2_bufs_fast_orb(bufs, sym->code >> (sym->nbits - rembits));
} else {
rv = nghttp2_bufs_orb(bufs, sym->code >> (sym->nbits - rembits));
if(rv != 0) {
return rv;
}
}
}
return 0;
}
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx)
{
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
ctx->state = 0;
ctx->accept = 1;
}
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_bufs *bufs,
const uint8_t *src, size_t srclen, int final)
{
nghttp2_bufs *bufs, const uint8_t *src,
size_t srclen, int final) {
size_t i, j;
int rv;
size_t avail;
@@ -174,22 +179,22 @@ 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) {
for (i = 0; i < srclen; ++i) {
uint8_t in = src[i] >> 4;
for(j = 0; j < 2; ++j) {
for (j = 0; j < 2; ++j) {
const nghttp2_huff_decode *t;
t = &huff_decode_table[ctx->state][in];
if(t->flags & NGHTTP2_HUFF_FAIL) {
if (t->flags & NGHTTP2_HUFF_FAIL) {
return NGHTTP2_ERR_HEADER_COMP;
}
if(t->flags & NGHTTP2_HUFF_SYM) {
if(avail) {
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) {
if (rv != 0) {
return rv;
}
avail = nghttp2_bufs_cur_avail(bufs);
@@ -200,7 +205,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
in = src[i] & 0xf;
}
}
if(final && !ctx->accept) {
if (final && !ctx->accept) {
return NGHTTP2_ERR_HEADER_COMP;
}
return (ssize_t)i;

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_HD_HUFFMAN_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>

View File

@@ -24,265 +24,265 @@
*/
#include "nghttp2_hd_huffman.h"
const nghttp2_huff_sym huff_sym_table[] = {
{ 13, 0x1ff8u },
{ 23, 0x7fffd8u },
{ 28, 0xfffffe2u },
{ 28, 0xfffffe3u },
{ 28, 0xfffffe4u },
{ 28, 0xfffffe5u },
{ 28, 0xfffffe6u },
{ 28, 0xfffffe7u },
{ 28, 0xfffffe8u },
{ 24, 0xffffeau },
{ 30, 0x3ffffffcu },
{ 28, 0xfffffe9u },
{ 28, 0xfffffeau },
{ 30, 0x3ffffffdu },
{ 28, 0xfffffebu },
{ 28, 0xfffffecu },
{ 28, 0xfffffedu },
{ 28, 0xfffffeeu },
{ 28, 0xfffffefu },
{ 28, 0xffffff0u },
{ 28, 0xffffff1u },
{ 28, 0xffffff2u },
{ 30, 0x3ffffffeu },
{ 28, 0xffffff3u },
{ 28, 0xffffff4u },
{ 28, 0xffffff5u },
{ 28, 0xffffff6u },
{ 28, 0xffffff7u },
{ 28, 0xffffff8u },
{ 28, 0xffffff9u },
{ 28, 0xffffffau },
{ 28, 0xffffffbu },
{ 6, 0x14u },
{ 10, 0x3f8u },
{ 10, 0x3f9u },
{ 12, 0xffau },
{ 13, 0x1ff9u },
{ 6, 0x15u },
{ 8, 0xf8u },
{ 11, 0x7fau },
{ 10, 0x3fau },
{ 10, 0x3fbu },
{ 8, 0xf9u },
{ 11, 0x7fbu },
{ 8, 0xfau },
{ 6, 0x16u },
{ 6, 0x17u },
{ 6, 0x18u },
{ 5, 0x0u },
{ 5, 0x1u },
{ 5, 0x2u },
{ 6, 0x19u },
{ 6, 0x1au },
{ 6, 0x1bu },
{ 6, 0x1cu },
{ 6, 0x1du },
{ 6, 0x1eu },
{ 6, 0x1fu },
{ 7, 0x5cu },
{ 8, 0xfbu },
{ 15, 0x7ffcu },
{ 6, 0x20u },
{ 12, 0xffbu },
{ 10, 0x3fcu },
{ 13, 0x1ffau },
{ 6, 0x21u },
{ 7, 0x5du },
{ 7, 0x5eu },
{ 7, 0x5fu },
{ 7, 0x60u },
{ 7, 0x61u },
{ 7, 0x62u },
{ 7, 0x63u },
{ 7, 0x64u },
{ 7, 0x65u },
{ 7, 0x66u },
{ 7, 0x67u },
{ 7, 0x68u },
{ 7, 0x69u },
{ 7, 0x6au },
{ 7, 0x6bu },
{ 7, 0x6cu },
{ 7, 0x6du },
{ 7, 0x6eu },
{ 7, 0x6fu },
{ 7, 0x70u },
{ 7, 0x71u },
{ 7, 0x72u },
{ 8, 0xfcu },
{ 7, 0x73u },
{ 8, 0xfdu },
{ 13, 0x1ffbu },
{ 19, 0x7fff0u },
{ 13, 0x1ffcu },
{ 14, 0x3ffcu },
{ 6, 0x22u },
{ 15, 0x7ffdu },
{ 5, 0x3u },
{ 6, 0x23u },
{ 5, 0x4u },
{ 6, 0x24u },
{ 5, 0x5u },
{ 6, 0x25u },
{ 6, 0x26u },
{ 6, 0x27u },
{ 5, 0x6u },
{ 7, 0x74u },
{ 7, 0x75u },
{ 6, 0x28u },
{ 6, 0x29u },
{ 6, 0x2au },
{ 5, 0x7u },
{ 6, 0x2bu },
{ 7, 0x76u },
{ 6, 0x2cu },
{ 5, 0x8u },
{ 5, 0x9u },
{ 6, 0x2du },
{ 7, 0x77u },
{ 7, 0x78u },
{ 7, 0x79u },
{ 7, 0x7au },
{ 7, 0x7bu },
{ 15, 0x7ffeu },
{ 11, 0x7fcu },
{ 14, 0x3ffdu },
{ 13, 0x1ffdu },
{ 28, 0xffffffcu },
{ 20, 0xfffe6u },
{ 22, 0x3fffd2u },
{ 20, 0xfffe7u },
{ 20, 0xfffe8u },
{ 22, 0x3fffd3u },
{ 22, 0x3fffd4u },
{ 22, 0x3fffd5u },
{ 23, 0x7fffd9u },
{ 22, 0x3fffd6u },
{ 23, 0x7fffdau },
{ 23, 0x7fffdbu },
{ 23, 0x7fffdcu },
{ 23, 0x7fffddu },
{ 23, 0x7fffdeu },
{ 24, 0xffffebu },
{ 23, 0x7fffdfu },
{ 24, 0xffffecu },
{ 24, 0xffffedu },
{ 22, 0x3fffd7u },
{ 23, 0x7fffe0u },
{ 24, 0xffffeeu },
{ 23, 0x7fffe1u },
{ 23, 0x7fffe2u },
{ 23, 0x7fffe3u },
{ 23, 0x7fffe4u },
{ 21, 0x1fffdcu },
{ 22, 0x3fffd8u },
{ 23, 0x7fffe5u },
{ 22, 0x3fffd9u },
{ 23, 0x7fffe6u },
{ 23, 0x7fffe7u },
{ 24, 0xffffefu },
{ 22, 0x3fffdau },
{ 21, 0x1fffddu },
{ 20, 0xfffe9u },
{ 22, 0x3fffdbu },
{ 22, 0x3fffdcu },
{ 23, 0x7fffe8u },
{ 23, 0x7fffe9u },
{ 21, 0x1fffdeu },
{ 23, 0x7fffeau },
{ 22, 0x3fffddu },
{ 22, 0x3fffdeu },
{ 24, 0xfffff0u },
{ 21, 0x1fffdfu },
{ 22, 0x3fffdfu },
{ 23, 0x7fffebu },
{ 23, 0x7fffecu },
{ 21, 0x1fffe0u },
{ 21, 0x1fffe1u },
{ 22, 0x3fffe0u },
{ 21, 0x1fffe2u },
{ 23, 0x7fffedu },
{ 22, 0x3fffe1u },
{ 23, 0x7fffeeu },
{ 23, 0x7fffefu },
{ 20, 0xfffeau },
{ 22, 0x3fffe2u },
{ 22, 0x3fffe3u },
{ 22, 0x3fffe4u },
{ 23, 0x7ffff0u },
{ 22, 0x3fffe5u },
{ 22, 0x3fffe6u },
{ 23, 0x7ffff1u },
{ 26, 0x3ffffe0u },
{ 26, 0x3ffffe1u },
{ 20, 0xfffebu },
{ 19, 0x7fff1u },
{ 22, 0x3fffe7u },
{ 23, 0x7ffff2u },
{ 22, 0x3fffe8u },
{ 25, 0x1ffffecu },
{ 26, 0x3ffffe2u },
{ 26, 0x3ffffe3u },
{ 26, 0x3ffffe4u },
{ 27, 0x7ffffdeu },
{ 27, 0x7ffffdfu },
{ 26, 0x3ffffe5u },
{ 24, 0xfffff1u },
{ 25, 0x1ffffedu },
{ 19, 0x7fff2u },
{ 21, 0x1fffe3u },
{ 26, 0x3ffffe6u },
{ 27, 0x7ffffe0u },
{ 27, 0x7ffffe1u },
{ 26, 0x3ffffe7u },
{ 27, 0x7ffffe2u },
{ 24, 0xfffff2u },
{ 21, 0x1fffe4u },
{ 21, 0x1fffe5u },
{ 26, 0x3ffffe8u },
{ 26, 0x3ffffe9u },
{ 28, 0xffffffdu },
{ 27, 0x7ffffe3u },
{ 27, 0x7ffffe4u },
{ 27, 0x7ffffe5u },
{ 20, 0xfffecu },
{ 24, 0xfffff3u },
{ 20, 0xfffedu },
{ 21, 0x1fffe6u },
{ 22, 0x3fffe9u },
{ 21, 0x1fffe7u },
{ 21, 0x1fffe8u },
{ 23, 0x7ffff3u },
{ 22, 0x3fffeau },
{ 22, 0x3fffebu },
{ 25, 0x1ffffeeu },
{ 25, 0x1ffffefu },
{ 24, 0xfffff4u },
{ 24, 0xfffff5u },
{ 26, 0x3ffffeau },
{ 23, 0x7ffff4u },
{ 26, 0x3ffffebu },
{ 27, 0x7ffffe6u },
{ 26, 0x3ffffecu },
{ 26, 0x3ffffedu },
{ 27, 0x7ffffe7u },
{ 27, 0x7ffffe8u },
{ 27, 0x7ffffe9u },
{ 27, 0x7ffffeau },
{ 27, 0x7ffffebu },
{ 28, 0xffffffeu },
{ 27, 0x7ffffecu },
{ 27, 0x7ffffedu },
{ 27, 0x7ffffeeu },
{ 27, 0x7ffffefu },
{ 27, 0x7fffff0u },
{ 26, 0x3ffffeeu },
{ 30, 0x3fffffffu }
};
/* Generated by mkhufftbl.py */
const nghttp2_huff_sym huff_sym_table[] = {{13, 0x1ff8u},
{23, 0x7fffd8u},
{28, 0xfffffe2u},
{28, 0xfffffe3u},
{28, 0xfffffe4u},
{28, 0xfffffe5u},
{28, 0xfffffe6u},
{28, 0xfffffe7u},
{28, 0xfffffe8u},
{24, 0xffffeau},
{30, 0x3ffffffcu},
{28, 0xfffffe9u},
{28, 0xfffffeau},
{30, 0x3ffffffdu},
{28, 0xfffffebu},
{28, 0xfffffecu},
{28, 0xfffffedu},
{28, 0xfffffeeu},
{28, 0xfffffefu},
{28, 0xffffff0u},
{28, 0xffffff1u},
{28, 0xffffff2u},
{30, 0x3ffffffeu},
{28, 0xffffff3u},
{28, 0xffffff4u},
{28, 0xffffff5u},
{28, 0xffffff6u},
{28, 0xffffff7u},
{28, 0xffffff8u},
{28, 0xffffff9u},
{28, 0xffffffau},
{28, 0xffffffbu},
{6, 0x14u},
{10, 0x3f8u},
{10, 0x3f9u},
{12, 0xffau},
{13, 0x1ff9u},
{6, 0x15u},
{8, 0xf8u},
{11, 0x7fau},
{10, 0x3fau},
{10, 0x3fbu},
{8, 0xf9u},
{11, 0x7fbu},
{8, 0xfau},
{6, 0x16u},
{6, 0x17u},
{6, 0x18u},
{5, 0x0u},
{5, 0x1u},
{5, 0x2u},
{6, 0x19u},
{6, 0x1au},
{6, 0x1bu},
{6, 0x1cu},
{6, 0x1du},
{6, 0x1eu},
{6, 0x1fu},
{7, 0x5cu},
{8, 0xfbu},
{15, 0x7ffcu},
{6, 0x20u},
{12, 0xffbu},
{10, 0x3fcu},
{13, 0x1ffau},
{6, 0x21u},
{7, 0x5du},
{7, 0x5eu},
{7, 0x5fu},
{7, 0x60u},
{7, 0x61u},
{7, 0x62u},
{7, 0x63u},
{7, 0x64u},
{7, 0x65u},
{7, 0x66u},
{7, 0x67u},
{7, 0x68u},
{7, 0x69u},
{7, 0x6au},
{7, 0x6bu},
{7, 0x6cu},
{7, 0x6du},
{7, 0x6eu},
{7, 0x6fu},
{7, 0x70u},
{7, 0x71u},
{7, 0x72u},
{8, 0xfcu},
{7, 0x73u},
{8, 0xfdu},
{13, 0x1ffbu},
{19, 0x7fff0u},
{13, 0x1ffcu},
{14, 0x3ffcu},
{6, 0x22u},
{15, 0x7ffdu},
{5, 0x3u},
{6, 0x23u},
{5, 0x4u},
{6, 0x24u},
{5, 0x5u},
{6, 0x25u},
{6, 0x26u},
{6, 0x27u},
{5, 0x6u},
{7, 0x74u},
{7, 0x75u},
{6, 0x28u},
{6, 0x29u},
{6, 0x2au},
{5, 0x7u},
{6, 0x2bu},
{7, 0x76u},
{6, 0x2cu},
{5, 0x8u},
{5, 0x9u},
{6, 0x2du},
{7, 0x77u},
{7, 0x78u},
{7, 0x79u},
{7, 0x7au},
{7, 0x7bu},
{15, 0x7ffeu},
{11, 0x7fcu},
{14, 0x3ffdu},
{13, 0x1ffdu},
{28, 0xffffffcu},
{20, 0xfffe6u},
{22, 0x3fffd2u},
{20, 0xfffe7u},
{20, 0xfffe8u},
{22, 0x3fffd3u},
{22, 0x3fffd4u},
{22, 0x3fffd5u},
{23, 0x7fffd9u},
{22, 0x3fffd6u},
{23, 0x7fffdau},
{23, 0x7fffdbu},
{23, 0x7fffdcu},
{23, 0x7fffddu},
{23, 0x7fffdeu},
{24, 0xffffebu},
{23, 0x7fffdfu},
{24, 0xffffecu},
{24, 0xffffedu},
{22, 0x3fffd7u},
{23, 0x7fffe0u},
{24, 0xffffeeu},
{23, 0x7fffe1u},
{23, 0x7fffe2u},
{23, 0x7fffe3u},
{23, 0x7fffe4u},
{21, 0x1fffdcu},
{22, 0x3fffd8u},
{23, 0x7fffe5u},
{22, 0x3fffd9u},
{23, 0x7fffe6u},
{23, 0x7fffe7u},
{24, 0xffffefu},
{22, 0x3fffdau},
{21, 0x1fffddu},
{20, 0xfffe9u},
{22, 0x3fffdbu},
{22, 0x3fffdcu},
{23, 0x7fffe8u},
{23, 0x7fffe9u},
{21, 0x1fffdeu},
{23, 0x7fffeau},
{22, 0x3fffddu},
{22, 0x3fffdeu},
{24, 0xfffff0u},
{21, 0x1fffdfu},
{22, 0x3fffdfu},
{23, 0x7fffebu},
{23, 0x7fffecu},
{21, 0x1fffe0u},
{21, 0x1fffe1u},
{22, 0x3fffe0u},
{21, 0x1fffe2u},
{23, 0x7fffedu},
{22, 0x3fffe1u},
{23, 0x7fffeeu},
{23, 0x7fffefu},
{20, 0xfffeau},
{22, 0x3fffe2u},
{22, 0x3fffe3u},
{22, 0x3fffe4u},
{23, 0x7ffff0u},
{22, 0x3fffe5u},
{22, 0x3fffe6u},
{23, 0x7ffff1u},
{26, 0x3ffffe0u},
{26, 0x3ffffe1u},
{20, 0xfffebu},
{19, 0x7fff1u},
{22, 0x3fffe7u},
{23, 0x7ffff2u},
{22, 0x3fffe8u},
{25, 0x1ffffecu},
{26, 0x3ffffe2u},
{26, 0x3ffffe3u},
{26, 0x3ffffe4u},
{27, 0x7ffffdeu},
{27, 0x7ffffdfu},
{26, 0x3ffffe5u},
{24, 0xfffff1u},
{25, 0x1ffffedu},
{19, 0x7fff2u},
{21, 0x1fffe3u},
{26, 0x3ffffe6u},
{27, 0x7ffffe0u},
{27, 0x7ffffe1u},
{26, 0x3ffffe7u},
{27, 0x7ffffe2u},
{24, 0xfffff2u},
{21, 0x1fffe4u},
{21, 0x1fffe5u},
{26, 0x3ffffe8u},
{26, 0x3ffffe9u},
{28, 0xffffffdu},
{27, 0x7ffffe3u},
{27, 0x7ffffe4u},
{27, 0x7ffffe5u},
{20, 0xfffecu},
{24, 0xfffff3u},
{20, 0xfffedu},
{21, 0x1fffe6u},
{22, 0x3fffe9u},
{21, 0x1fffe7u},
{21, 0x1fffe8u},
{23, 0x7ffff3u},
{22, 0x3fffeau},
{22, 0x3fffebu},
{25, 0x1ffffeeu},
{25, 0x1ffffefu},
{24, 0xfffff4u},
{24, 0xfffff5u},
{26, 0x3ffffeau},
{23, 0x7ffff4u},
{26, 0x3ffffebu},
{27, 0x7ffffe6u},
{26, 0x3ffffecu},
{26, 0x3ffffedu},
{27, 0x7ffffe7u},
{27, 0x7ffffe8u},
{27, 0x7ffffe9u},
{27, 0x7ffffeau},
{27, 0x7ffffebu},
{28, 0xffffffeu},
{27, 0x7ffffecu},
{27, 0x7ffffedu},
{27, 0x7ffffeeu},
{27, 0x7ffffefu},
{27, 0x7fffff0u},
{26, 0x3ffffeeu},
{30, 0x3fffffffu}};
const nghttp2_huff_decode huff_decode_table[][16] = {
/* 0 */

View File

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

View File

@@ -26,10 +26,11 @@
#define NGHTTP2_HELPER_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_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))
@@ -58,25 +59,6 @@ uint16_t nghttp2_get_uint16(const uint8_t *data);
*/
uint32_t nghttp2_get_uint32(const uint8_t *data);
/*
* Ensures that buffer |*buf_ptr| with |*buflen_ptr| length has at
* least |min_length| bytes. If |min_length| > |*buflen_ptr|,
* allocates new buffer having at least |min_length| bytes and assigns
* its pointer to |*buf_ptr| and allocated number of bytes to
* |*buflen_ptr|. The memory pointed by |*buf_ptr| previously may
* change. No memory copy is done between old and new buffer.
* |*buf_ptr| and |*buflen_ptr| are only updated iff this function
* succeeds.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t min_length);
/*
* Allocates |n| bytes of memory and copy the memory region pointed by
* |src| with the length |n| bytes into it. Returns the allocated memory.
@@ -87,7 +69,7 @@ int nghttp2_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
void* nghttp2_memdup(const void* src, size_t n);
void *nghttp2_memdup(const void *src, size_t n, nghttp2_mem *mem);
void nghttp2_downcase(uint8_t *s, size_t len);
@@ -118,19 +100,11 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
int nghttp2_should_send_window_update(int32_t local_window_size,
int32_t recv_window_size);
/*
* Deallocates memory space pointed by |ptr|. This function exists for
* the application to free the memory space allocated by the library
* functions. Currently this function is hidden from the public API,
* but may be exposed as public API.
*/
void nghttp2_free(void *ptr);
/*
* Copies the buffer |src| of length |len| to the destination pointed
* by the |dest|, assuming that the |dest| is at lest |len| bytes long
* . Returns dest + len.
*/
uint8_t* nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
#endif /* NGHTTP2_HELPER_H */

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_INT_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
/* Macros, types and constants for internal use */
@@ -34,7 +34,9 @@
#ifdef DEBUGBUILD
#define DEBUGF(x) x
#else
#define DEBUGF(x) do { } while(0)
#define DEBUGF(x) \
do { \
} while (0)
#endif
typedef int (*nghttp2_compar)(const void *lhs, const void *rhs);

View File

@@ -26,13 +26,14 @@
#include <string.h>
#define INITIAL_TABLE_LENGTH 16
#define INITIAL_TABLE_LENGTH 256
int nghttp2_map_init(nghttp2_map *map)
{
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
map->mem = mem;
map->tablelen = INITIAL_TABLE_LENGTH;
map->table = calloc(map->tablelen, sizeof(nghttp2_map_entry*));
if(map->table == NULL) {
map->table =
nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_entry *));
if (map->table == NULL) {
return NGHTTP2_ERR_NOMEM;
}
@@ -41,19 +42,17 @@ int nghttp2_map_init(nghttp2_map *map)
return 0;
}
void nghttp2_map_free(nghttp2_map *map)
{
free(map->table);
void nghttp2_map_free(nghttp2_map *map) {
nghttp2_mem_free(map->mem, map->table);
}
void nghttp2_map_each_free(nghttp2_map *map,
int (*func)(nghttp2_map_entry *entry, void *ptr),
void *ptr)
{
void *ptr) {
size_t i;
for(i = 0; i < map->tablelen; ++i) {
for (i = 0; i < map->tablelen; ++i) {
nghttp2_map_entry *entry;
for(entry = map->table[i]; entry;) {
for (entry = map->table[i]; entry;) {
nghttp2_map_entry *next = entry->next;
func(entry, ptr);
entry = next;
@@ -64,15 +63,14 @@ void nghttp2_map_each_free(nghttp2_map *map,
int nghttp2_map_each(nghttp2_map *map,
int (*func)(nghttp2_map_entry *entry, void *ptr),
void *ptr)
{
void *ptr) {
int rv;
size_t i;
for(i = 0; i < map->tablelen; ++i) {
for (i = 0; i < map->tablelen; ++i) {
nghttp2_map_entry *entry;
for(entry = map->table[i]; entry; entry = entry->next) {
for (entry = map->table[i]; entry; entry = entry->next) {
rv = func(entry, ptr);
if(rv != 0) {
if (rv != 0) {
return rv;
}
}
@@ -80,32 +78,29 @@ int nghttp2_map_each(nghttp2_map *map,
return 0;
}
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key)
{
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) {
entry->key = key;
entry->next = NULL;
}
/* Same hash function in android HashMap source code. */
/* The |mod| must be power of 2 */
static int32_t hash(int32_t h, size_t mod)
{
static int32_t hash(int32_t h, size_t mod) {
h ^= (h >> 20) ^ (h >> 12);
h ^= (h >> 7) ^ (h >> 4);
return h & (mod - 1);
}
static int insert(nghttp2_map_entry **table, size_t tablelen,
nghttp2_map_entry *entry)
{
nghttp2_map_entry *entry) {
int32_t h = hash(entry->key, tablelen);
if(table[h] == NULL) {
if (table[h] == NULL) {
table[h] = entry;
} else {
nghttp2_map_entry *p;
/* We won't allow duplicated key, so check it out. */
for(p = table[h]; p; p = p->next) {
if(p->key == entry->key) {
for (p = table[h]; p; p = p->next) {
if (p->key == entry->key) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
}
@@ -116,18 +111,19 @@ static int insert(nghttp2_map_entry **table, size_t tablelen,
}
/* new_tablelen must be power of 2 */
static int resize(nghttp2_map *map, size_t new_tablelen)
{
static int resize(nghttp2_map *map, size_t new_tablelen) {
size_t i;
nghttp2_map_entry **new_table;
new_table = calloc(new_tablelen, sizeof(nghttp2_map_entry*));
if(new_table == NULL) {
new_table =
nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_entry *));
if (new_table == NULL) {
return NGHTTP2_ERR_NOMEM;
}
for(i = 0; i < map->tablelen; ++i) {
for (i = 0; i < map->tablelen; ++i) {
nghttp2_map_entry *entry;
for(entry = map->table[i]; entry;) {
for (entry = map->table[i]; entry;) {
nghttp2_map_entry *next = entry->next;
entry->next = NULL;
/* This function must succeed */
@@ -135,52 +131,50 @@ static int resize(nghttp2_map *map, size_t new_tablelen)
entry = next;
}
}
free(map->table);
nghttp2_mem_free(map->mem, map->table);
map->tablelen = new_tablelen;
map->table = new_table;
return 0;
}
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry)
{
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
int rv;
/* Load factor is 0.75 */
if((map->size + 1) * 4 > map->tablelen * 3) {
if ((map->size + 1) * 4 > map->tablelen * 3) {
rv = resize(map, map->tablelen * 2);
if(rv != 0) {
if (rv != 0) {
return rv;
}
}
rv = insert(map->table, map->tablelen, new_entry);
if(rv != 0) {
if (rv != 0) {
return rv;
}
++map->size;
return 0;
}
nghttp2_map_entry* nghttp2_map_find(nghttp2_map *map, key_type key)
{
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) {
int32_t h;
nghttp2_map_entry *entry;
h = hash(key, map->tablelen);
for(entry = map->table[h]; entry; entry = entry->next) {
if(entry->key == key) {
for (entry = map->table[h]; entry; entry = entry->next) {
if (entry->key == key) {
return entry;
}
}
return NULL;
}
int nghttp2_map_remove(nghttp2_map *map, key_type key)
{
int nghttp2_map_remove(nghttp2_map *map, key_type key) {
int32_t h;
nghttp2_map_entry *entry, *prev;
h = hash(key, map->tablelen);
prev = NULL;
for(entry = map->table[h]; entry; entry = entry->next) {
if(entry->key == key) {
if(prev == NULL) {
for (entry = map->table[h]; entry; entry = entry->next) {
if (entry->key == key) {
if (prev == NULL) {
map->table[h] = entry->next;
} else {
prev->next = entry->next;
@@ -193,7 +187,4 @@ int nghttp2_map_remove(nghttp2_map *map, key_type key)
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
size_t nghttp2_map_size(nghttp2_map *map)
{
return map->size;
}
size_t nghttp2_map_size(nghttp2_map *map) { return map->size; }

View File

@@ -26,11 +26,12 @@
#define NGHTTP2_MAP_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_int.h"
#include "nghttp2_mem.h"
/* Implementation of unordered map */
@@ -43,6 +44,7 @@ typedef struct nghttp2_map_entry {
typedef struct {
nghttp2_map_entry **table;
nghttp2_mem *mem;
size_t tablelen;
size_t size;
} nghttp2_map;
@@ -56,7 +58,7 @@ typedef struct {
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_map_init(nghttp2_map *map);
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |map|. The stored entries
@@ -98,7 +100,7 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
* Returns the entry associated by the key |key|. If there is no such
* entry, this function returns NULL.
*/
nghttp2_map_entry* nghttp2_map_find(nghttp2_map *map, key_type key);
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
/*
* Removes the entry associated by the key |key| from the |map|. The

61
lib/nghttp2_mem.c Normal file
View File

@@ -0,0 +1,61 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp2_mem.h"
static void *default_malloc(size_t size, void *mem_user_data _U_) {
return malloc(size);
}
static void default_free(void *ptr, void *mem_user_data _U_) { free(ptr); }
static void *default_calloc(size_t nmemb, size_t size,
void *mem_user_data _U_) {
return calloc(nmemb, size);
}
static void *default_realloc(void *ptr, size_t size, void *mem_user_data _U_) {
return realloc(ptr, size);
}
static nghttp2_mem mem_default = {NULL, default_malloc, default_free,
default_calloc, default_realloc};
nghttp2_mem *nghttp2_mem_default(void) { return &mem_default; }
void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size) {
return mem->malloc(size, mem->mem_user_data);
}
void nghttp2_mem_free(nghttp2_mem *mem, void *ptr) {
mem->free(ptr, mem->mem_user_data);
}
void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size) {
return mem->calloc(nmemb, size, mem->mem_user_data);
}
void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size) {
return mem->realloc(ptr, size, mem->mem_user_data);
}

44
lib/nghttp2_mem.h Normal file
View File

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

View File

@@ -26,19 +26,19 @@
#define NGHTTP2_NET_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#include <arpa/inet.h>
#endif /* HAVE_ARPA_INET_H */
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
#include <winsock2.h>
#endif /* HAVE_WINSOCK2_H */
#endif /* NGHTTP2_NET_H */

View File

@@ -27,28 +27,26 @@
#include <string.h>
int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen)
{
const unsigned char *in, unsigned int inlen) {
int http_selected = 0;
unsigned int i = 0;
for(; i < inlen; i += in[i]+1) {
if(in[i] == NGHTTP2_PROTO_VERSION_ID_LEN &&
i + 1 + in[i] <= inlen &&
memcmp(&in[i+1], NGHTTP2_PROTO_VERSION_ID, in[i]) == 0) {
*out = (unsigned char*)&in[i+1];
for (; i < inlen; i += in [i] + 1) {
if (in[i] == NGHTTP2_PROTO_VERSION_ID_LEN && i + 1 + in[i] <= inlen &&
memcmp(&in[i + 1], NGHTTP2_PROTO_VERSION_ID, in[i]) == 0) {
*out = (unsigned char *)&in[i + 1];
*outlen = in[i];
return 1;
}
if(in[i] == 8 && i + 1 + in[i] <= inlen &&
memcmp(&in[i+1], "http/1.1", in[i]) == 0) {
if (in[i] == 8 && i + 1 + in[i] <= inlen &&
memcmp(&in[i + 1], "http/1.1", in[i]) == 0) {
http_selected = 1;
*out = (unsigned char*)&in[i+1];
*out = (unsigned char *)&in[i + 1];
*outlen = in[i];
/* Go through to the next iteration, because "HTTP/2" may be
there */
}
}
if(http_selected) {
if (http_selected) {
return 0;
} else {
return -1;

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_NPN_H
#ifdef HAVE_CONFIG
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG */
#include <nghttp2/nghttp2.h>

View File

@@ -24,31 +24,30 @@
*/
#include "nghttp2_option.h"
int nghttp2_option_new(nghttp2_option **option_ptr)
{
int nghttp2_option_new(nghttp2_option **option_ptr) {
*option_ptr = calloc(1, sizeof(nghttp2_option));
if(*option_ptr == NULL) {
if (*option_ptr == NULL) {
return NGHTTP2_ERR_NOMEM;
}
return 0;
}
void nghttp2_option_del(nghttp2_option *option)
{
free(option);
}
void nghttp2_option_del(nghttp2_option *option) { free(option); }
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val)
{
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val) {
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE;
option->no_auto_window_update = val;
}
void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
uint32_t val)
{
uint32_t val) {
option->opt_set_mask |= NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS;
option->peer_max_concurrent_streams = val;
}
void nghttp2_option_set_recv_client_preface(nghttp2_option *option, int val) {
option->opt_set_mask |= NGHTTP2_OPT_RECV_CLIENT_PREFACE;
option->recv_client_preface = val;
}

View File

@@ -26,7 +26,7 @@
#define NGHTTP2_OPTION_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
@@ -56,7 +56,8 @@ typedef enum {
* will be overwritten if the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
*/
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
NGHTTP2_OPT_RECV_CLIENT_PREFACE = 1 << 2,
} nghttp2_option_flag;
/**
@@ -76,6 +77,10 @@ struct nghttp2_option {
* NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
*/
uint8_t no_auto_window_update;
/**
* NGHTTP2_OPT_RECV_CLIENT_PREFACE
*/
uint8_t recv_client_preface;
};
#endif /* NGHTTP2_OPTION_H */

View File

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

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