mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-07 10:38:53 +08:00
Compare commits
326 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efa344be98 | ||
|
|
2ba9a009fe | ||
|
|
c59ffa09e0 | ||
|
|
72f5e028d0 | ||
|
|
80b361dbb0 | ||
|
|
58254adb11 | ||
|
|
7f60e8a307 | ||
|
|
c31be5af4d | ||
|
|
292c01fda2 | ||
|
|
91f7d43e84 | ||
|
|
ce71e65aee | ||
|
|
1119701071 | ||
|
|
42122c270a | ||
|
|
1348621d9e | ||
|
|
8c5ea61376 | ||
|
|
c410f4055f | ||
|
|
1e86635572 | ||
|
|
62ede05c09 | ||
|
|
a067eb02a5 | ||
|
|
154876a17b | ||
|
|
f8c70993c0 | ||
|
|
03a2828fcf | ||
|
|
2fc0056ada | ||
|
|
9a33116526 | ||
|
|
29fcd7c946 | ||
|
|
189f122dd7 | ||
|
|
69c708be44 | ||
|
|
14e56fcd81 | ||
|
|
db67412511 | ||
|
|
76800dc8e7 | ||
|
|
7d282cd0bd | ||
|
|
49b8d1d88c | ||
|
|
4d93dd9d91 | ||
|
|
be1a513c59 | ||
|
|
20900b133e | ||
|
|
279fc2ad37 | ||
|
|
0ef99b90d9 | ||
|
|
1bd8f6a0e2 | ||
|
|
f70c142e10 | ||
|
|
b3fbf047b2 | ||
|
|
0cd8da2cd9 | ||
|
|
7fa0f2763e | ||
|
|
f381b13c91 | ||
|
|
6b9382d865 | ||
|
|
2c335dbc7a | ||
|
|
b3463b20a3 | ||
|
|
15bdf048cc | ||
|
|
992ca93533 | ||
|
|
b4ed3324c0 | ||
|
|
98fd6019cf | ||
|
|
6ccae48f7c | ||
|
|
6933e0ef54 | ||
|
|
a9ecdca08a | ||
|
|
af5bedd45f | ||
|
|
7097a31968 | ||
|
|
4122920dc6 | ||
|
|
9aed11e3dc | ||
|
|
9ea4905f68 | ||
|
|
c6cfcc3c30 | ||
|
|
4bc5e55113 | ||
|
|
566a252577 | ||
|
|
27c766cb04 | ||
|
|
41dd6d0205 | ||
|
|
db071ca35c | ||
|
|
e3af9d8bd3 | ||
|
|
73955f0519 | ||
|
|
5df21e3683 | ||
|
|
a6e1a40c05 | ||
|
|
e330520341 | ||
|
|
d13ed04b17 | ||
|
|
75a23c6c7e | ||
|
|
eaca5d83b0 | ||
|
|
9c1b5e8fb1 | ||
|
|
0c31dbb5d9 | ||
|
|
8a0b11e9e1 | ||
|
|
7ca2787cc8 | ||
|
|
cfbf907418 | ||
|
|
dd02c4cd9b | ||
|
|
93ee5bdba6 | ||
|
|
f2aa6f4e2b | ||
|
|
bc8a583184 | ||
|
|
502ff24568 | ||
|
|
47692d113c | ||
|
|
19c2805d0d | ||
|
|
df078dc004 | ||
|
|
e570225e97 | ||
|
|
8fffa05513 | ||
|
|
0d4120ce2c | ||
|
|
20de432725 | ||
|
|
325bb0115e | ||
|
|
cc3b41ec96 | ||
|
|
225b90eefd | ||
|
|
3931a0b04d | ||
|
|
70c0558443 | ||
|
|
f2bfe623fc | ||
|
|
80dcb565eb | ||
|
|
6d42b6697b | ||
|
|
bcbb2e8649 | ||
|
|
ba92935f64 | ||
|
|
402c262de5 | ||
|
|
03c4092862 | ||
|
|
a225bb29df | ||
|
|
f3a76d84f1 | ||
|
|
7a09feebc3 | ||
|
|
32ddca532a | ||
|
|
df875db989 | ||
|
|
1d138accb9 | ||
|
|
7e6019aef1 | ||
|
|
e20b417b84 | ||
|
|
df56b69060 | ||
|
|
b6d0a32d0e | ||
|
|
a82956d1d6 | ||
|
|
9c0760e3c1 | ||
|
|
4e71e9e2e8 | ||
|
|
521450c7ad | ||
|
|
aa57e91e85 | ||
|
|
4023c26cf1 | ||
|
|
a0f558ee3c | ||
|
|
4f0d03b4b9 | ||
|
|
88d7abcc23 | ||
|
|
409316018d | ||
|
|
d25b9da9f6 | ||
|
|
b48ceac56c | ||
|
|
34413d8d7c | ||
|
|
b7ccca4c47 | ||
|
|
e887b2516f | ||
|
|
be0f6dcaaf | ||
|
|
937bb9f768 | ||
|
|
a11fbf6e2f | ||
|
|
9aa914c756 | ||
|
|
e20d2ba9c1 | ||
|
|
c1be28684a | ||
|
|
fd07f5e142 | ||
|
|
99ca15cae0 | ||
|
|
3651467c71 | ||
|
|
c27ec6f57b | ||
|
|
485d04851c | ||
|
|
83728219db | ||
|
|
5d0bf4cc84 | ||
|
|
446f8f13aa | ||
|
|
96bb9c2018 | ||
|
|
a9b74261b6 | ||
|
|
89c3c08590 | ||
|
|
83309b6391 | ||
|
|
23dd428d65 | ||
|
|
b305495a75 | ||
|
|
727662257c | ||
|
|
b2f88f8fe3 | ||
|
|
44ac571037 | ||
|
|
5bff48a15a | ||
|
|
e4751a798a | ||
|
|
6fc12caa6d | ||
|
|
d00d4d647d | ||
|
|
5ff73de195 | ||
|
|
901de5fbce | ||
|
|
5847a56c40 | ||
|
|
0da0140026 | ||
|
|
207b1db6af | ||
|
|
85f605f20d | ||
|
|
5cf07f5c21 | ||
|
|
340b52da84 | ||
|
|
3de678e164 | ||
|
|
0af71ee6be | ||
|
|
d8c0d87c90 | ||
|
|
9b2c24ad68 | ||
|
|
b4bb6a6101 | ||
|
|
8890e593e6 | ||
|
|
ec0a2e7cca | ||
|
|
f8471a5f45 | ||
|
|
f34cbf9b45 | ||
|
|
a23a705121 | ||
|
|
822ec75814 | ||
|
|
0209b7c083 | ||
|
|
70a8fd59b1 | ||
|
|
223242b512 | ||
|
|
42ac80d3da | ||
|
|
4c11cd0671 | ||
|
|
4c5c6749a0 | ||
|
|
dd038bf753 | ||
|
|
577512f2ca | ||
|
|
565c635e9b | ||
|
|
0b1ab90fb8 | ||
|
|
93b4d9efc3 | ||
|
|
82bc7198e6 | ||
|
|
03ed29953e | ||
|
|
a36c4c6f5f | ||
|
|
3daa6f2c30 | ||
|
|
53ee21caa9 | ||
|
|
31528b6267 | ||
|
|
ab5b81bee1 | ||
|
|
9f6bb989e3 | ||
|
|
3655090997 | ||
|
|
3cd08251ca | ||
|
|
1673ae2c99 | ||
|
|
bf48ef9bab | ||
|
|
1093b3eeab | ||
|
|
d5da7611fa | ||
|
|
9893ae81af | ||
|
|
7bfa276e96 | ||
|
|
02c5621c61 | ||
|
|
9ad2c0887e | ||
|
|
0c7e2fbec6 | ||
|
|
cfee9cab36 | ||
|
|
679a0a0fa1 | ||
|
|
d5dcbf6f3b | ||
|
|
69b9ce6b68 | ||
|
|
c81e87bf37 | ||
|
|
97533c966d | ||
|
|
d6b495f2a7 | ||
|
|
c7e9fe8154 | ||
|
|
fb62a5ed4f | ||
|
|
345121975a | ||
|
|
a5dfe24e49 | ||
|
|
273d9f4f7d | ||
|
|
500c5eea56 | ||
|
|
83a39f5b49 | ||
|
|
2fb675f13c | ||
|
|
eebd1f5492 | ||
|
|
00ead22395 | ||
|
|
2b4bd57c7f | ||
|
|
86dd1519b4 | ||
|
|
a507fc80b6 | ||
|
|
69c3920a1a | ||
|
|
bbe4f5a3d1 | ||
|
|
49a9ec2cb3 | ||
|
|
5d2390deba | ||
|
|
02c347fe6b | ||
|
|
3c056973a1 | ||
|
|
d17f35a488 | ||
|
|
1b8ad61779 | ||
|
|
ede801d099 | ||
|
|
9649b2d346 | ||
|
|
53e52194b5 | ||
|
|
0e8419ac37 | ||
|
|
da08ba5d50 | ||
|
|
30fa6d24d0 | ||
|
|
f776c50d43 | ||
|
|
7b85f6c50d | ||
|
|
21cbf417c8 | ||
|
|
ca680c16e3 | ||
|
|
bf13d91264 | ||
|
|
8aa6580d89 | ||
|
|
11fa71ba6c | ||
|
|
58afce2382 | ||
|
|
24cfb52b5a | ||
|
|
d499803221 | ||
|
|
894783f572 | ||
|
|
93ed89df5f | ||
|
|
1a2e50ca08 | ||
|
|
76703f79fa | ||
|
|
4679188069 | ||
|
|
4c3aa081a0 | ||
|
|
ab9b0538bc | ||
|
|
24edd2972d | ||
|
|
a8b7fa524f | ||
|
|
b827b99b2f | ||
|
|
88add854ff | ||
|
|
704bbbfcaa | ||
|
|
e217e789de | ||
|
|
d4d56e1846 | ||
|
|
8883df2fd6 | ||
|
|
d496c42dc9 | ||
|
|
8433a75a6b | ||
|
|
76b3ba2832 | ||
|
|
05f982dcfb | ||
|
|
cc24b9aaf0 | ||
|
|
e6695d9ba7 | ||
|
|
9fb2bc8468 | ||
|
|
6ccf06c6da | ||
|
|
49e3fd6862 | ||
|
|
9c1a956e47 | ||
|
|
86b089f957 | ||
|
|
3f212a60a5 | ||
|
|
5c61917007 | ||
|
|
8736f61fbd | ||
|
|
04e94824a0 | ||
|
|
ec93c9f55f | ||
|
|
6c71889552 | ||
|
|
4bbb4172aa | ||
|
|
9ccf4c037d | ||
|
|
1f356391f1 | ||
|
|
3c603ec4ae | ||
|
|
d36bea8554 | ||
|
|
16101b8b3f | ||
|
|
455d911f61 | ||
|
|
2fb750f2e3 | ||
|
|
7c781bcd1a | ||
|
|
a234166fc4 | ||
|
|
ecb7e7db74 | ||
|
|
99ceb7df33 | ||
|
|
2e0775d506 | ||
|
|
ac28cd7efa | ||
|
|
a5ec5c1a1d | ||
|
|
7952029752 | ||
|
|
2e083352d5 | ||
|
|
d848b9815a | ||
|
|
48734b6d05 | ||
|
|
8838f666cb | ||
|
|
d8d14a3fc9 | ||
|
|
6e027ad830 | ||
|
|
9d78167297 | ||
|
|
c13329b328 | ||
|
|
b8a2bf2675 | ||
|
|
98be65a1eb | ||
|
|
742b28833a | ||
|
|
77374ac6e2 | ||
|
|
c4be7d48a0 | ||
|
|
0752ce6701 | ||
|
|
8d5422c9bb | ||
|
|
04b5d1679f | ||
|
|
15055c11f9 | ||
|
|
c859fb8f7c | ||
|
|
dd1850aed0 | ||
|
|
079db14d45 | ||
|
|
9f17bee51d | ||
|
|
e904842504 | ||
|
|
4f815521ae | ||
|
|
78df530b90 | ||
|
|
e147c14186 | ||
|
|
06453fb15e | ||
|
|
af5fd2019d | ||
|
|
744ec4dba1 | ||
|
|
38bfbffb1b | ||
|
|
63398f30dd | ||
|
|
961dcf614a | ||
|
|
5b572d8d59 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -21,6 +21,7 @@ install-sh
|
||||
.libs
|
||||
lib/includes/nghttp2/nghttp2ver.h
|
||||
lib/libnghttp2.pc
|
||||
src/libnghttp2_asio.pc
|
||||
ltmain.sh
|
||||
stamp-h1
|
||||
.deps/
|
||||
@@ -39,3 +40,9 @@ doc/nghttpx-howto.rst
|
||||
doc/h2load-howto.rst
|
||||
doc/tutorial-hpack.rst
|
||||
doc/python-apiref.rst
|
||||
doc/building-android-binary.rst
|
||||
doc/asio_http2.h.rst
|
||||
doc/libnghttp2_asio.rst
|
||||
python/setup.py
|
||||
python/dist
|
||||
python/MANIFEST
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
#Disable gcc build for the moment...
|
||||
# - gcc
|
||||
python:
|
||||
- "3.4"
|
||||
before_install:
|
||||
@@ -34,3 +35,4 @@ before_script:
|
||||
- ./configure --enable-werror
|
||||
script:
|
||||
- make
|
||||
- make check
|
||||
|
||||
19
COPYING
19
COPYING
@@ -20,3 +20,22 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
[The text below was composed based on 1.2. License section of
|
||||
curl/libcurl project.]
|
||||
|
||||
When contributing with code, you agree to put your changes and new
|
||||
code under the same license nghttp2 is already using unless stated and
|
||||
agreed otherwise.
|
||||
|
||||
When changing existing source code, you do not alter the copyright of
|
||||
the original file(s). The copyright will still be owned by the
|
||||
original creator(s) or those who have been assigned copyright by the
|
||||
original author(s).
|
||||
|
||||
By submitting a patch to the nghttp2 project, you are assumed to have
|
||||
the right to the code and to be allowed by your employer or whatever
|
||||
to hand over that patch/code to us. We will credit you for your
|
||||
changes as far as possible, to give credit but also to keep a trace
|
||||
back to who made what changes. Please always provide us with your
|
||||
full real name when contributing!
|
||||
|
||||
100
Dockerfile.android
Normal file
100
Dockerfile.android
Normal file
@@ -0,0 +1,100 @@
|
||||
# Dockerfile to build nghttp2 android binary
|
||||
#
|
||||
# $ sudo docker build -t nghttp2-android - < Dockerfile.android
|
||||
#
|
||||
# After successful build, android binaries are located under
|
||||
# /root/build/nghttp2. You can copy the binary using docker cp. For
|
||||
# example, to copy nghttpx binary to host file system location
|
||||
# /path/to/dest, do this:
|
||||
#
|
||||
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
|
||||
|
||||
FROM ubuntu
|
||||
|
||||
MAINTAINER Tatsuhiro Tsujikawa
|
||||
|
||||
ENV ANDROID_HOME /root/android
|
||||
ENV PREFIX $ANDROID_HOME/usr/local
|
||||
ENV TOOLCHAIN $ANDROID_HOME/toolchain
|
||||
ENV PATH $TOOLCHAIN/bin:$PATH
|
||||
|
||||
# It would be better to use nearest ubuntu archive mirror for faster
|
||||
# downloads.
|
||||
# RUN sed -ie 's/archive\.ubuntu/jp.archive.ubuntu/g' /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update
|
||||
# genisoimage, libc6-i386 and lib32stdc++6 are required to decompress ndk.
|
||||
RUN apt-get install -y make binutils autoconf automake autotools-dev libtool \
|
||||
pkg-config git curl dpkg-dev libxml2-dev \
|
||||
genisoimage libc6-i386 lib32stdc++6
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin
|
||||
RUN chmod a+x android-ndk-r10c-linux-x86_64.bin
|
||||
RUN ./android-ndk-r10c-linux-x86_64.bin
|
||||
|
||||
WORKDIR /root/build/android-ndk-r10c
|
||||
RUN /bin/bash build/tools/make-standalone-toolchain.sh \
|
||||
--install-dir=$ANDROID_HOME/toolchain \
|
||||
--toolchain=arm-linux-androideabi-4.9 --llvm-version=3.5 \
|
||||
--system=linux-x86_64
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN git clone https://github.com/tatsuhiro-t/spdylay
|
||||
WORKDIR /root/build/spdylay
|
||||
RUN autoreconf -i && \
|
||||
./configure \
|
||||
--disable-shared \
|
||||
--host=arm-linux-androideabi \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
--without-libxml2 \
|
||||
--disable-src \
|
||||
--disable-examples \
|
||||
CPPFLAGS="-I$PREFIX/include" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||
LDFLAGS="-L$PREFIX/lib" && \
|
||||
make install
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.1j.tar.gz
|
||||
RUN tar xf openssl-1.0.1j.tar.gz
|
||||
WORKDIR /root/build/openssl-1.0.1j
|
||||
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
|
||||
./Configure --prefix=$PREFIX android && \
|
||||
make && make install_sw
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN curl -L -O https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
|
||||
RUN tar xf libevent-2.0.21-stable.tar.gz
|
||||
WORKDIR /root/build/libevent-2.0.21-stable
|
||||
RUN ./configure \
|
||||
--host=arm-linux-androideabi \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
CPPFLAGS=-I$PREFIX/include \
|
||||
LDFLAGS=-L$PREFIX/lib && \
|
||||
make install
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN git clone https://github.com/tatsuhiro-t/nghttp2
|
||||
WORKDIR /root/build/nghttp2
|
||||
RUN autoreconf -i && \
|
||||
./configure \
|
||||
--disable-shared \
|
||||
--host=arm-linux-androideabi \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--with-xml-prefix="$PREFIX" \
|
||||
--without-libxml2 \
|
||||
--disable-python-bindings \
|
||||
--disable-examples \
|
||||
--disable-threads \
|
||||
LIBSPDYLAY_CFLAGS=-I$PREFIX/usr/local/include \
|
||||
LIBSPDYLAY_LIBS="-L$PREFIX/usr/local/lib -lspdylay" \
|
||||
CPPFLAGS="-I$PREFIX/include" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||
LDFLAGS="-L$PREFIX/lib" && \
|
||||
make && \
|
||||
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp
|
||||
@@ -20,10 +20,11 @@
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
SUBDIRS = lib third-party src examples python tests doc
|
||||
SUBDIRS = lib third-party src examples python tests doc contrib
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
dist_doc_DATA = README.rst
|
||||
|
||||
EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make
|
||||
EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make \
|
||||
Dockerfile.android
|
||||
|
||||
121
README.rst
121
README.rst
@@ -4,12 +4,14 @@ nghttp2 - HTTP/2 C Library
|
||||
This is an implementation of Hypertext Transfer Protocol version 2
|
||||
in C.
|
||||
|
||||
The framing layer of HTTP/2 is implemented as form of reusable C
|
||||
The framing layer of HTTP/2 is implemented as a form of reusable C
|
||||
library. On top of that, we have implemented HTTP/2 client, server
|
||||
and proxy. Also we have developed load test/benchmarking tool for
|
||||
and proxy. We have also developed load test and benchmarking tool for
|
||||
HTTP/2 and SPDY.
|
||||
|
||||
HPACK encoding and decoding are available as public API.
|
||||
HPACK encoder and decoder are available as public API.
|
||||
|
||||
The experimental high level C++ library is also available.
|
||||
|
||||
We have Python binding of this libary, but we have not covered
|
||||
everything yet.
|
||||
@@ -17,10 +19,12 @@ everything yet.
|
||||
Development Status
|
||||
------------------
|
||||
|
||||
We started to implement h2-13
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-13) and the
|
||||
header compression
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08).
|
||||
We started to implement h2-14
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), the header
|
||||
compression
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09)
|
||||
and HTTP Alternative Services
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-04).
|
||||
|
||||
The nghttp2 code base was forked from spdylay project.
|
||||
|
||||
@@ -30,32 +34,25 @@ HTTP/2 Features Support
|
||||
Core frames handling Yes
|
||||
Dependency Tree Yes
|
||||
Large header (CONTINUATION) Yes
|
||||
ALTSVC extension Yes \*1
|
||||
ALTSVC extension Yes
|
||||
=========================== =======
|
||||
|
||||
* \*1 As described in draft-12, but reserved byte was removed. ALTSVC
|
||||
may be removed from nghttp2 public API since it is not stabilized
|
||||
yet.
|
||||
|
||||
BLOCKED frame, which once existed in h2-12, was removed in h2-13.
|
||||
|
||||
Public Test Server
|
||||
------------------
|
||||
|
||||
The following endpoints are available to try out nghttp2
|
||||
implementation.
|
||||
|
||||
* https://nghttp2.org/ (TLS + NPN)
|
||||
* https://nghttp2.org/ (TLS + ALPN/NPN)
|
||||
|
||||
NPN offer ``h2-13``, ``spdy/3.1`` and ``http/1.1``.
|
||||
ALPN is currently disabled.
|
||||
NPN offer ``h2-14``, ``spdy/3.1`` and ``http/1.1``.
|
||||
|
||||
This endpoint requires TLSv1.2 and DHE or EDCHE with GCM cipher
|
||||
suite for HTTP/2 connection.
|
||||
|
||||
* http://nghttp2.org/ (Upgrade / Direct)
|
||||
|
||||
``h2c-13`` and ``http/1.1``. We configured this server to send
|
||||
``h2c-14`` and ``http/1.1``. We configured this server to send
|
||||
ALTSVC frame or Alt-Svc header field to announce that alternative
|
||||
service is available at port 443.
|
||||
|
||||
@@ -89,7 +86,7 @@ ALPN support requires unreleased version OpenSSL >= 1.0.2.
|
||||
To enable SPDY protocol in the application program ``nghttpx`` and
|
||||
``h2load``, the following package is required:
|
||||
|
||||
* spdylay >= 1.2.3
|
||||
* spdylay >= 1.3.0
|
||||
|
||||
To enable ``-a`` option (getting linked assets from the downloaded
|
||||
resource) in ``nghttp``, the following package is required:
|
||||
@@ -105,6 +102,11 @@ To mitigate heap fragmentation in long running server programs
|
||||
|
||||
* jemalloc
|
||||
|
||||
libnghttp2_asio C++ library requires the following packages:
|
||||
|
||||
* libboost-dev >= 1.54.0
|
||||
* libboost-thread-dev >= 1.54.0
|
||||
|
||||
The Python bindings require the following packages:
|
||||
|
||||
* cython >= 0.19
|
||||
@@ -113,6 +115,8 @@ The Python bindings require the following packages:
|
||||
If you are using Ubuntu 14.04 LTS, you need the following packages
|
||||
installed:
|
||||
|
||||
* make
|
||||
* binutils
|
||||
* autoconf
|
||||
* automake
|
||||
* autotools-dev
|
||||
@@ -186,10 +190,10 @@ output from ``nghttp`` client::
|
||||
|
||||
$ src/nghttp -nv https://nghttp2.org
|
||||
[ 0.033][NPN] server offers:
|
||||
* h2-13
|
||||
* h2-14
|
||||
* spdy/3.1
|
||||
* http/1.1
|
||||
The negotiated protocol: h2-13
|
||||
The negotiated protocol: h2-14
|
||||
[ 0.068] send SETTINGS frame <length=15, flags=0x00, stream_id=0>
|
||||
(niv=3)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
|
||||
@@ -258,7 +262,7 @@ The HTTP Upgrade is performed like this::
|
||||
GET / HTTP/1.1
|
||||
Host: nghttp2.org
|
||||
Connection: Upgrade, HTTP2-Settings
|
||||
Upgrade: h2c-13
|
||||
Upgrade: h2c-14
|
||||
HTTP2-Settings: AwAAAGQEAAD__wUAAAAB
|
||||
Accept: */*
|
||||
User-Agent: nghttp2/0.4.0-DEV
|
||||
@@ -267,7 +271,7 @@ The HTTP Upgrade is performed like this::
|
||||
[ 0.024] HTTP Upgrade response
|
||||
HTTP/1.1 101 Switching Protocols
|
||||
Connection: Upgrade
|
||||
Upgrade: h2c-13
|
||||
Upgrade: h2c-14
|
||||
|
||||
|
||||
[ 0.024] HTTP Upgrade success
|
||||
@@ -281,7 +285,7 @@ The HTTP Upgrade is performed like this::
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
|
||||
[ 0.024] recv ALTSVC frame <length=43, flags=0x00, stream_id=0>
|
||||
(max-age=86400, port=443, protocol_id=h2-13, host=nghttp2.org, origin=http://nghttp2.org)
|
||||
(max-age=86400, port=443, protocol_id=h2-14, host=nghttp2.org, origin=http://nghttp2.org)
|
||||
[ 0.024] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
; ACK
|
||||
(niv=0)
|
||||
@@ -389,7 +393,7 @@ information. Here is sample output from ``nghttpd`` server::
|
||||
nghttpx - proxy
|
||||
+++++++++++++++
|
||||
|
||||
``nghttpx`` is a multi-threaded reverse proxy for ``h2-13``, SPDY and
|
||||
``nghttpx`` is a multi-threaded reverse proxy for ``h2-14``, SPDY and
|
||||
HTTP/1.1 and powers nghttp2.org site. It has several operation modes:
|
||||
|
||||
================== ============================ ============== =============
|
||||
@@ -403,7 +407,7 @@ default mode HTTP/2, SPDY, HTTP/1.1 (TLS) HTTP/1.1 Reverse proxy
|
||||
================== ============================ ============== =============
|
||||
|
||||
The interesting mode at the moment is the default mode. It works like
|
||||
a reverse proxy and listens for ``h2-13``, SPDY and HTTP/1.1 and can
|
||||
a reverse proxy and listens for ``h2-14``, SPDY and HTTP/1.1 and can
|
||||
be deployed SSL/TLS terminator for existing web server.
|
||||
|
||||
The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
|
||||
@@ -966,6 +970,49 @@ associated value includes the state of dynamic header table after the
|
||||
corresponding header set was processed. The format is the same as
|
||||
``deflatehd``.
|
||||
|
||||
libnghttp2_asio: High level HTTP/2 C++ library
|
||||
----------------------------------------------
|
||||
|
||||
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
|
||||
high level abstraction API to build HTTP/2 applications. It depends
|
||||
on Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
|
||||
provides server side API.
|
||||
|
||||
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
|
||||
configure flag to build libnghttp2_asio. The required Boost libraries
|
||||
are:
|
||||
|
||||
* Boost::Asio
|
||||
* Boost::System
|
||||
* Boost::Thread
|
||||
|
||||
Server API is designed to build HTTP/2 server very easily to utilize
|
||||
C++11 anonymous function and closure. The bare minimum example of
|
||||
HTTP/2 server looks like this:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
http2 server;
|
||||
|
||||
server.listen
|
||||
("*", 3000,
|
||||
[](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
res->write_head(200);
|
||||
res->end("hello, world");
|
||||
});
|
||||
}
|
||||
|
||||
For more details, see the documentation of libnghttp2_asio.
|
||||
|
||||
Python bindings
|
||||
---------------
|
||||
|
||||
@@ -1081,3 +1128,25 @@ BaseRequestHandler usage:
|
||||
# give None to ssl to make the server non-SSL/TLS
|
||||
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
|
||||
server.serve_forever()
|
||||
|
||||
Contribution
|
||||
------------
|
||||
|
||||
[This text was composed based on 1.2. License section of curl/libcurl
|
||||
project.]
|
||||
|
||||
When contributing with code, you agree to put your changes and new
|
||||
code under the same license nghttp2 is already using unless stated and
|
||||
agreed otherwise.
|
||||
|
||||
When changing existing source code, you do not alter the copyright of
|
||||
the original file(s). The copyright will still be owned by the
|
||||
original creator(s) or those who have been assigned copyright by the
|
||||
original author(s).
|
||||
|
||||
By submitting a patch to the nghttp2 project, you are assumed to have
|
||||
the right to the code and to be allowed by your employer or whatever
|
||||
to hand over that patch/code to us. We will credit you for your
|
||||
changes as far as possible, to give credit but also to keep a trace
|
||||
back to who made what changes. Please always provide us with your
|
||||
full real name when contributing!
|
||||
|
||||
@@ -36,12 +36,10 @@ PATH=$TOOLCHAIN/bin:$PATH
|
||||
--host=arm-linux-androideabi \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--with-xml-prefix="$PREFIX" \
|
||||
--without-libxml2 \
|
||||
--disable-python-bindings \
|
||||
--disable-examples \
|
||||
--enable-werror \
|
||||
--disable-threads \
|
||||
CC=clang \
|
||||
CXX=clang++ \
|
||||
CPPFLAGS="-I$PREFIX/include" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||
LDFLAGS="-L$PREFIX/lib"
|
||||
|
||||
79
configure.ac
79
configure.ac
@@ -21,14 +21,14 @@ dnl LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
dnl OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
dnl WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([nghttp2], [0.5.1], [t-tujikawa@users.sourceforge.net])
|
||||
AC_INIT([nghttp2], [0.6.6], [t-tujikawa@users.sourceforge.net])
|
||||
LT_PREREQ([2.2.6])
|
||||
LT_INIT()
|
||||
dnl See versioning rule:
|
||||
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
AC_SUBST(LT_CURRENT, 4)
|
||||
AC_SUBST(LT_CURRENT, 7)
|
||||
AC_SUBST(LT_REVISION, 1)
|
||||
AC_SUBST(LT_AGE, 0)
|
||||
AC_SUBST(LT_AGE, 2)
|
||||
|
||||
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
|
||||
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
|
||||
@@ -76,6 +76,11 @@ AC_ARG_ENABLE([hpack-tools],
|
||||
[Build HPACK tools [default=check]])],
|
||||
[request_hpack_tools=$enableval], [request_hpack_tools=check])
|
||||
|
||||
AC_ARG_ENABLE([asio-lib],
|
||||
[AS_HELP_STRING([--enable-asio-lib],
|
||||
[Build C++ libnghttp2_asio library [default=no]])],
|
||||
[request_asio_lib=$enableval], [request_asio_lib=no])
|
||||
|
||||
AC_ARG_ENABLE([examples],
|
||||
[AS_HELP_STRING([--enable-examples],
|
||||
[Build examples [default=check]])],
|
||||
@@ -205,7 +210,8 @@ case "$host" in
|
||||
SRC_LIBS="$SRC_LIBS -lstdc++ -lsupc++"
|
||||
;;
|
||||
*)
|
||||
SRC_LIBS="$SRC_LIBS -pthread"
|
||||
PTHREAD_LDFLAGS="-pthread"
|
||||
SRC_LIBS="$SRC_LIBS $PTHREAD_LDFLAGS"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -293,7 +299,8 @@ AM_CONDITIONAL([HAVE_LIBXML2], [ test "x${have_libxml2}" = "xyes" ])
|
||||
have_jemalloc=no
|
||||
if test "x${request_jemalloc}" != "xno"; then
|
||||
LIBS_OLD=$LIBS
|
||||
AC_SEARCH_LIBS([malloc_stats_print], [jemalloc], [have_jemalloc=yes])
|
||||
AC_SEARCH_LIBS([malloc_stats_print], [jemalloc], [have_jemalloc=yes], [],
|
||||
[$PTHREAD_LDFLAGS])
|
||||
LIBS=$LIBS_OLD
|
||||
if test "x${have_jemalloc}" = "xyes" &&
|
||||
test "x${ac_cv_search_malloc_stats_print}" != "xnone required"; then
|
||||
@@ -310,7 +317,7 @@ fi
|
||||
# spdylay (for src/nghttpx and src/h2load)
|
||||
have_spdylay=no
|
||||
if test "x${request_spdylay}" != "xno"; then
|
||||
PKG_CHECK_MODULES([LIBSPDYLAY], [libspdylay >= 1.2.3],
|
||||
PKG_CHECK_MODULES([LIBSPDYLAY], [libspdylay >= 1.3.0],
|
||||
[have_spdylay=yes], [have_spdylay=no])
|
||||
if test "x${have_spdylay}" = "xyes"; then
|
||||
AC_DEFINE([HAVE_SPDYLAY], [1], [Define to 1 if you have `spdylay` library.])
|
||||
@@ -327,6 +334,25 @@ fi
|
||||
|
||||
AM_CONDITIONAL([HAVE_SPDYLAY], [ test "x${have_spdylay}" = "xyes" ])
|
||||
|
||||
# Check Boost Asio library
|
||||
have_asio_lib=no
|
||||
|
||||
if test "x${request_asio_lib}" = "xyes"; then
|
||||
AX_BOOST_BASE([1.54.0], [have_boost_base=yes], [have_boost_base=no])
|
||||
|
||||
if test "x${have_boost_base}" = "xyes"; then
|
||||
AX_BOOST_ASIO()
|
||||
AX_BOOST_SYSTEM()
|
||||
AX_BOOST_THREAD()
|
||||
|
||||
if test "x${ax_cv_boost_asio}" = "xyes" &&
|
||||
test "x${ax_cv_boost_system}" = "xyes" &&
|
||||
test "x${ax_cv_boost_thread}" = "xyes"; then
|
||||
have_asio_lib=yes
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL
|
||||
# and libevent_openssl
|
||||
enable_app=no
|
||||
@@ -343,7 +369,6 @@ if test "x${request_app}" = "xyes" &&
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_APP], [ test "x${enable_app}" = "xyes" ])
|
||||
AM_CONDITIONAL([ENABLE_H2LOAD], [ test "x${have_std_future}" = "xyes" ])
|
||||
|
||||
enable_hpack_tools=no
|
||||
# HPACK tools requires jansson
|
||||
@@ -359,6 +384,16 @@ fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_HPACK_TOOLS], [ test "x${enable_hpack_tools}" = "xyes" ])
|
||||
|
||||
# C++ library libnghttp2_asio
|
||||
|
||||
enable_asio_lib=no
|
||||
if test "x${request_asio_lib}" != "xno" &&
|
||||
test "x${have_asio_lib}" = "xyes"; then
|
||||
enable_asio_lib=yes
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_ASIO_LIB], [ test "x${enable_asio_lib}" = "xyes" ])
|
||||
|
||||
# The example programs depend on OpenSSL and libevent_openssl
|
||||
enable_examples=no
|
||||
if test "x${request_examples}" != "xno" &&
|
||||
@@ -435,12 +470,26 @@ if test "x$cross_compiling" != "xyes"; then
|
||||
AC_FUNC_MALLOC
|
||||
fi
|
||||
AC_CHECK_FUNCS([ \
|
||||
_Exit \
|
||||
getpwnam \
|
||||
memmove \
|
||||
memset \
|
||||
timegm \
|
||||
])
|
||||
|
||||
# timerfd_create was added in linux kernel 2.6.25
|
||||
|
||||
AC_CHECK_FUNC([timerfd_create],
|
||||
[have_timerfd_create=yes], [have_timerfd_create=no])
|
||||
|
||||
|
||||
# Checks for epoll availability, primarily for examples/tiny-nghttpd
|
||||
AX_HAVE_EPOLL([have_epoll=yes], [have_epoll=no])
|
||||
|
||||
AM_CONDITIONAL([ENABLE_TINY_NGHTTPD],
|
||||
[ test "x${have_epoll}" = "xyes" &&
|
||||
test "x${have_timerfd_create}" = "xyes"])
|
||||
|
||||
dnl Windows library for winsock2
|
||||
case "${host}" in
|
||||
*mingw*)
|
||||
@@ -485,7 +534,9 @@ if test "x$debug" != "xno"; then
|
||||
AC_DEFINE([DEBUGBUILD], [1], [Define to 1 to enable debug output.])
|
||||
fi
|
||||
|
||||
if test "x$threads" != "xyes"; then
|
||||
# Some platform does not have working std::future. We disable
|
||||
# threading for those platforms to exclude std::future use.
|
||||
if test "x$threads" != "xyes" || test "x$have_std_future" != "xyes"; then
|
||||
AC_DEFINE([NOTHREADS], [1], [Define to 1 if you want to disable threads.])
|
||||
fi
|
||||
|
||||
@@ -502,6 +553,8 @@ AC_CONFIG_FILES([
|
||||
tests/testdata/Makefile
|
||||
third-party/Makefile
|
||||
src/Makefile
|
||||
src/includes/Makefile
|
||||
src/libnghttp2_asio.pc
|
||||
examples/Makefile
|
||||
python/Makefile
|
||||
python/setup.py
|
||||
@@ -514,9 +567,13 @@ AC_CONFIG_FILES([
|
||||
doc/tutorial-hpack.rst
|
||||
doc/nghttpx-howto.rst
|
||||
doc/h2load-howto.rst
|
||||
doc/libnghttp2_asio.rst
|
||||
doc/python-apiref.rst
|
||||
doc/building-android-binary.rst
|
||||
doc/nghttp2.h.rst
|
||||
doc/nghttp2ver.h.rst
|
||||
doc/asio_http2.h.rst
|
||||
contrib/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -549,8 +606,14 @@ AC_MSG_NOTICE([summary of build options:
|
||||
Spdylay: ${have_spdylay}
|
||||
Jansson: ${have_jansson}
|
||||
Jemalloc: ${have_jemalloc}
|
||||
Boost CPPFLAGS: ${BOOST_CPPFLAGS}
|
||||
Boost LDFLAGS: ${BOOST_LDFLAGS}
|
||||
Boost::ASIO: ${BOOST_ASIO_LIB}
|
||||
Boost::System: ${BOOST_SYSTEM_LIB}
|
||||
Boost::Thread: ${BOOST_THREAD_LIB}
|
||||
Applications: ${enable_app}
|
||||
HPACK tools: ${enable_hpack_tools}
|
||||
Libnghttp2_asio:${enable_asio_lib}
|
||||
Examples: ${enable_examples}
|
||||
Python bindings:${enable_python_bindings}
|
||||
Failmalloc: ${request_failmalloc}
|
||||
|
||||
39
contrib/Makefile.am
Normal file
39
contrib/Makefile.am
Normal 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
173
contrib/nghttpx-init.in
Normal 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
18
contrib/nghttpx-logrotate
Normal 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
|
||||
}
|
||||
@@ -37,7 +37,9 @@ EXTRA_DIST = \
|
||||
sources/tutorial-hpack.rst \
|
||||
sources/nghttpx-howto.rst \
|
||||
sources/h2load-howto.rst \
|
||||
sources/libnghttp2_asio.rst \
|
||||
sources/python-apiref.rst \
|
||||
sources/building-android-binary.rst \
|
||||
_themes/sphinx_rtd_theme/footer.html \
|
||||
_themes/sphinx_rtd_theme/theme.conf \
|
||||
_themes/sphinx_rtd_theme/layout_old.html \
|
||||
|
||||
8
doc/_themes/sphinx_rtd_theme/layout.html
vendored
8
doc/_themes/sphinx_rtd_theme/layout.html
vendored
@@ -23,7 +23,7 @@
|
||||
{% endif %}
|
||||
|
||||
{# CSS #}
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
|
||||
{# OPENSEARCH #}
|
||||
{% if not embedded %}
|
||||
@@ -82,7 +82,9 @@
|
||||
{# SIDE NAV, TOGGLES ON MOBILE #}
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||
<div class="wy-side-nav-search">
|
||||
<a href="{{ pathto(master_doc) }}" class="fa fa-home"> {{ project }}</a>
|
||||
{% block sidebartitle %}
|
||||
<a href="{{ pathto(master_doc) }}" class="fa fa-home"> {{ project }}</a>
|
||||
{% endblock %}
|
||||
{% include "searchbox.html" %}
|
||||
</div>
|
||||
|
||||
@@ -111,7 +113,7 @@
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
{% include "breadcrumbs.html" %}
|
||||
<div role="main">
|
||||
<div role="main" class="document">
|
||||
{% block body %}{% endblock %}
|
||||
</div>
|
||||
{% include "footer.html" %}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:"\f02d"}.icon-book:before{content:"\f02d"}.fa-caret-down:before{content:"\f0d7"}.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}
|
||||
.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}
|
||||
/*# sourceMappingURL=badge_only.css.map */
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -26,6 +26,8 @@ do not send client connection preface
|
||||
responsible to send it before sending any HTTP/2 frames using these
|
||||
functions if :type:`nghttp2_session` is configured as client.
|
||||
Similarly, `nghttp2_session_recv()` and `nghttp2_session_mem_recv()`
|
||||
do not consume client connection preface. The applications are
|
||||
responsible to receive it before calling these functions if
|
||||
:type:`nghttp2_session` is configured as server.
|
||||
do not consume client connection preface unless
|
||||
`nghttp2_option_set_recv_client_preface()` is used with nonzero option
|
||||
value. The applications are responsible to receive it before calling
|
||||
these functions if :type:`nghttp2_session` is configured as server and
|
||||
`nghttp2_option_set_recv_client_preface()` is not used.
|
||||
|
||||
4
doc/asio_http2.h.rst.in
Normal file
4
doc/asio_http2.h.rst.in
Normal file
@@ -0,0 +1,4 @@
|
||||
asio_http2.h
|
||||
============
|
||||
|
||||
.. literalinclude:: @top_srcdir@/src/includes/nghttp2/asio_http2.h
|
||||
1
doc/building-android-binary.rst.in
Normal file
1
doc/building-android-binary.rst.in
Normal file
@@ -0,0 +1 @@
|
||||
.. include:: @top_srcdir@/doc/sources/building-android-binary.rst
|
||||
@@ -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 = {
|
||||
|
||||
24
doc/h2load.1
24
doc/h2load.1
@@ -1,10 +1,10 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.45.1.
|
||||
.TH H2LOAD "1" "July 2014" "h2load nghttp2/0.5.1" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
|
||||
.TH H2LOAD "1" "November 2014" "h2load nghttp2/0.6.6" "User Commands"
|
||||
.SH NAME
|
||||
h2load \- HTTP/2 benchmarking tool
|
||||
.SH SYNOPSIS
|
||||
.B h2load
|
||||
[\fI\,OPTIONS\/\fR]... \fI\,<URI>\/\fR...
|
||||
[\fI\,OPTIONS\/\fR]... [\fI\,URI\/\fR]...
|
||||
.SH DESCRIPTION
|
||||
benchmarking tool for HTTP/2 and SPDY server
|
||||
.TP
|
||||
@@ -26,6 +26,17 @@ Number of concurrent clients. Default: 1
|
||||
\fB\-t\fR, \fB\-\-threads=\fR<N>
|
||||
Number of native threads. Default: 1
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-input\-file=\fR<FILE>
|
||||
Path of a file with multiple URIs are seperated
|
||||
by EOLs. This option will disable URIs getting
|
||||
from command\-line. If '\-' is given as <FILE>,
|
||||
URIs will be read from stdin. URIs are used in
|
||||
this order for each client. All URIs are used,
|
||||
then first URI is used and then 2nd URI, and so
|
||||
on. The scheme, host and port in the subsequent
|
||||
URIs, if present, are ignored. Those in the
|
||||
first URI are used solely.
|
||||
.TP
|
||||
\fB\-m\fR, \fB\-\-max\-concurrent\-streams=\fR(auto|<N>)
|
||||
Max concurrent streams to issue per session. If
|
||||
"auto" is given, the number of given URIs is
|
||||
@@ -41,12 +52,15 @@ Sets the connection level initial window size to
|
||||
than 16, this option is ignored. Otherwise
|
||||
2**<N> is used for SPDY.
|
||||
.TP
|
||||
\fB\-H\fR, \fB\-\-header=\fR<HEADER>
|
||||
Add/Override a header to the requests.
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-no\-tls\-proto=\fR<PROTOID>
|
||||
Specify ALPN identifier of the protocol to be
|
||||
used when accessing http URI without SSL/TLS.
|
||||
Available protocols: spdy/2, spdy/3, spdy/3.1 and
|
||||
h2c\-13
|
||||
Default: h2c\-13
|
||||
h2c\-14
|
||||
Default: h2c\-14
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Output debug information.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
|
||||
|
||||
.. program:: h2load
|
||||
|
||||
h2load(1)
|
||||
@@ -9,7 +11,7 @@ h2load - HTTP/2 benchmarking tool
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
**h2load** [OPTIONS]... <URI>...
|
||||
**h2load** [OPTIONS]... [URI]...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -42,6 +44,19 @@ OPTIONS
|
||||
|
||||
Number of native threads. Default: 1
|
||||
|
||||
.. option:: -i, --input-file=<FILE>
|
||||
|
||||
|
||||
Path of a file with multiple URIs are seperated
|
||||
by EOLs. This option will disable URIs getting
|
||||
from command-line. If '-' is given as <FILE>,
|
||||
URIs will be read from stdin. URIs are used in
|
||||
this order for each client. All URIs are used,
|
||||
then first URI is used and then 2nd URI, and so
|
||||
on. The scheme, host and port in the subsequent
|
||||
URIs, if present, are ignored. Those in the
|
||||
first URI are used solely.
|
||||
|
||||
.. option:: -m, --max-concurrent-streams=(auto|<N>)
|
||||
|
||||
|
||||
@@ -63,14 +78,19 @@ OPTIONS
|
||||
than 16, this option is ignored. Otherwise
|
||||
2\*\*<N> is used for SPDY.
|
||||
|
||||
.. option:: -H, --header=<HEADER>
|
||||
|
||||
|
||||
Add/Override a header to the requests.
|
||||
|
||||
.. option:: -p, --no-tls-proto=<PROTOID>
|
||||
|
||||
|
||||
Specify ALPN identifier of the protocol to be
|
||||
used when accessing http URI without SSL/TLS.
|
||||
Available protocols: spdy/2, spdy/3, spdy/3.1 and
|
||||
h2c-13
|
||||
Default: h2c-13
|
||||
h2c-14
|
||||
Default: h2c-14
|
||||
|
||||
.. option:: -v, --verbose
|
||||
|
||||
|
||||
1
doc/libnghttp2_asio.rst.in
Normal file
1
doc/libnghttp2_asio.rst.in
Normal file
@@ -0,0 +1 @@
|
||||
.. include:: @top_srcdir@/doc/sources/libnghttp2_asio.rst
|
||||
19
doc/nghttp.1
19
doc/nghttp.1
@@ -1,5 +1,5 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.45.1.
|
||||
.TH NGHTTP "1" "July 2014" "nghttp nghttp2/0.5.1" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
|
||||
.TH NGHTTP "1" "November 2014" "nghttp nghttp2/0.6.6" "User Commands"
|
||||
.SH NAME
|
||||
nghttp \- HTTP/2 experimental client
|
||||
.SH SYNOPSIS
|
||||
@@ -14,7 +14,9 @@ Specify URI to access.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Print debug information such as reception and
|
||||
transmission of frames and name/value pairs.
|
||||
transmission of frames and name/value pairs.
|
||||
Specifying this option multiple times increases
|
||||
verbosity.
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-null\-out\fR
|
||||
Discard downloaded data.
|
||||
@@ -40,13 +42,18 @@ Sets the connection level initial window size to
|
||||
Download assets such as stylesheets, images and
|
||||
script files linked from the downloaded resource.
|
||||
Only links whose origins are the same with the
|
||||
linking resource will be downloaded.
|
||||
linking resource will be downloaded. nghttp
|
||||
prioritizes resources using HTTP/2 dependency
|
||||
based priority. The priority order, from highest
|
||||
to lowest, is html itself, css, javascript and
|
||||
images.
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-stat\fR
|
||||
Print statistics.
|
||||
.TP
|
||||
\fB\-H\fR, \fB\-\-header\fR
|
||||
Add a header to the requests.
|
||||
\fB\-H\fR, \fB\-\-header=\fR<HEADER>
|
||||
Add a header to the requests. Example:
|
||||
\fB\-H\fR':method: PUT'
|
||||
.TP
|
||||
\fB\-\-cert=\fR<CERT>
|
||||
Use the specified client certificate file. The
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
|
||||
|
||||
.. program:: nghttp
|
||||
|
||||
nghttp(1)
|
||||
@@ -26,7 +28,9 @@ OPTIONS
|
||||
|
||||
|
||||
Print debug information such as reception and
|
||||
transmission of frames and name/value pairs.
|
||||
transmission of frames and name/value pairs.
|
||||
Specifying this option multiple times increases
|
||||
verbosity.
|
||||
|
||||
.. option:: -n, --null-out
|
||||
|
||||
@@ -38,7 +42,7 @@ OPTIONS
|
||||
|
||||
Save download data in the current directory. The
|
||||
filename is dereived from URI. If URI ends with
|
||||
\&'/', 'index.html' is used as a filename. Not
|
||||
'/', 'index.html' is used as a filename. Not
|
||||
implemented yet.
|
||||
|
||||
.. option:: -t, --timeout=<N>
|
||||
@@ -64,17 +68,22 @@ OPTIONS
|
||||
Download assets such as stylesheets, images and
|
||||
script files linked from the downloaded resource.
|
||||
Only links whose origins are the same with the
|
||||
linking resource will be downloaded.
|
||||
linking resource will be downloaded. nghttp
|
||||
prioritizes resources using HTTP/2 dependency
|
||||
based priority. The priority order, from highest
|
||||
to lowest, is html itself, css, javascript and
|
||||
images.
|
||||
|
||||
.. option:: -s, --stat
|
||||
|
||||
|
||||
Print statistics.
|
||||
|
||||
.. option:: -H, --header
|
||||
.. option:: -H, --header=<HEADER>
|
||||
|
||||
|
||||
Add a header to the requests.
|
||||
Add a header to the requests. Example:
|
||||
-H':method: PUT'
|
||||
|
||||
.. option:: --cert=<CERT>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.45.1.
|
||||
.TH NGHTTPD "1" "July 2014" "nghttpd nghttp2/0.5.1" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
|
||||
.TH NGHTTPD "1" "November 2014" "nghttpd nghttp2/0.6.6" "User Commands"
|
||||
.SH NAME
|
||||
nghttpd \- HTTP/2 experimental server
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
|
||||
|
||||
.. program:: nghttpd
|
||||
|
||||
nghttpd(1)
|
||||
|
||||
113
doc/nghttpx.1
113
doc/nghttpx.1
@@ -1,5 +1,5 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.45.1.
|
||||
.TH NGHTTPX "1" "July 2014" "nghttpx nghttp2/0.5.1" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
|
||||
.TH NGHTTPX "1" "November 2014" "nghttpx nghttp2/0.6.6" "User Commands"
|
||||
.SH NAME
|
||||
nghttpx \- HTTP/2 experimental proxy
|
||||
.SH SYNOPSIS
|
||||
@@ -42,12 +42,54 @@ Resolve backend hostname to IPv4 address only.
|
||||
.TP
|
||||
\fB\-\-backend\-ipv6\fR
|
||||
Resolve backend hostname to IPv6 address only.
|
||||
.TP
|
||||
\fB\-\-backend\-http\-proxy\-uri=\fR<URI>
|
||||
Specify proxy URI in the form
|
||||
http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a
|
||||
proxy requires authentication, specify <USER> and
|
||||
<PASS>. Note that they must be properly
|
||||
percent\-encoded. This proxy is used when the
|
||||
backend connection is HTTP/2. First, make a
|
||||
CONNECT request to the proxy and it connects to
|
||||
the backend on behalf of nghttpx. This forms
|
||||
tunnel. After that, nghttpx performs SSL/TLS
|
||||
handshake with the downstream through the tunnel.
|
||||
The timeouts when connecting and making CONNECT
|
||||
request can be specified by
|
||||
\fB\-\-backend\-read\-timeout\fR and
|
||||
\fB\-\-backend\-write\-timeout\fR options.
|
||||
.SS "Performance:"
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-workers=\fR<CORES>
|
||||
Set the number of worker threads.
|
||||
Default: 1
|
||||
.TP
|
||||
\fB\-\-read\-rate=\fR<RATE>
|
||||
Set maximum average read rate on frontend
|
||||
connection. Setting 0 to this option means read
|
||||
rate is unlimited.
|
||||
Default: 0
|
||||
.TP
|
||||
\fB\-\-read\-burst=\fR<SIZE>
|
||||
Set maximum read burst size on frontend
|
||||
connection. Setting 0 does not work, but it is
|
||||
not a problem because \fB\-\-read\-rate\fR=\fI\,0\/\fR will give
|
||||
unlimited read rate regardless of this option
|
||||
value.
|
||||
Default: 1073741824
|
||||
.TP
|
||||
\fB\-\-write\-rate=\fR<RATE>
|
||||
Set maximum average write rate on frontend
|
||||
connection. Setting 0 to this option means write
|
||||
rate is unlimited.
|
||||
Default: 0
|
||||
.TP
|
||||
\fB\-\-write\-burst=\fR<SIZE>
|
||||
Set maximum write burst size on frontend
|
||||
connection. Setting 0 to this option means write
|
||||
burst size is unlimited.
|
||||
Default: 0
|
||||
.TP
|
||||
\fB\-\-worker\-read\-rate=\fR<RATE>
|
||||
Set maximum average read rate on frontend
|
||||
connection per worker. Setting 0 to this option
|
||||
@@ -76,6 +118,13 @@ Default: 0
|
||||
Set maximum number of simultaneous connections
|
||||
frontend accepts. Setting 0 means unlimited.
|
||||
Default: 0
|
||||
.TP
|
||||
\fB\-\-backend\-connections\-per\-frontend=\fR<NUM>
|
||||
Set maximum number of backend simultaneous
|
||||
connections per frontend. This option is
|
||||
meaningful when the combination of HTTP/2 or SPDY
|
||||
frontend and HTTP/1 backend is used.
|
||||
Default: 100
|
||||
.SS "Timeout:"
|
||||
.TP
|
||||
\fB\-\-frontend\-http2\-read\-timeout=\fR<SEC>
|
||||
@@ -86,41 +135,41 @@ Default: 180
|
||||
\fB\-\-frontend\-read\-timeout=\fR<SEC>
|
||||
Specify read timeout for HTTP/1.1 frontend
|
||||
connection.
|
||||
Default: 180
|
||||
Default: 30
|
||||
.TP
|
||||
\fB\-\-frontend\-write\-timeout=\fR<SEC>
|
||||
Specify write timeout for all frontend
|
||||
connections.
|
||||
Default: 60
|
||||
Default: 30
|
||||
.TP
|
||||
\fB\-\-stream\-read\-timeout=\fR<SEC>
|
||||
Specify read timeout for HTTP/2 and SPDY streams.
|
||||
0 means no timeout.
|
||||
Default: 0
|
||||
.TP
|
||||
\fB\-\-stream\-write\-timeout=\fR<SEC>
|
||||
Specify write timeout for HTTP/2 and SPDY
|
||||
streams. 0 means no timeout.
|
||||
Default: 0
|
||||
.TP
|
||||
\fB\-\-backend\-read\-timeout=\fR<SEC>
|
||||
Specify read timeout for backend connection.
|
||||
Default: 900
|
||||
Default: 30
|
||||
.TP
|
||||
\fB\-\-backend\-write\-timeout=\fR<SEC>
|
||||
Specify write timeout for backend connection.
|
||||
Default: 60
|
||||
Default: 30
|
||||
.TP
|
||||
\fB\-\-backend\-keep\-alive\-timeout=\fR<SEC>
|
||||
Specify keep\-alive timeout for backend
|
||||
connection.
|
||||
Default: 60
|
||||
.TP
|
||||
\fB\-\-backend\-http\-proxy\-uri=\fR<URI>
|
||||
Specify proxy URI in the form
|
||||
http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a
|
||||
proxy requires authentication, specify <USER> and
|
||||
<PASS>. Note that they must be properly
|
||||
percent\-encoded. This proxy is used when the
|
||||
backend connection is HTTP/2. First, make a
|
||||
CONNECT request to the proxy and it connects to
|
||||
the backend on behalf of nghttpx. This forms
|
||||
tunnel. After that, nghttpx performs SSL/TLS
|
||||
handshake with the downstream through the tunnel.
|
||||
The timeouts when connecting and making CONNECT
|
||||
request can be specified by
|
||||
\fB\-\-backend\-read\-timeout\fR and
|
||||
\fB\-\-backend\-write\-timeout\fR options.
|
||||
\fB\-\-listener\-disable\-timeout=\fR<SEC>
|
||||
After accepting connection failed, connection
|
||||
listener is disabled for a given time in seconds.
|
||||
Specifying 0 disables this feature.
|
||||
Default: 0
|
||||
.SS "SSL/TLS:"
|
||||
.TP
|
||||
\fB\-\-ciphers=\fR<SUITE>
|
||||
@@ -171,7 +220,7 @@ most desirable protocol comes first. This is
|
||||
used in both ALPN and NPN. The parameter must be
|
||||
delimited by a single comma only and any white
|
||||
spaces are treated as a part of protocol string.
|
||||
Default: h2\-13,spdy/3.1,spdy/3,spdy/2,http/1.1
|
||||
Default: h2\-14,spdy/3.1,spdy/3,spdy/2,http/1.1
|
||||
.TP
|
||||
\fB\-\-verify\-client\fR
|
||||
Require and verify client certificate.
|
||||
@@ -193,8 +242,8 @@ used in backend client authentication.
|
||||
\fB\-\-tls\-proto\-list=\fR<LIST>
|
||||
Comma delimited list of SSL/TLS protocol to be
|
||||
enabled. The following protocols are available:
|
||||
TLSv1.2, TLSv1.1, TLSv1.0 and SSLv3. The name
|
||||
matching is done in case\-insensitive manner. The
|
||||
TLSv1.2, TLSv1.1 and TLSv1.0. The name matching
|
||||
is done in case\-insensitive manner. The
|
||||
parameter must be delimited by a single comma
|
||||
only and any white spaces are treated as a part
|
||||
of protocol string.
|
||||
@@ -279,8 +328,9 @@ URI, suitable for use as a forward proxy.
|
||||
.TP
|
||||
\fB\-L\fR, \fB\-\-log\-level=\fR<LEVEL>
|
||||
Set the severity level of log output. <LEVEL>
|
||||
must be one of INFO, WARNING, ERROR and FATAL.
|
||||
Default: WARNING
|
||||
must be one of INFO, NOTICE, WARN, ERROR and
|
||||
FATAL.
|
||||
Default: NOTICE
|
||||
.TP
|
||||
\fB\-\-accesslog\-file=\fR<PATH>
|
||||
Set path to write access log. To reopen file,
|
||||
@@ -308,10 +358,21 @@ Default: daemon
|
||||
Append X\-Forwarded\-For header field to the
|
||||
downstream request.
|
||||
.TP
|
||||
\fB\-\-strip\-incoming\-x\-forwarded\-for\fR
|
||||
Strip X\-Forwarded\-For header field from inbound
|
||||
client requests.
|
||||
.TP
|
||||
\fB\-\-no\-via\fR
|
||||
Don't append to Via header field. If Via header
|
||||
field is received, it is left unaltered.
|
||||
.TP
|
||||
\fB\-\-no\-location\-rewrite\fR
|
||||
Don't rewrite location header field on
|
||||
\fB\-\-http2\-bridge\fR, \fB\-\-client\fR and default mode. For
|
||||
\fB\-\-http2\-proxy\fR and \fB\-\-client\-proxy\fR mode, location
|
||||
header field will not be altered regardless of
|
||||
this option.
|
||||
.TP
|
||||
\fB\-\-altsvc=\fR<PROTOID,PORT[,HOST,[ORIGIN]]>
|
||||
Specify protocol ID, port, host and origin of
|
||||
alternative service. <HOST> and <ORIGIN> are
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
.. DO NOT MODIFY THIS FILE! It was generated by man2rst.py
|
||||
|
||||
.. program:: nghttpx
|
||||
|
||||
nghttpx(1)
|
||||
@@ -66,6 +68,24 @@ Connections
|
||||
|
||||
Resolve backend hostname to IPv6 address only.
|
||||
|
||||
.. option:: --backend-http-proxy-uri=<URI>
|
||||
|
||||
|
||||
Specify proxy URI in the form
|
||||
http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a
|
||||
proxy requires authentication, specify <USER> and
|
||||
<PASS>. Note that they must be properly
|
||||
percent-encoded. This proxy is used when the
|
||||
backend connection is HTTP/2. First, make a
|
||||
CONNECT request to the proxy and it connects to
|
||||
the backend on behalf of nghttpx. This forms
|
||||
tunnel. After that, nghttpx performs SSL/TLS
|
||||
handshake with the downstream through the tunnel.
|
||||
The timeouts when connecting and making CONNECT
|
||||
request can be specified by
|
||||
:option:`--backend-read-timeout` and
|
||||
:option:`--backend-write-timeout` options.
|
||||
|
||||
Performance
|
||||
^^^^^^^^^^^
|
||||
|
||||
@@ -75,6 +95,40 @@ Performance
|
||||
Set the number of worker threads.
|
||||
Default: 1
|
||||
|
||||
.. option:: --read-rate=<RATE>
|
||||
|
||||
|
||||
Set maximum average read rate on frontend
|
||||
connection. Setting 0 to this option means read
|
||||
rate is unlimited.
|
||||
Default: 0
|
||||
|
||||
.. option:: --read-burst=<SIZE>
|
||||
|
||||
|
||||
Set maximum read burst size on frontend
|
||||
connection. Setting 0 does not work, but it is
|
||||
not a problem because --read-rate=0 will give
|
||||
unlimited read rate regardless of this option
|
||||
value.
|
||||
Default: 1073741824
|
||||
|
||||
.. option:: --write-rate=<RATE>
|
||||
|
||||
|
||||
Set maximum average write rate on frontend
|
||||
connection. Setting 0 to this option means write
|
||||
rate is unlimited.
|
||||
Default: 0
|
||||
|
||||
.. option:: --write-burst=<SIZE>
|
||||
|
||||
|
||||
Set maximum write burst size on frontend
|
||||
connection. Setting 0 to this option means write
|
||||
burst size is unlimited.
|
||||
Default: 0
|
||||
|
||||
.. option:: --worker-read-rate=<RATE>
|
||||
|
||||
|
||||
@@ -114,6 +168,15 @@ Performance
|
||||
frontend accepts. Setting 0 means unlimited.
|
||||
Default: 0
|
||||
|
||||
.. option:: --backend-connections-per-frontend=<NUM>
|
||||
|
||||
|
||||
Set maximum number of backend simultaneous
|
||||
connections per frontend. This option is
|
||||
meaningful when the combination of HTTP/2 or SPDY
|
||||
frontend and HTTP/1 backend is used.
|
||||
Default: 100
|
||||
|
||||
Timeout
|
||||
^^^^^^^
|
||||
|
||||
@@ -129,26 +192,40 @@ Timeout
|
||||
|
||||
Specify read timeout for HTTP/1.1 frontend
|
||||
connection.
|
||||
Default: 180
|
||||
Default: 30
|
||||
|
||||
.. option:: --frontend-write-timeout=<SEC>
|
||||
|
||||
|
||||
Specify write timeout for all frontend
|
||||
connections.
|
||||
Default: 60
|
||||
Default: 30
|
||||
|
||||
.. option:: --stream-read-timeout=<SEC>
|
||||
|
||||
|
||||
Specify read timeout for HTTP/2 and SPDY streams.
|
||||
0 means no timeout.
|
||||
Default: 0
|
||||
|
||||
.. option:: --stream-write-timeout=<SEC>
|
||||
|
||||
|
||||
Specify write timeout for HTTP/2 and SPDY
|
||||
streams. 0 means no timeout.
|
||||
Default: 0
|
||||
|
||||
.. option:: --backend-read-timeout=<SEC>
|
||||
|
||||
|
||||
Specify read timeout for backend connection.
|
||||
Default: 900
|
||||
Default: 30
|
||||
|
||||
.. option:: --backend-write-timeout=<SEC>
|
||||
|
||||
|
||||
Specify write timeout for backend connection.
|
||||
Default: 60
|
||||
Default: 30
|
||||
|
||||
.. option:: --backend-keep-alive-timeout=<SEC>
|
||||
|
||||
@@ -157,23 +234,13 @@ Timeout
|
||||
connection.
|
||||
Default: 60
|
||||
|
||||
.. option:: --backend-http-proxy-uri=<URI>
|
||||
.. option:: --listener-disable-timeout=<SEC>
|
||||
|
||||
|
||||
Specify proxy URI in the form
|
||||
http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a
|
||||
proxy requires authentication, specify <USER> and
|
||||
<PASS>. Note that they must be properly
|
||||
percent-encoded. This proxy is used when the
|
||||
backend connection is HTTP/2. First, make a
|
||||
CONNECT request to the proxy and it connects to
|
||||
the backend on behalf of nghttpx. This forms
|
||||
tunnel. After that, nghttpx performs SSL/TLS
|
||||
handshake with the downstream through the tunnel.
|
||||
The timeouts when connecting and making CONNECT
|
||||
request can be specified by
|
||||
:option:`--backend-read-timeout` and
|
||||
:option:`--backend-write-timeout` options.
|
||||
After accepting connection failed, connection
|
||||
listener is disabled for a given time in seconds.
|
||||
Specifying 0 disables this feature.
|
||||
Default: 0
|
||||
|
||||
SSL/TLS
|
||||
^^^^^^^
|
||||
@@ -242,7 +309,7 @@ SSL/TLS
|
||||
used in both ALPN and NPN. The parameter must be
|
||||
delimited by a single comma only and any white
|
||||
spaces are treated as a part of protocol string.
|
||||
Default: h2-13,spdy/3.1,spdy/3,spdy/2,http/1.1
|
||||
Default: h2-14,spdy/3.1,spdy/3,spdy/2,http/1.1
|
||||
|
||||
.. option:: --verify-client
|
||||
|
||||
@@ -274,8 +341,8 @@ SSL/TLS
|
||||
|
||||
Comma delimited list of SSL/TLS protocol to be
|
||||
enabled. The following protocols are available:
|
||||
TLSv1.2, TLSv1.1, TLSv1.0 and SSLv3. The name
|
||||
matching is done in case-insensitive manner. The
|
||||
TLSv1.2, TLSv1.1 and TLSv1.0. The name matching
|
||||
is done in case-insensitive manner. The
|
||||
parameter must be delimited by a single comma
|
||||
only and any white spaces are treated as a part
|
||||
of protocol string.
|
||||
@@ -395,8 +462,9 @@ Logging
|
||||
|
||||
|
||||
Set the severity level of log output. <LEVEL>
|
||||
must be one of INFO, WARNING, ERROR and FATAL.
|
||||
Default: WARNING
|
||||
must be one of INFO, NOTICE, WARN, ERROR and
|
||||
FATAL.
|
||||
Default: NOTICE
|
||||
|
||||
.. option:: --accesslog-file=<PATH>
|
||||
|
||||
@@ -438,12 +506,27 @@ Misc
|
||||
Append X-Forwarded-For header field to the
|
||||
downstream request.
|
||||
|
||||
.. option:: --strip-incoming-x-forwarded-for
|
||||
|
||||
|
||||
Strip X-Forwarded-For header field from inbound
|
||||
client requests.
|
||||
|
||||
.. option:: --no-via
|
||||
|
||||
|
||||
Don't append to Via header field. If Via header
|
||||
field is received, it is left unaltered.
|
||||
|
||||
.. option:: --no-location-rewrite
|
||||
|
||||
|
||||
Don't rewrite location header field on
|
||||
:option:`--http2-bridge`, :option:`--client` and default mode. For
|
||||
:option:`--http2-proxy` and :option:`--client-proxy` mode, location
|
||||
header field will not be altered regardless of
|
||||
this option.
|
||||
|
||||
.. option:: --altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
|
||||
|
||||
|
||||
|
||||
124
doc/sources/building-android-binary.rst
Normal file
124
doc/sources/building-android-binary.rst
Normal file
@@ -0,0 +1,124 @@
|
||||
Building Android binary
|
||||
=======================
|
||||
|
||||
In this article, we briefly describe how to build Android binary using
|
||||
`Android NDK <http://developer.android.com/tools/sdk/ndk/index.html>`_
|
||||
cross-compiler on Debian Linux.
|
||||
|
||||
The easiest way to build android binary is use Dockerfile.android.
|
||||
See Dockerfile.android for more details. If you cannot use
|
||||
Dockerfile.android for whatever reason, continue to read the rest of
|
||||
this article.
|
||||
|
||||
We offer ``android-config`` and ``android-make`` scripts to make the
|
||||
build easier. To make these script work, NDK toolchain must be
|
||||
installed in the following way. First, let us introduce
|
||||
``ANDROID_HOME`` environment variable. We need to install toolchain
|
||||
under ``$ANDROID_HOME/toolchain``. An user can freely choose the path
|
||||
for ``ANDROID_HOME``. For example, to install toolchain under
|
||||
``$ANDROID_HOME/toolchain``, do this in the the directory where NDK is
|
||||
unpacked::
|
||||
|
||||
$ build/tools/make-standalone-toolchain.sh \
|
||||
--install-dir=$ANDROID_HOME/toolchain \
|
||||
--toolchain=arm-linux-androideabi-4.8
|
||||
|
||||
The additional flag ``--system=linux-x86_64`` may be required if you
|
||||
are using x86_64 system.
|
||||
|
||||
The platform level is not important here because we don't use Android
|
||||
specific C/C++ API.
|
||||
|
||||
The dependent libraries, such as OpenSSL and libevent should be built
|
||||
with the toolchain and installed under ``$ANDROID_HOME/usr/local``.
|
||||
We recommend to build these libraries as static library to make the
|
||||
deployment easier. libxml2 support is currently disabled.
|
||||
|
||||
We use zlib which comes with Android NDK, so we don't have to build it
|
||||
by ourselves.
|
||||
|
||||
If SPDY support is required for nghttpx and h2load, build and install
|
||||
spdylay as well.
|
||||
|
||||
Before running ``android-config`` and ``android-make``,
|
||||
``ANDROID_HOME`` environment variable must be set to point to the
|
||||
correct path. Also add ``$ANDROID_HOME/toolchain/bin`` to ``PATH``::
|
||||
|
||||
$ export PATH=$PATH:$ANDROID_HOME/toolchain/bin
|
||||
|
||||
To configure OpenSSL, use the following script::
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
echo 'No $ANDROID_HOME specified.'
|
||||
exit 1
|
||||
fi
|
||||
PREFIX=$ANDROID_HOME/usr/local
|
||||
TOOLCHAIN=$ANDROID_HOME/toolchain
|
||||
PATH=$TOOLCHAIN/bin:$PATH
|
||||
|
||||
export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi-
|
||||
./Configure --prefix=$PREFIX android
|
||||
|
||||
And run ``make install`` to build and install.
|
||||
|
||||
To configure libevent, use the following script::
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
echo 'No $ANDROID_HOME specified.'
|
||||
exit 1
|
||||
fi
|
||||
PREFIX=$ANDROID_HOME/usr/local
|
||||
TOOLCHAIN=$ANDROID_HOME/toolchain
|
||||
PATH=$TOOLCHAIN/bin:$PATH
|
||||
|
||||
./configure \
|
||||
--host=arm-linux-androideabi \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
CPPFLAGS=-I$PREFIX/include \
|
||||
LDFLAGS=-L$PREFIX/lib
|
||||
|
||||
And run ``make install`` to build and install.
|
||||
|
||||
To configure spdylay, use the following script::
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
echo 'No $ANDROID_HOME specified.'
|
||||
exit 1
|
||||
fi
|
||||
PREFIX=$ANDROID_HOME/usr/local
|
||||
TOOLCHAIN=$ANDROID_HOME/toolchain
|
||||
PATH=$TOOLCHAIN/bin:$PATH
|
||||
|
||||
./configure \
|
||||
--disable-shared \
|
||||
--host=arm-linux-androideabi \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
--without-libxml2 \
|
||||
--disable-src \
|
||||
--disable-examples \
|
||||
CPPFLAGS="-I$PREFIX/include" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||
LDFLAGS="-L$PREFIX/lib"
|
||||
|
||||
And run ``make install`` to build and install. After spdylay
|
||||
installation, edit $ANDROID_HOME/usr/local/lib/pkgconfig/libspdylay.pc
|
||||
and remove the following line::
|
||||
|
||||
Requires.private: zlib
|
||||
|
||||
After prerequisite libraries are prepared, run ``android-config`` and
|
||||
then ``android-make`` to compile nghttp2 source files.
|
||||
|
||||
If all went well, application binaries, such as nghttpx, are created
|
||||
under src directory. Strip debugging information from the binary
|
||||
using the following command::
|
||||
|
||||
$ arm-linux-androideabi-strip src/nghttpx
|
||||
@@ -17,6 +17,7 @@ Contents:
|
||||
:maxdepth: 2
|
||||
|
||||
package_README
|
||||
building-android-binary
|
||||
tutorial-client
|
||||
tutorial-server
|
||||
tutorial-hpack
|
||||
@@ -27,24 +28,22 @@ Contents:
|
||||
nghttpx-howto
|
||||
h2load-howto
|
||||
apiref
|
||||
libnghttp2_asio
|
||||
python-apiref
|
||||
nghttp2.h
|
||||
nghttp2ver.h
|
||||
asio_http2.h
|
||||
Source <https://github.com/tatsuhiro-t/nghttp2>
|
||||
Issues <https://github.com/tatsuhiro-t/nghttp2/issues>
|
||||
|
||||
Released Versions
|
||||
=================
|
||||
|
||||
* `v0.3.2 <released-versions/v0.3.2/>`_ `(Download v0.3.2) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.3.2>`_
|
||||
* `v0.3.1 <released-versions/v0.3.1/>`_ `(Download v0.3.1) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.3.1>`_
|
||||
* `v0.3.0 <released-versions/v0.3.0/>`_ `(Download v0.3.0) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.3.0>`_
|
||||
* `v0.2.0 <released-versions/v0.2.0/>`_ `(Download v0.2.0) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.2.0>`_
|
||||
* `v0.1.0 <released-versions/v0.1.0/>`_ `(Download v0.1.0) <https://github.com/tatsuhiro-t/nghttp2/releases/tag/v0.1.0>`_
|
||||
|
||||
https://github.com/tatsuhiro-t/nghttp2/releases
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* http://tools.ietf.org/html/draft-ietf-httpbis-http2-13
|
||||
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08
|
||||
* http://tools.ietf.org/html/draft-ietf-httpbis-http2-14
|
||||
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09
|
||||
* http://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-04
|
||||
|
||||
248
doc/sources/libnghttp2_asio.rst
Normal file
248
doc/sources/libnghttp2_asio.rst
Normal file
@@ -0,0 +1,248 @@
|
||||
libnghttp2_asio: High level HTTP/2 C++ library
|
||||
==============================================
|
||||
|
||||
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
|
||||
high level abstraction API to build HTTP/2 applications. It depends
|
||||
on Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
|
||||
provides server side API.
|
||||
|
||||
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
|
||||
configure flag to build libnghttp2_asio. The required Boost libraries
|
||||
are:
|
||||
|
||||
* Boost::Asio
|
||||
* Boost::System
|
||||
* Boost::Thread
|
||||
|
||||
To use libnghttp2_asio, first include following header file:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
Also take a look at that header file :doc:`asio_http2.h`.
|
||||
|
||||
Server API
|
||||
----------
|
||||
|
||||
Server API is designed to build HTTP/2 server very easily to utilize
|
||||
C++11 anonymous function and closure. The bare minimum example of
|
||||
HTTP/2 server looks like this:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
http2 server;
|
||||
|
||||
server.listen
|
||||
("*", 3000,
|
||||
[](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
res->write_head(200);
|
||||
res->end("hello, world");
|
||||
});
|
||||
}
|
||||
|
||||
First we instantiate ``nghttp2::asio_http2::server::http2`` object.
|
||||
Then call ``nghttp2::asio_http2::server::http2::listen`` function with
|
||||
address and port to listen to and callback function, namely "request
|
||||
callback", invoked when request arrives.
|
||||
|
||||
The ``req`` and ``res`` represent HTTP request and response
|
||||
respectively. ``nghttp2::asio_http2_::server::response::write_head``
|
||||
constructs HTTP response header fields. The first argument is HTTP
|
||||
status code, in the above example, which is 200. The second argument,
|
||||
which is omitted in the above example, is additional header fields to
|
||||
send.
|
||||
|
||||
``nghttp2::asio_http2::server::response::end`` sends responde body.
|
||||
In the above example, we send string "hello, world".
|
||||
|
||||
Serving static files and enabling SSL/TLS
|
||||
+++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
In this example, we serve a couple of static files and also enable
|
||||
SSL/TLS.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
http2 server;
|
||||
|
||||
server.tls("server.key", "server.crt");
|
||||
|
||||
server.listen
|
||||
("*", 3000,
|
||||
[](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
if(req->path() == "/" || req->path() == "/index.html") {
|
||||
res->write_head(200);
|
||||
res->end(file_reader("index.html"));
|
||||
} else {
|
||||
res->write_head(404);
|
||||
res->end("<html><head><title>404</title></head>"
|
||||
"<body>404 Not Found</body></html>");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Specifying path to private key file and certificate file in
|
||||
``nghttp2::asio_http2::server::http2::tls`` will enable SSL/TLS. Both
|
||||
files must be in PEM format.
|
||||
|
||||
In the above example, if request path is either "/" or "/index.html",
|
||||
we serve index.html file in the current working directory.
|
||||
``nghttp2::asio_http2::server::response::end`` has overload to take
|
||||
function of type ``nghttp2::asio_http2::read_cb`` and application pass
|
||||
its implementation to generate response body. For the convenience,
|
||||
libnghttp2_asio library provides ``nghttp2::asio_http2::file_reader``
|
||||
function to generate function to server static file.
|
||||
|
||||
Server push
|
||||
+++++++++++
|
||||
|
||||
Server push is also supported.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
http2 server;
|
||||
|
||||
server.tls("server.key", "server.crt");
|
||||
|
||||
server.listen
|
||||
("*", 3000,
|
||||
[](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
if(req->path() == "/") {
|
||||
req->push("GET", "/my.css");
|
||||
|
||||
res->write_head(200);
|
||||
res->end(file_reader("index.html"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(req->path() == "/my.css") {
|
||||
res->write_head(200);
|
||||
res->end(file_reader("my.css"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
res->write_head(404);
|
||||
res->end("<html><head><title>404</title></head>"
|
||||
"<body>404 Not Found</body></html>");
|
||||
});
|
||||
}
|
||||
|
||||
When client requested "/", we push "/my.css". To push resource, call
|
||||
``nghttp2::asio_http2::server::request::push`` function with desired
|
||||
method and path. Later, the callback will be called with the pushed
|
||||
resource "/my.css".
|
||||
|
||||
Enable multi-threading
|
||||
++++++++++++++++++++++
|
||||
|
||||
Enabling multi-threading is very easy. Just call
|
||||
``nghttp2::asio_http2::server::http2::num_threads`` function with the
|
||||
desired number of threads:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
http2 server;
|
||||
|
||||
// Use 4 native threads
|
||||
server.num_threads(4);
|
||||
|
||||
Run blocking tasks in background thread
|
||||
+++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The request callback is called in the same thread where HTTP request
|
||||
is handled. And many connections shares the same thread, we cannot
|
||||
directly run blocking tasks in request callback.
|
||||
|
||||
To run blocking tasks, use
|
||||
``nghttp2::asio_http2::server::request::run_task``. The passed
|
||||
callback will be executed in the different thread from the thread
|
||||
where request callback was executed. So application can perform
|
||||
blocking task there. The example follows:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <unistd.h>
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
http2 server;
|
||||
|
||||
server.num_concurrent_tasks(16);
|
||||
|
||||
server.listen
|
||||
("*", 3000,
|
||||
[](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
req->run_task
|
||||
([res](channel& channel)
|
||||
{
|
||||
// executed in different thread than the thread where
|
||||
// request callback was executed.
|
||||
|
||||
// using res directly here is not safe. Capturing it by
|
||||
// value is safe because it is std::shared_ptr.
|
||||
|
||||
sleep(1);
|
||||
|
||||
channel.post
|
||||
([res]()
|
||||
{
|
||||
// executed in the same thread where request callback
|
||||
// was executed.
|
||||
res->write_head(200);
|
||||
res->end("hello, world");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
First we set the number of background threads which run tasks. By
|
||||
default it is set to 1. In this example, we set it to 16, so at most
|
||||
16 tasks can be executed concurrently without blocking handling new
|
||||
requests.
|
||||
|
||||
We call ``req->run_task()`` to execute task in background thread. In
|
||||
the passed callback, we just simply sleeps 1 second. After sleep is
|
||||
over, we schedule another callback to send response to the client.
|
||||
Since the callback passed to ``req->run_task()`` is executed in the
|
||||
different thread from the thread where request callback is called,
|
||||
using ``req`` or ``res`` object directly there may cause undefined
|
||||
behaviour. To avoid this issue, we can use
|
||||
``nghttp2::asio_http2::channel::post`` by supplying a callback which
|
||||
in turn get called in the same thread where request callback was
|
||||
called.
|
||||
@@ -197,9 +197,9 @@ connection, so the connection gets insecure. To disable SSL/TLS in
|
||||
backend connection, use ``--backend-no-tls`` option.
|
||||
|
||||
The backend server is supporsed to be a HTTP/2 web server or HTTP/2
|
||||
proxy. Since HTTP/2 requests opaque between proxied and non-proxied
|
||||
request, the backend server may be proxy or just web server depending
|
||||
on the context of incoming requests.
|
||||
proxy. If backend server is HTTP/2 proxy, use
|
||||
``--no-location-rewrite`` option to disable rewriting location header
|
||||
field.
|
||||
|
||||
The use-case of this mode is aggregate the incoming connections to one
|
||||
HTTP/2 connection. One backend HTTP/2 connection is created per
|
||||
@@ -235,20 +235,13 @@ Read/write rate limit
|
||||
---------------------
|
||||
|
||||
nghttpx supports transfer rate limiting on frontend connections. You
|
||||
can do rate limit per connection or per worker (thread) for reading
|
||||
and writeing individually.
|
||||
|
||||
To rate limit per connection for reading, use ``--read-rate`` and
|
||||
``--read-burst`` options. For writing, use ``--write-rate`` and
|
||||
``--write-burst`` options.
|
||||
can do rate limit per worker (thread) for reading and writeing
|
||||
individually.
|
||||
|
||||
To rate limit per worker (thread), use ``--worker-read-rate`` and
|
||||
``--worker-read-burst`` options. For writing, use
|
||||
``--worker-write-rate`` and ``--worker-write-burst``.
|
||||
|
||||
If both per connection and per worker rate limit configurations are
|
||||
specified, the lower rate is used.
|
||||
|
||||
Please note that rate limit is performed on top of TCP and nothing to
|
||||
do with HTTP/2 flow control.
|
||||
|
||||
@@ -269,3 +262,25 @@ used in frontend, and host is replaced with which appears in
|
||||
precedence. If the above conditions are not met with the host value
|
||||
in :authority header field, rewrite is retried with the value in host
|
||||
header field.
|
||||
|
||||
Hot deploy
|
||||
----------
|
||||
|
||||
nghttpx supports hot deploy feature using signals. The hot deploy in
|
||||
nghttpx is multi step process. First send USR2 signal to nghttpx
|
||||
process. It will do fork and execute new executable, using same
|
||||
command-line arguments and environment variables. At this point, both
|
||||
current and new processes can accept requests. To gracefully shutdown
|
||||
current process, send QUIT signal to current nghttpx process. When
|
||||
all existing frontend connections are done, the current process will
|
||||
exit. At this point, only new nghttpx process exists and serves
|
||||
incoming requests.
|
||||
|
||||
Re-opening log files
|
||||
--------------------
|
||||
|
||||
When rotating log files, it is desirable to re-open log files after
|
||||
log rotation daemon renamed existing log files. To tell nghttpx to
|
||||
re-open log files, send USR1 signal to nghttpx process. It will
|
||||
re-open files specified by ``--accesslog-file`` and
|
||||
``--errorlog-file`` options.
|
||||
|
||||
@@ -156,15 +156,30 @@ finished successfully. We first initialize nghttp2 session object in
|
||||
|
||||
static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||
{
|
||||
nghttp2_session_callbacks callbacks = {0};
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
|
||||
callbacks.send_callback = send_callback;
|
||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||
nghttp2_session_client_new(&session_data->session, &callbacks, session_data);
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(callbacks, on_data_chunk_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_header_callback
|
||||
(callbacks, on_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(callbacks, on_begin_headers_callback);
|
||||
|
||||
nghttp2_session_client_new(&session_data->session, callbacks, session_data);
|
||||
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
}
|
||||
|
||||
Since we are creating client, we use `nghttp2_session_client_new()` to
|
||||
@@ -291,11 +306,9 @@ frames. The ``session_send()`` function is defined as follows::
|
||||
}
|
||||
|
||||
The `nghttp2_session_send()` function serializes the frame into wire
|
||||
format and call :member:`nghttp2_session_callbacks.send_callback` with
|
||||
it. We set ``send_callback()`` function to
|
||||
:member:`nghttp2_session_callbacks.send_callback` in
|
||||
``initialize_nghttp2_session()`` function described earlier. It is
|
||||
defined as follows::
|
||||
format and call ``send_callback()`` function of type
|
||||
:type:`nghttp2_send_callback`. The ``send_callback()`` is defined as
|
||||
follows::
|
||||
|
||||
static ssize_t send_callback(nghttp2_session *session,
|
||||
const uint8_t *data, size_t length,
|
||||
@@ -311,15 +324,14 @@ Since we use bufferevent to abstract network I/O, we just write the
|
||||
data to the bufferevent object. Note that `nghttp2_session_send()`
|
||||
continues to write all frames queued so far. If we were writing the
|
||||
data to the non-blocking socket directly using ``write()`` system call
|
||||
in the :member:`nghttp2_session_callbacks.send_callback`, we will
|
||||
surely get ``EAGAIN`` or ``EWOULDBLOCK`` since the socket has limited
|
||||
send buffer. If that happens, we can return
|
||||
:macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the nghttp2 library to stop
|
||||
sending further data. But writing to the bufferevent, we have to
|
||||
regulate the amount data to be buffered by ourselves to avoid possible
|
||||
huge memory consumption. In this example client, we do not limit
|
||||
anything. To see how to regulate the amount of buffered data, see the
|
||||
``send_callback()`` in the server tutorial.
|
||||
in the ``send_callback()``, we will surely get ``EAGAIN`` or
|
||||
``EWOULDBLOCK`` since the socket has limited send buffer. If that
|
||||
happens, we can return :macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the
|
||||
nghttp2 library to stop sending further data. But writing to the
|
||||
bufferevent, we have to regulate the amount data to be buffered by
|
||||
ourselves to avoid possible huge memory consumption. In this example
|
||||
client, we do not limit anything. To see how to regulate the amount of
|
||||
buffered data, see the ``send_callback()`` in the server tutorial.
|
||||
|
||||
The third bufferevent callback is ``writecb()``, which is invoked when
|
||||
all data written in the bufferevent output buffer have been sent::
|
||||
|
||||
@@ -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
|
||||
----------------------------
|
||||
|
||||
|
||||
@@ -3,29 +3,28 @@ Tutorial: HTTP/2 server
|
||||
|
||||
In this tutorial, we are going to write single-threaded, event-based
|
||||
HTTP/2 web server, which supports HTTPS only. It can handle
|
||||
concurrent multiple requests, but only GET method is supported. The
|
||||
concurrent multiple requests, but only the GET method is supported. The
|
||||
complete source code, `libevent-server.c`_, is attached at the end of
|
||||
this page. It also resides in examples directory in the archive or
|
||||
repository.
|
||||
|
||||
This simple server takes 3 arguments, a port number to listen to, a
|
||||
path to SSL/TLS private key file and certificate file. Its synopsis
|
||||
is like this::
|
||||
This simple server takes 3 arguments, a port number to listen to, a path to
|
||||
your SSL/TLS private key file and a path to your certificate file. Its
|
||||
synopsis is like this::
|
||||
|
||||
$ libevent-server PORT /path/to/server.key /path/to/server.crt
|
||||
|
||||
We use libevent in this tutorial to handle networking I/O. Please
|
||||
note that nghttp2 itself does not depend on libevent.
|
||||
|
||||
First we do some setup routine for libevent and OpenSSL library in
|
||||
function ``main()`` and ``run()``, which is not so relevant to nghttp2
|
||||
library use. The one thing you should look at is setup NPN callback.
|
||||
The NPN callback is used for the server to advertise the application
|
||||
protocols the server supports to a client. In this example program,
|
||||
when creating ``SSL_CTX`` object, we stores the application protocol
|
||||
name in the wire format of NPN in statically allocated buffer. This is
|
||||
safe because we only create 1 ``SSL_CTX`` object in the entire program
|
||||
life time::
|
||||
First we create a setup routine for libevent and OpenSSL in the functions
|
||||
``main()`` and ``run()``. One thing in there you should look at, is the setup
|
||||
of the NPN callback. The NPN callback is used for the server to advertise
|
||||
which application protocols the server supports to a client. In this example
|
||||
program, when creating ``SSL_CTX`` object, we store the application protocol
|
||||
name in the wire format of NPN in a statically allocated buffer. This is safe
|
||||
because we only create one ``SSL_CTX`` object in the program's entire life
|
||||
time::
|
||||
|
||||
static unsigned char next_proto_list[256];
|
||||
static size_t next_proto_list_len;
|
||||
@@ -54,25 +53,25 @@ life time::
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
The wire format of NPN is a sequence of length prefixed string. The
|
||||
exactly one byte is used to specify the length of each protocol
|
||||
identifier. In this tutorial, we advertise the HTTP/2 protocol the
|
||||
nghttp2 library supports. The nghttp2 library exports its identifier
|
||||
in :macro:`NGHTTP2_PROTO_VERSION_ID`. The ``next_proto_cb()`` function
|
||||
is the server-side NPN callback. In OpenSSL implementation, we just
|
||||
assign the pointer to the NPN buffers we filled earlier. The NPN
|
||||
callback function is set to ``SSL_CTX`` object using
|
||||
The wire format of NPN is a sequence of length prefixed string. Exactly one
|
||||
byte is used to specify the length of each protocol identifier. In this
|
||||
tutorial, we advertise the specific HTTP/2 protocol version the current
|
||||
nghttp2 library supports. The nghttp2 library exports its identifier in
|
||||
:macro:`NGHTTP2_PROTO_VERSION_ID`. The ``next_proto_cb()`` function is the
|
||||
server-side NPN callback. In the OpenSSL implementation, we just assign the
|
||||
pointer to the NPN buffers we filled in earlier. The NPN callback function is
|
||||
set to the ``SSL_CTX`` object using
|
||||
``SSL_CTX_set_next_protos_advertised_cb()``.
|
||||
|
||||
We use ``app_content`` structure to store the application-wide data::
|
||||
We use the ``app_content`` structure to store application-wide data::
|
||||
|
||||
struct app_context {
|
||||
SSL_CTX *ssl_ctx;
|
||||
struct event_base *evbase;
|
||||
};
|
||||
|
||||
We use ``http2_session_data`` structure to store the session-level
|
||||
(which corresponds to 1 HTTP/2 connection) data::
|
||||
We use the ``http2_session_data`` structure to store session-level
|
||||
(which corresponds to one HTTP/2 connection) data::
|
||||
|
||||
typedef struct http2_session_data {
|
||||
struct http2_stream_data root;
|
||||
@@ -80,11 +79,9 @@ We use ``http2_session_data`` structure to store the session-level
|
||||
app_context *app_ctx;
|
||||
nghttp2_session *session;
|
||||
char *client_addr;
|
||||
size_t handshake_leftlen;
|
||||
} http2_session_data;
|
||||
|
||||
We use ``http2_stream_data`` structure to store the stream-level
|
||||
data::
|
||||
We use the ``http2_stream_data`` structure to store stream-level data::
|
||||
|
||||
typedef struct http2_stream_data {
|
||||
struct http2_stream_data *prev, *next;
|
||||
@@ -93,23 +90,18 @@ data::
|
||||
int fd;
|
||||
} http2_stream_data;
|
||||
|
||||
1 HTTP/2 session can have multiple streams. We manage these multiple
|
||||
streams by intrusive doubly linked list to add and remove the object
|
||||
in O(1). The first element of this list is pointed by the
|
||||
``root->next`` in ``http2_session_data``. Initially, ``root->next``
|
||||
is ``NULL``. The ``handshake_leftlen`` member of
|
||||
``http2_session_data`` is used to track the number of bytes remaining
|
||||
when receiving first client connection preface
|
||||
(:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`), which is 24 bytes magic
|
||||
byte string, from the client. We use libevent's bufferevent structure
|
||||
to perform network I/O. Notice that bufferevent object is in
|
||||
``http2_session_data`` and not in ``http2_stream_data``. This is
|
||||
because ``http2_stream_data`` is just a logical stream multiplexed
|
||||
A single HTTP/2 session can have multiple streams. We manage these
|
||||
multiple streams with a doubly linked list. The first element of this
|
||||
list is pointed to by the ``root->next`` in ``http2_session_data``.
|
||||
Initially, ``root->next`` is ``NULL``. We use libevent's bufferevent
|
||||
structure to perform network I/O. Note that the bufferevent object is
|
||||
kept in ``http2_session_data`` and not in ``http2_stream_data``. This
|
||||
is because ``http2_stream_data`` is just a logical stream multiplexed
|
||||
over the single connection managed by bufferevent in
|
||||
``http2_session_data``.
|
||||
|
||||
We first create listener object to accept incoming connections.
|
||||
We use libevent's ``struct evconnlistener`` for this purpose::
|
||||
We first create a listener object to accept incoming connections. We use
|
||||
libevent's ``struct evconnlistener`` for this purpose::
|
||||
|
||||
static void start_listen(struct event_base *evbase, const char *service,
|
||||
app_context *app_ctx)
|
||||
@@ -143,8 +135,8 @@ We use libevent's ``struct evconnlistener`` for this purpose::
|
||||
errx(1, "Could not start listener");
|
||||
}
|
||||
|
||||
We specify ``acceptcb`` callback which is called when a new connection
|
||||
is accepted::
|
||||
We specify the ``acceptcb`` callback which is called when a new connection is
|
||||
accepted::
|
||||
|
||||
static void acceptcb(struct evconnlistener *listener, int fd,
|
||||
struct sockaddr *addr, int addrlen, void *arg)
|
||||
@@ -153,15 +145,16 @@ is accepted::
|
||||
http2_session_data *session_data;
|
||||
|
||||
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
|
||||
bufferevent_setcb(session_data->bev, handshake_readcb, NULL, eventcb,
|
||||
session_data);
|
||||
|
||||
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data);
|
||||
}
|
||||
|
||||
Here we create ``http2_session_data`` object. The bufferevent for this
|
||||
connection is also initialized at this time. We specify 2 callbacks
|
||||
for the bufferevent: ``handshake_readcb`` and ``eventcb``.
|
||||
Here we create the ``http2_session_data`` object. The bufferevent for
|
||||
this connection is also initialized at this time. We specify three
|
||||
callbacks for the bufferevent: ``readcb``, ``writecb`` and
|
||||
``eventcb``.
|
||||
|
||||
The ``eventcb()`` is invoked by libevent event loop when an event
|
||||
The ``eventcb()`` callback is invoked by the libevent event loop when an event
|
||||
(e.g., connection has been established, timeout, etc) happens on the
|
||||
underlying network socket::
|
||||
|
||||
@@ -170,6 +163,14 @@ underlying network socket::
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
if(events & BEV_EVENT_CONNECTED) {
|
||||
fprintf(stderr, "%s connected\n", session_data->client_addr);
|
||||
|
||||
initialize_nghttp2_session(session_data);
|
||||
|
||||
if(send_server_connection_header(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if(events & BEV_EVENT_EOF) {
|
||||
@@ -182,77 +183,64 @@ underlying network socket::
|
||||
delete_http2_session_data(session_data);
|
||||
}
|
||||
|
||||
For ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR`` and ``BEV_EVENT_TIMEOUT``
|
||||
event, we just simply tear down the connection. The
|
||||
``delete_http2_session_data()`` function destroys
|
||||
``http2_session_data`` object and thus its bufferevent member. As a
|
||||
result, the underlying connection is closed. The
|
||||
For the ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR`` and
|
||||
``BEV_EVENT_TIMEOUT`` events, we just simply tear down the connection.
|
||||
The ``delete_http2_session_data()`` function destroys the
|
||||
``http2_session_data`` object and thus also its bufferevent member.
|
||||
As a result, the underlying connection is closed. The
|
||||
``BEV_EVENT_CONNECTED`` event is invoked when SSL/TLS handshake is
|
||||
finished successfully.
|
||||
finished successfully. Now we are ready to start the HTTP/2
|
||||
communication.
|
||||
|
||||
The ``handshake_readcb()`` is a callback function to handle 24 bytes
|
||||
magic byte string from a client, since nghttp2 library does not handle
|
||||
it::
|
||||
|
||||
static void handshake_readcb(struct bufferevent *bev, void *ptr)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
uint8_t data[24];
|
||||
struct evbuffer *input = bufferevent_get_input(session_data->bev);
|
||||
int readlen = evbuffer_remove(input, data, session_data->handshake_leftlen);
|
||||
const char *conhead = NGHTTP2_CLIENT_CONNECTION_PREFACE;
|
||||
|
||||
if(memcmp(conhead + NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
|
||||
- session_data->handshake_leftlen, data, readlen) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
session_data->handshake_leftlen -= readlen;
|
||||
if(session_data->handshake_leftlen == 0) {
|
||||
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, ptr);
|
||||
/* Process pending data in buffer since they are not notified
|
||||
further */
|
||||
initialize_nghttp2_session(session_data);
|
||||
if(send_server_connection_header(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
if(session_recv(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
We check that the received byte string matches
|
||||
:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`. When they match, the
|
||||
connection state is ready for starting HTTP/2 communication. First
|
||||
we change the callback functions for the bufferevent object. We use
|
||||
same ``eventcb`` as before. But we specify new ``readcb`` and
|
||||
``writecb`` function to handle HTTP/2 communication. We describe
|
||||
these 2 functions later.
|
||||
|
||||
We initialize nghttp2 session object which is done in
|
||||
We initialize a nghttp2 session object which is done in
|
||||
``initialize_nghttp2_session()``::
|
||||
|
||||
static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||
{
|
||||
nghttp2_session_callbacks callbacks = {0};
|
||||
nghttp2_option *option;
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
|
||||
callbacks.send_callback = send_callback;
|
||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||
nghttp2_session_server_new(&session_data->session, &callbacks, session_data);
|
||||
nghttp2_option_new(&option);
|
||||
|
||||
/* Tells nghttp2_session object that it handles client connection
|
||||
preface */
|
||||
nghttp2_option_set_recv_client_preface(option, 1);
|
||||
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_header_callback
|
||||
(callbacks, on_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(callbacks, on_begin_headers_callback);
|
||||
|
||||
|
||||
|
||||
nghttp2_session_server_new2(&session_data->session, callbacks, session_data,
|
||||
option);
|
||||
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
nghttp2_option_del(option);
|
||||
}
|
||||
|
||||
Since we are creating server, nghttp2 session object is created using
|
||||
`nghttp2_session_server_new()` function. We registers 5 callbacks to
|
||||
nghttp2 session object. We'll talk about these callbacks later.
|
||||
Since we are creating a server and uses options, the nghttp2 session
|
||||
object is created using `nghttp2_session_server_new2()` function. We
|
||||
registers five callbacks for nghttp2 session object. We'll talk about
|
||||
these callbacks later. Our server only speaks HTTP/2. In this case,
|
||||
we use `nghttp2_option_set_recv_client_preface()` to make
|
||||
:type:`nghttp2_session` object handle client connection preface, which
|
||||
saves some lines of application code.
|
||||
|
||||
After initialization of nghttp2 session object, we are going to send
|
||||
server connection header in ``send_server_connection_header()``::
|
||||
After initialization of the nghttp2 session object, we are going to send
|
||||
a server connection header in ``send_server_connection_header()``::
|
||||
|
||||
static int send_server_connection_header(http2_session_data *session_data)
|
||||
{
|
||||
@@ -270,18 +258,18 @@ server connection header in ``send_server_connection_header()``::
|
||||
return 0;
|
||||
}
|
||||
|
||||
The server connection header is SETTINGS frame. We specify
|
||||
SETTINGS_MAX_CONCURRENT_STREAMS to 100 in SETTINGS frame. To queue
|
||||
The server connection header is a SETTINGS frame. We specify
|
||||
SETTINGS_MAX_CONCURRENT_STREAMS to 100 in the SETTINGS frame. To queue
|
||||
the SETTINGS frame for the transmission, we use
|
||||
`nghttp2_submit_settings()`. Note that `nghttp2_submit_settings()`
|
||||
function only queues the frame and not actually send it. All
|
||||
``nghttp2_submit_*()`` family functions have this property. To
|
||||
actually send the frame, `nghttp2_session_send()` is used, which is
|
||||
described about later.
|
||||
function only queues the frame and it does not actually send it. All
|
||||
functions in the ``nghttp2_submit_*()`` family have this property. To
|
||||
actually send the frame, `nghttp2_session_send()` should be used, as
|
||||
described later.
|
||||
|
||||
Since bufferevent may buffer more than first 24 bytes from the client,
|
||||
we have to process them here since libevent won't invoke callback
|
||||
functions for these pending data. To process received data, we call
|
||||
Since bufferevent may buffer more than the first 24 bytes from the client, we
|
||||
have to process them here since libevent won't invoke callback functions for
|
||||
this pending data. To process the received data, we call the
|
||||
``session_recv()`` function::
|
||||
|
||||
static int session_recv(http2_session_data *session_data)
|
||||
@@ -306,12 +294,12 @@ functions for these pending data. To process received data, we call
|
||||
return 0;
|
||||
}
|
||||
|
||||
In this function, we feed all unprocessed, received data to nghttp2
|
||||
session object using `nghttp2_session_mem_recv()` function. The
|
||||
`nghttp2_session_mem_recv()` processes the received data and may
|
||||
invoke nghttp2 callbacks and also queue outgoing frames. Since there
|
||||
may be pending frames, we call ``session_send()`` function to send
|
||||
those frames. The ``session_send()`` function is defined as follows::
|
||||
In this function, we feed all unprocessed but already received data to the
|
||||
nghttp2 session object using the `nghttp2_session_mem_recv()` function. The
|
||||
`nghttp2_session_mem_recv()` function processes the data and may invoke the
|
||||
nghttp2 callbacks and also queue outgoing frames. Since there may be pending
|
||||
outgoing frames, we call ``session_send()`` function to send off those
|
||||
frames. The ``session_send()`` function is defined as follows::
|
||||
|
||||
static int session_send(http2_session_data *session_data)
|
||||
{
|
||||
@@ -325,11 +313,9 @@ those frames. The ``session_send()`` function is defined as follows::
|
||||
}
|
||||
|
||||
The `nghttp2_session_send()` function serializes the frame into wire
|
||||
format and call :member:`nghttp2_session_callbacks.send_callback` with
|
||||
it. We set ``send_callback()`` function to
|
||||
:member:`nghttp2_session_callbacks.send_callback` in
|
||||
``initialize_nghttp2_session()`` function described earlier. It is
|
||||
defined as follows::
|
||||
format and calls ``send_callback()`` of type
|
||||
:type:`nghttp2_send_callback`. The ``send_callback()`` is defined as
|
||||
follows::
|
||||
|
||||
static ssize_t send_callback(nghttp2_session *session,
|
||||
const uint8_t *data, size_t length,
|
||||
@@ -349,18 +335,17 @@ defined as follows::
|
||||
Since we use bufferevent to abstract network I/O, we just write the
|
||||
data to the bufferevent object. Note that `nghttp2_session_send()`
|
||||
continues to write all frames queued so far. If we were writing the
|
||||
data to the non-blocking socket directly using ``write()`` system call
|
||||
in the :member:`nghttp2_session_callbacks.send_callback`, we will
|
||||
surely get ``EAGAIN`` or ``EWOULDBLOCK`` since the socket has limited
|
||||
send buffer. If that happens, we can return
|
||||
:macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the nghttp2 library to stop
|
||||
sending further data. But writing to the bufferevent, we have to
|
||||
regulate the amount data to be buffered by ourselves to avoid possible
|
||||
huge memory consumption. To achieve this, we check the size of output
|
||||
buffer and if it is more than or equal to
|
||||
``OUTPUT_WOULDBLOCK_THRESHOLD`` bytes, we stop writing data and return
|
||||
:macro:`NGHTTP2_ERR_WOULDBLOCK` to tell the library to stop calling
|
||||
send_callback.
|
||||
data to a non-blocking socket directly using ``write()`` system call
|
||||
in the ``send_callback()``, we would surely get ``EAGAIN`` or
|
||||
``EWOULDBLOCK`` back since the socket has limited send buffer. If that
|
||||
happens, we can return :macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the
|
||||
nghttp2 library to stop sending further data. But when writing to the
|
||||
bufferevent, we have to regulate the amount data to get buffered
|
||||
ourselves to avoid using huge amounts of memory. To achieve this, we
|
||||
check the size of the output buffer and if it reaches more than or
|
||||
equal to ``OUTPUT_WOULDBLOCK_THRESHOLD`` bytes, we stop writing data
|
||||
and return :macro:`NGHTTP2_ERR_WOULDBLOCK` to tell the library to stop
|
||||
calling send_callback.
|
||||
|
||||
The next bufferevent callback is ``readcb()``, which is invoked when
|
||||
data is available to read in the bufferevent input buffer::
|
||||
@@ -377,8 +362,8 @@ data is available to read in the bufferevent input buffer::
|
||||
In this function, we just call ``session_recv()`` to process incoming
|
||||
data.
|
||||
|
||||
The third bufferevent callback is ``writecb()``, which is invoked when
|
||||
all data written in the bufferevent output buffer have been sent::
|
||||
The third bufferevent callback is ``writecb()``, which is invoked when all
|
||||
data in the bufferevent output buffer has been sent::
|
||||
|
||||
static void writecb(struct bufferevent *bev, void *ptr)
|
||||
{
|
||||
@@ -397,29 +382,28 @@ all data written in the bufferevent output buffer have been sent::
|
||||
}
|
||||
}
|
||||
|
||||
First we check whether we should drop connection or not. The nghttp2
|
||||
session object keeps track of reception and transmission of GOAWAY
|
||||
frame and other error conditions as well. Using these information,
|
||||
nghttp2 session object will tell whether the connection should be
|
||||
dropped or not. More specifically, both `nghttp2_session_want_read()`
|
||||
and `nghttp2_session_want_write()` return 0, we have no business in
|
||||
the connection. But since we are using bufferevent and its deferred
|
||||
callback option, the bufferevent output buffer may contain the pending
|
||||
data when the ``writecb()`` is called. To handle this situation, we
|
||||
also check whether the output buffer is empty or not. If these
|
||||
conditions are met, we drop connection.
|
||||
First we check whether we should drop the connection or not. The nghttp2
|
||||
session object keeps track of reception and transmission of GOAWAY frames and
|
||||
other error conditions as well. Using this information, the nghttp2 session
|
||||
object will tell whether the connection should be dropped or not. More
|
||||
specifically, if both `nghttp2_session_want_read()` and
|
||||
`nghttp2_session_want_write()` return 0, we have no business left in the
|
||||
connection. But since we are using bufferevent and its deferred callback
|
||||
option, the bufferevent output buffer may contain pending data when the
|
||||
``writecb()`` is called. To handle this, we check whether the output buffer is
|
||||
empty or not. If all these conditions are met, we drop connection.
|
||||
|
||||
Otherwise, we call ``session_send()`` to process pending output
|
||||
data. Remember that in ``send_callback()``, we may not write all data
|
||||
to bufferevent to avoid excessive buffering. We continue process
|
||||
pending data when output buffer becomes empty.
|
||||
Otherwise, we call ``session_send()`` to process the pending output
|
||||
data. Remember that in ``send_callback()``, we must not write all data to
|
||||
bufferevent to avoid excessive buffering. We continue processing pending data
|
||||
when the output buffer becomes empty.
|
||||
|
||||
We have already described about nghttp2 callback ``send_callback()``.
|
||||
Let's describe remaining nghttp2 callbacks we setup in
|
||||
We have already described the nghttp2 callback ``send_callback()``. Let's
|
||||
learn about the remaining nghttp2 callbacks we setup in
|
||||
``initialize_nghttp2_setup()`` function.
|
||||
|
||||
The ``on_begin_headers_callback()`` function is invoked when reception
|
||||
of header block in HEADERS or PUSH_PROMISE frame is started::
|
||||
The ``on_begin_headers_callback()`` function is invoked when the reception of
|
||||
a header block in HEADERS or PUSH_PROMISE frame is started::
|
||||
|
||||
static int on_begin_headers_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
@@ -438,17 +422,17 @@ of header block in HEADERS or PUSH_PROMISE frame is started::
|
||||
return 0;
|
||||
}
|
||||
|
||||
We only interested in HEADERS frame in this function. Since HEADERS
|
||||
frame has several roles in HTTP/2 protocol, we check that it is a
|
||||
request HEADERS, which opens new stream. If frame is request HEADERS,
|
||||
then we create ``http2_stream_data`` object to store stream related
|
||||
data. We associate created ``http2_stream_data`` object to the stream
|
||||
in nghttp2 session object using `nghttp2_set_stream_user_data()` in
|
||||
order to get the object without searching through doubly linked list.
|
||||
We are only interested in the HEADERS frame in this function. Since the
|
||||
HEADERS frame has several roles in the HTTP/2 protocol, we check that it is a
|
||||
request HEADERS, which opens new stream. If the frame is a request HEADERS, we
|
||||
create a ``http2_stream_data`` object to store the stream related data. We
|
||||
associate the created ``http2_stream_data`` object with the stream in the
|
||||
nghttp2 session object using `nghttp2_set_stream_user_data()` to get the
|
||||
object without searching through the doubly linked list.
|
||||
|
||||
In this example server, we want to serve files relative to the current
|
||||
working directory the program was invoked. Each header name/value pair
|
||||
is emitted via ``on_header_callback`` function, which is called after
|
||||
In this example server, we want to serve files relative to the current working
|
||||
directory in which the program was invoked. Each header name/value pair is
|
||||
emitted via ``on_header_callback`` function, which is called after
|
||||
``on_begin_headers_callback()``::
|
||||
|
||||
static int on_header_callback(nghttp2_session *session,
|
||||
@@ -479,10 +463,10 @@ is emitted via ``on_header_callback`` function, which is called after
|
||||
return 0;
|
||||
}
|
||||
|
||||
We search ``:path`` header field in request headers and keep the
|
||||
requested path in ``http2_stream_data`` object. In this example
|
||||
program, we ignore ``:method`` header field and always treat the
|
||||
request as GET request.
|
||||
We search for the ``:path`` header field among the request headers and store
|
||||
the requested path in the ``http2_stream_data`` object. In this example
|
||||
program, we ignore ``:method`` header field and always treat the request as a
|
||||
GET request.
|
||||
|
||||
The ``on_frame_recv_callback()`` function is invoked when a frame is
|
||||
fully received::
|
||||
@@ -513,15 +497,15 @@ fully received::
|
||||
return 0;
|
||||
}
|
||||
|
||||
First we retrieve ``http2_stream_data`` object associated to the
|
||||
stream in ``on_begin_headers_callback()``. It is done using
|
||||
`nghttp2_session_get_stream_user_data()`. If the requested path cannot
|
||||
be served for some reasons (e.g., file is not found), we send 404
|
||||
response, which is done in ``error_reply()``. Otherwise, we open
|
||||
requested file and send its content. We send 1 header field
|
||||
``:status`` as a response header.
|
||||
First we retrieve the ``http2_stream_data`` object associated with the stream
|
||||
in ``on_begin_headers_callback()``. It is done using
|
||||
`nghttp2_session_get_stream_user_data()`. If the requested path cannot be
|
||||
served for some reason (e.g., file is not found), we send a 404 response,
|
||||
which is done in ``error_reply()``. Otherwise, we open the requested file and
|
||||
send its content. We send the header field ``:status`` as a single response
|
||||
header.
|
||||
|
||||
Sending content of a file is done in ``send_response()`` function::
|
||||
Sending the content of the file is done in ``send_response()`` function::
|
||||
|
||||
static int send_response(nghttp2_session *session, int32_t stream_id,
|
||||
nghttp2_nv *nva, size_t nvlen, int fd)
|
||||
@@ -539,12 +523,12 @@ Sending content of a file is done in ``send_response()`` function::
|
||||
return 0;
|
||||
}
|
||||
|
||||
The nghttp2 library uses :type:`nghttp2_data_provider` structure to
|
||||
The nghttp2 library uses the :type:`nghttp2_data_provider` structure to
|
||||
send entity body to the remote peer. The ``source`` member of this
|
||||
structure is a union and it can be either void pointer or int which is
|
||||
intended to be used as file descriptor. In this example server, we use
|
||||
file descriptor. We also set ``file_read_callback()`` callback
|
||||
function to read content of the file::
|
||||
the file descriptor. We also set the ``file_read_callback()`` callback
|
||||
function to read the contents of the file::
|
||||
|
||||
static ssize_t file_read_callback
|
||||
(nghttp2_session *session, int32_t stream_id,
|
||||
@@ -563,14 +547,14 @@ function to read content of the file::
|
||||
return r;
|
||||
}
|
||||
|
||||
If error happens while reading file, we return
|
||||
If an error happens while reading the file, we return
|
||||
:macro:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. This tells the
|
||||
library to send RST_STREAM to the stream. When all data are read, set
|
||||
:macro:`NGHTTP2_DATA_FLAG_EOF` flag to ``*data_flags`` to tell the
|
||||
nghttp2 library that we have finished reading file.
|
||||
library to send RST_STREAM to the stream. When all data has been read, set
|
||||
the :macro:`NGHTTP2_DATA_FLAG_EOF` flag to ``*data_flags`` to tell the
|
||||
nghttp2 library that we have finished reading the file.
|
||||
|
||||
The `nghttp2_submit_response()` is used to send response to the remote
|
||||
peer.
|
||||
The `nghttp2_submit_response()` function is used to send the response to the
|
||||
remote peer.
|
||||
|
||||
The ``on_stream_close_callback()`` function is invoked when the stream
|
||||
is about to close::
|
||||
@@ -592,5 +576,5 @@ is about to close::
|
||||
return 0;
|
||||
}
|
||||
|
||||
We destroy ``http2_stream_data`` object in this function since the
|
||||
stream is about to close and we no longer use that object.
|
||||
We destroy the ``http2_stream_data`` object in this function since the stream
|
||||
is about to close and we no longer use that object.
|
||||
|
||||
4
examples/.gitignore
vendored
4
examples/.gitignore
vendored
@@ -2,3 +2,7 @@ client
|
||||
libevent-client
|
||||
libevent-server
|
||||
deflate
|
||||
asio-sv
|
||||
tiny-nghttpd
|
||||
asio-sv2
|
||||
asio-sv3
|
||||
|
||||
@@ -27,6 +27,7 @@ AM_CPPFLAGS = \
|
||||
-Wall \
|
||||
-I$(top_srcdir)/lib/includes \
|
||||
-I$(top_builddir)/lib/includes \
|
||||
-I$(top_srcdir)/src/includes \
|
||||
-I$(top_srcdir)/third-party \
|
||||
@LIBEVENT_OPENSSL_CFLAGS@ \
|
||||
@OPENSSL_CFLAGS@ \
|
||||
@@ -48,4 +49,37 @@ libevent_server_SOURCES = libevent-server.c
|
||||
|
||||
deflate_SOURCES = deflate.c
|
||||
|
||||
if ENABLE_TINY_NGHTTPD
|
||||
|
||||
noinst_PROGRAMS += tiny-nghttpd
|
||||
|
||||
tiny_nghttpd_SOURCES = tiny-nghttpd.c
|
||||
|
||||
endif # ENABLE_TINY_NGHTTPD
|
||||
|
||||
if ENABLE_ASIO_LIB
|
||||
|
||||
noinst_PROGRAMS += asio-sv asio-sv2 asio-sv3
|
||||
|
||||
ASIOCPPFLAGS = ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
ASIOLDFLAGS = @JEMALLOC_LIBS@
|
||||
ASIOLDADD = $(top_builddir)/src/libnghttp2_asio.la
|
||||
|
||||
asio_sv_SOURCES = asio-sv.cc
|
||||
asio_sv_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
asio_sv_LDFLAGS = ${ASIOLDFLAGS}
|
||||
asio_sv_LDADD = ${ASIOLDADD}
|
||||
|
||||
asio_sv2_SOURCES = asio-sv2.cc
|
||||
asio_sv2_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
asio_sv2_LDFLAGS = ${ASIOLDFLAGS}
|
||||
asio_sv2_LDADD = ${ASIOLDADD}
|
||||
|
||||
asio_sv3_SOURCES = asio-sv3.cc
|
||||
asio_sv3_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
asio_sv3_LDFLAGS = ${ASIOLDFLAGS}
|
||||
asio_sv3_LDADD = ${ASIOLDADD}
|
||||
|
||||
endif # ENABLE_ASIO_LIB
|
||||
|
||||
endif # ENABLE_EXAMPLES
|
||||
|
||||
79
examples/asio-sv.cc
Normal file
79
examples/asio-sv.cc
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// main.cpp
|
||||
// ~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try {
|
||||
// Check command line arguments.
|
||||
if (argc < 3) {
|
||||
std::cerr << "Usage: asio-sv <port> <threads> <private-key-file> "
|
||||
<< "<cert-file>\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t port = std::stoi(argv[1]);
|
||||
std::size_t num_threads = std::stoi(argv[2]);
|
||||
|
||||
http2 server;
|
||||
|
||||
server.num_threads(num_threads);
|
||||
|
||||
if(argc >= 5) {
|
||||
server.tls(argv[3], argv[4]);
|
||||
}
|
||||
|
||||
server.listen
|
||||
("*", port,
|
||||
[](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
res->write_head(200, { header{ "foo", "bar" } });
|
||||
res->end("hello, world");
|
||||
});
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
111
examples/asio-sv2.cc
Normal file
111
examples/asio-sv2.cc
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// main.cpp
|
||||
// ~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try {
|
||||
// Check command line arguments.
|
||||
if (argc < 4) {
|
||||
std::cerr << "Usage: asio-sv2 <port> <threads> <doc-root> "
|
||||
<< "<private-key-file> <cert-file>\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t port = std::stoi(argv[1]);
|
||||
std::size_t num_threads = std::stoi(argv[2]);
|
||||
std::string docroot = argv[3];
|
||||
|
||||
http2 server;
|
||||
|
||||
server.num_threads(num_threads);
|
||||
|
||||
if(argc >= 6) {
|
||||
server.tls(argv[4], argv[5]);
|
||||
}
|
||||
|
||||
server.listen
|
||||
("*", port,
|
||||
[&docroot](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
auto path = percent_decode(req->path());
|
||||
if(!check_path(path)) {
|
||||
res->write_head(404);
|
||||
res->end();
|
||||
return;
|
||||
}
|
||||
|
||||
if(path == "/") {
|
||||
path = "/index.html";
|
||||
}
|
||||
|
||||
path = docroot + path;
|
||||
auto fd = open(path.c_str(), O_RDONLY);
|
||||
if(fd == -1) {
|
||||
res->write_head(404);
|
||||
res->end();
|
||||
return;
|
||||
}
|
||||
|
||||
auto headers = std::vector<header>();
|
||||
|
||||
struct stat stbuf;
|
||||
if(stat(path.c_str(), &stbuf) == 0) {
|
||||
headers.push_back
|
||||
(header{"content-length", std::to_string(stbuf.st_size)});
|
||||
headers.push_back
|
||||
(header{"last-modified", http_date(stbuf.st_mtim.tv_sec)});
|
||||
}
|
||||
res->write_head(200, std::move(headers));
|
||||
res->end(file_reader_from_fd(fd));
|
||||
});
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
151
examples/asio-sv3.cc
Normal file
151
examples/asio-sv3.cc
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// main.cpp
|
||||
// ~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try {
|
||||
// Check command line arguments.
|
||||
if (argc < 4) {
|
||||
std::cerr << "Usage: asio-sv3 <port> <threads> <tasks> "
|
||||
<< " <private-key-file> <cert-file>\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t port = std::stoi(argv[1]);
|
||||
std::size_t num_threads = std::stoi(argv[2]);
|
||||
std::size_t num_concurrent_tasks = std::stoi(argv[3]);
|
||||
|
||||
http2 server;
|
||||
|
||||
server.num_threads(num_threads);
|
||||
|
||||
if(argc >= 5) {
|
||||
server.tls(argv[4], argv[5]);
|
||||
}
|
||||
|
||||
server.num_concurrent_tasks(num_concurrent_tasks);
|
||||
|
||||
server.listen
|
||||
("*", port,
|
||||
[](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
res->write_head(200);
|
||||
|
||||
auto msgq = std::make_shared<std::deque<std::string>>();
|
||||
|
||||
res->end
|
||||
([msgq](uint8_t *buf, std::size_t len) -> std::pair<ssize_t, bool>
|
||||
{
|
||||
if(msgq->empty()) {
|
||||
// if msgq is empty, tells the library that don't call
|
||||
// this callback until we call res->resume(). This is
|
||||
// done by returing std::make_pair(0, false).
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
auto msg = std::move(msgq->front());
|
||||
msgq->pop_front();
|
||||
|
||||
if(msg.empty()) {
|
||||
// The empty message signals the end of response in
|
||||
// this simple protocol.
|
||||
return std::make_pair(0, true);
|
||||
}
|
||||
|
||||
auto nwrite = std::min(len, msg.size());
|
||||
std::copy(std::begin(msg), std::begin(msg) + nwrite, buf);
|
||||
if(msg.size() > nwrite) {
|
||||
msgq->push_front(msg.substr(nwrite));
|
||||
}
|
||||
return std::make_pair(nwrite, false);
|
||||
});
|
||||
|
||||
req->run_task
|
||||
([res, msgq](channel& channel)
|
||||
{
|
||||
// executed in different thread from request callback
|
||||
// was called.
|
||||
|
||||
// Using res and msgq is not safe inside this callback.
|
||||
// But using them in callback passed to channel::post is
|
||||
// safe.
|
||||
|
||||
// We just emit simple message "message N\n" in every 1
|
||||
// second and 3 times in total.
|
||||
for(std::size_t i = 0; i < 3; ++i) {
|
||||
msgq->push_back("message " + std::to_string(i + 1) + "\n");
|
||||
|
||||
channel.post([res]()
|
||||
{
|
||||
// executed in same thread where
|
||||
// request callback was called.
|
||||
|
||||
// Tells library we have new message.
|
||||
res->resume();
|
||||
});
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
// Send empty message to signal the end of response
|
||||
// body.
|
||||
msgq->push_back("");
|
||||
|
||||
channel.post([res]()
|
||||
{
|
||||
// executed in same thread where request
|
||||
// callback was called.
|
||||
res->resume();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/conf.h>
|
||||
|
||||
enum {
|
||||
IO_NONE,
|
||||
@@ -309,13 +310,21 @@ static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
*/
|
||||
static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks)
|
||||
{
|
||||
memset(callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks->send_callback = send_callback;
|
||||
callbacks->recv_callback = recv_callback;
|
||||
callbacks->on_frame_send_callback = on_frame_send_callback;
|
||||
callbacks->on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks->on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_send_callback
|
||||
(callbacks, on_frame_send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(callbacks, on_data_chunk_recv_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -506,7 +515,7 @@ static void request_free(struct Request *req)
|
||||
*/
|
||||
static void fetch_uri(const struct URI *uri)
|
||||
{
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
int fd;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL *ssl;
|
||||
@@ -518,8 +527,6 @@ static void fetch_uri(const struct URI *uri)
|
||||
|
||||
request_init(&req, uri);
|
||||
|
||||
setup_nghttp2_callbacks(&callbacks);
|
||||
|
||||
/* Establish connection and setup SSL */
|
||||
fd = connect_to(req.host, req.port);
|
||||
if(fd == -1) {
|
||||
@@ -550,8 +557,20 @@ static void fetch_uri(const struct URI *uri)
|
||||
set_tcp_nodelay(fd);
|
||||
|
||||
printf("[INFO] SSL/TLS handshake completed\n");
|
||||
rv = nghttp2_session_client_new(&connection.session, &callbacks,
|
||||
|
||||
rv = nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
if(rv != 0) {
|
||||
diec("nghttp2_session_callbacks_new", rv);
|
||||
}
|
||||
|
||||
setup_nghttp2_callbacks(callbacks);
|
||||
|
||||
rv = nghttp2_session_client_new(&connection.session, callbacks,
|
||||
&connection);
|
||||
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
|
||||
if(rv != 0) {
|
||||
diec("nghttp2_session_client_new", rv);
|
||||
}
|
||||
@@ -685,6 +704,8 @@ int main(int argc, char **argv)
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &act, 0);
|
||||
|
||||
OPENSSL_config(NULL);
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/conf.h>
|
||||
|
||||
#include <event.h>
|
||||
#include <event2/event.h>
|
||||
@@ -330,17 +331,30 @@ static SSL* create_ssl(SSL_CTX *ssl_ctx)
|
||||
|
||||
static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||
{
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
callbacks.send_callback = send_callback;
|
||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||
nghttp2_session_client_new(&session_data->session, &callbacks, session_data);
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(callbacks, on_data_chunk_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_header_callback
|
||||
(callbacks, on_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(callbacks, on_begin_headers_callback);
|
||||
|
||||
nghttp2_session_client_new(&session_data->session, callbacks, session_data);
|
||||
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
}
|
||||
|
||||
static void send_client_connection_header(http2_session_data *session_data)
|
||||
@@ -560,6 +574,8 @@ int main(int argc, char **argv)
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &act, NULL);
|
||||
|
||||
OPENSSL_config(NULL);
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/conf.h>
|
||||
|
||||
#include <event.h>
|
||||
#include <event2/event.h>
|
||||
@@ -68,7 +69,6 @@ typedef struct http2_session_data {
|
||||
app_context *app_ctx;
|
||||
nghttp2_session *session;
|
||||
char *client_addr;
|
||||
size_t handshake_leftlen;
|
||||
} http2_session_data;
|
||||
|
||||
struct app_context {
|
||||
@@ -191,7 +191,6 @@ static http2_session_data* create_http2_session_data(app_context *app_ctx,
|
||||
(app_ctx->evbase, fd, ssl,
|
||||
BUFFEREVENT_SSL_ACCEPTING,
|
||||
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
|
||||
session_data->handshake_leftlen = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN;
|
||||
rv = getnameinfo(addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
|
||||
if(rv != 0) {
|
||||
session_data->client_addr = strdup("(unknown)");
|
||||
@@ -554,16 +553,38 @@ static int on_stream_close_callback(nghttp2_session *session,
|
||||
|
||||
static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||
{
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_option *option;
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
nghttp2_option_new(&option);
|
||||
|
||||
callbacks.send_callback = send_callback;
|
||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||
nghttp2_session_server_new(&session_data->session, &callbacks, session_data);
|
||||
/* Tells nghttp2_session object that it handles client connection
|
||||
preface */
|
||||
nghttp2_option_set_recv_client_preface(option, 1);
|
||||
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_header_callback
|
||||
(callbacks, on_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(callbacks, on_begin_headers_callback);
|
||||
|
||||
|
||||
|
||||
nghttp2_session_server_new2(&session_data->session, callbacks, session_data,
|
||||
option);
|
||||
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
nghttp2_option_del(option);
|
||||
}
|
||||
|
||||
/* Send HTTP/2 client connection header, which includes 24 bytes
|
||||
@@ -626,6 +647,14 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr)
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
if(events & BEV_EVENT_CONNECTED) {
|
||||
fprintf(stderr, "%s connected\n", session_data->client_addr);
|
||||
|
||||
initialize_nghttp2_session(session_data);
|
||||
|
||||
if(send_server_connection_header(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if(events & BEV_EVENT_EOF) {
|
||||
@@ -638,38 +667,6 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr)
|
||||
delete_http2_session_data(session_data);
|
||||
}
|
||||
|
||||
/* readcb for bufferevent to check first 24 bytes client connection
|
||||
header. */
|
||||
static void handshake_readcb(struct bufferevent *bev, void *ptr)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
uint8_t data[24];
|
||||
struct evbuffer *input = bufferevent_get_input(session_data->bev);
|
||||
int readlen = evbuffer_remove(input, data, session_data->handshake_leftlen);
|
||||
const char *conhead = NGHTTP2_CLIENT_CONNECTION_PREFACE;
|
||||
|
||||
if(memcmp(conhead + NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
|
||||
- session_data->handshake_leftlen, data, readlen) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
session_data->handshake_leftlen -= readlen;
|
||||
if(session_data->handshake_leftlen == 0) {
|
||||
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, ptr);
|
||||
/* Process pending data in buffer since they are not notified
|
||||
further */
|
||||
initialize_nghttp2_session(session_data);
|
||||
if(send_server_connection_header(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
if(session_recv(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* callback for evconnlistener */
|
||||
static void acceptcb(struct evconnlistener *listener, int fd,
|
||||
struct sockaddr *addr, int addrlen, void *arg)
|
||||
@@ -678,8 +675,8 @@ static void acceptcb(struct evconnlistener *listener, int fd,
|
||||
http2_session_data *session_data;
|
||||
|
||||
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
|
||||
bufferevent_setcb(session_data->bev, handshake_readcb, NULL, eventcb,
|
||||
session_data);
|
||||
|
||||
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data);
|
||||
}
|
||||
|
||||
static void start_listen(struct event_base *evbase, const char *service,
|
||||
@@ -755,6 +752,8 @@ int main(int argc, char **argv)
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &act, NULL);
|
||||
|
||||
OPENSSL_config(NULL);
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
|
||||
1324
examples/tiny-nghttpd.c
Normal file
1324
examples/tiny-nghttpd.c
Normal file
File diff suppressed because it is too large
Load Diff
30
gendowncasetbl.py
Executable file
30
gendowncasetbl.py
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
|
||||
def name(i):
|
||||
if i < 0x20:
|
||||
return \
|
||||
['NUL ', 'SOH ', 'STX ', 'ETX ', 'EOT ', 'ENQ ', 'ACK ', 'BEL ',
|
||||
'BS ', 'HT ', 'LF ', 'VT ', 'FF ', 'CR ', 'SO ', 'SI ',
|
||||
'DLE ', 'DC1 ', 'DC2 ', 'DC3 ', 'DC4 ', 'NAK ', 'SYN ', 'ETB ',
|
||||
'CAN ', 'EM ', 'SUB ', 'ESC ', 'FS ', 'GS ', 'RS ', 'US '][i]
|
||||
elif i == 0x7f:
|
||||
return 'DEL '
|
||||
|
||||
for i in range(256):
|
||||
if chr(i) == ' ':
|
||||
sys.stdout.write('{} /* SPC */, '.format(i))
|
||||
elif chr(i) == '\t':
|
||||
sys.stdout.write('{} /* HT */, '.format(i))
|
||||
elif 'A' <= chr(i) and chr(i) <= 'Z':
|
||||
sys.stdout.write('{} /* {} */, '.format(i - ord('A') + ord('a'), chr(i)))
|
||||
elif (0x21 <= i and i < 0x7f):
|
||||
sys.stdout.write('{} /* {} */, '.format(i, chr(i)))
|
||||
elif 0x80 <= i:
|
||||
sys.stdout.write('{} /* {} */, '.format(i, hex(i)))
|
||||
elif 0 == i:
|
||||
sys.stdout.write('{} /* NUL */, '.format(i))
|
||||
else:
|
||||
sys.stdout.write('{} /* {} */, '.format(i, name(i)))
|
||||
if (i + 1)%4 == 0:
|
||||
sys.stdout.write('\n')
|
||||
0
gennmchartbl.py
Normal file → Executable file
0
gennmchartbl.py
Normal file → Executable file
0
genvchartbl.py
Normal file → Executable file
0
genvchartbl.py
Normal file → Executable file
@@ -22,6 +22,8 @@
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
SUBDIRS = includes
|
||||
|
||||
EXTRA_DIST = Makefile.msvc
|
||||
|
||||
AM_CFLAGS = -Wall
|
||||
AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes @DEFS@
|
||||
|
||||
@@ -41,7 +43,8 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
|
||||
nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c \
|
||||
nghttp2_version.c \
|
||||
nghttp2_priority_spec.c \
|
||||
nghttp2_option.c
|
||||
nghttp2_option.c \
|
||||
nghttp2_callbacks.c
|
||||
|
||||
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
||||
nghttp2_frame.h \
|
||||
@@ -52,7 +55,8 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
||||
nghttp2_net.h \
|
||||
nghttp2_hd.h nghttp2_hd_huffman.h \
|
||||
nghttp2_priority_spec.h \
|
||||
nghttp2_option.h
|
||||
nghttp2_option.h \
|
||||
nghttp2_callbacks.h
|
||||
|
||||
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
|
||||
libnghttp2_la_LDFLAGS = -no-undefined \
|
||||
|
||||
266
lib/Makefile.msvc
Normal file
266
lib/Makefile.msvc
Normal file
@@ -0,0 +1,266 @@
|
||||
#
|
||||
# GNU Makefile for nghttp2 / MSVC.
|
||||
#
|
||||
# By G. Vanem <gvanem@yahoo.no> 2013
|
||||
# The MIT License apply.
|
||||
#
|
||||
|
||||
#
|
||||
# Choose your weapons:
|
||||
# Set 'ZLIB_ROOT' to the root of zlib.
|
||||
# Set 'USE_CYTHON=1' to build and install the 'nghttp2.pyd' Python extension.
|
||||
#
|
||||
ZLIB_ROOT = g:/MingW32/src/Compression/zlib-1.2.8
|
||||
USE_CYTHON = 1
|
||||
|
||||
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV], //g')
|
||||
_VERSION := $(subst ., ,$(_VERSION))
|
||||
VER_MAJOR = $(word 1,$(_VERSION))
|
||||
VER_MINOR = $(word 2,$(_VERSION))
|
||||
VER_MICRO = $(word 3,$(_VERSION))
|
||||
VERSION = $(VER_MAJOR).$(VER_MINOR).$(VER_MICRO)
|
||||
VERSION_NUM = ($(VER_MAJOR) << 16) + ($(VER_MINOR) << 8) + $(VER_MICRO)
|
||||
|
||||
GENERATED = 'Generated by $(realpath Makefile.MSVC)'
|
||||
|
||||
#
|
||||
# Where to copy nghttp2.dll + lib + headers to.
|
||||
# Note: 'make install' is not in default targets. Do it explicitly.
|
||||
#
|
||||
VC_ROOT = $(realpath $(VCINSTALLDIR))
|
||||
INSTALL_BIN = $(VC_ROOT)/bin
|
||||
INSTALL_LIB = $(VC_ROOT)/lib
|
||||
INSTALL_HDR = $(VC_ROOT)/include
|
||||
|
||||
#
|
||||
# Build for DEBUG-model and RELEASE at the same time.
|
||||
#
|
||||
TARGETS = nghttp2.lib nghttp2.dll nghttp2_imp.lib \
|
||||
nghttp2d.lib nghttp2d.dll nghttp2d_imp.lib
|
||||
|
||||
EXT_LIBS = $(ZLIB_ROOT)/zlib.lib ws2_32.lib
|
||||
|
||||
OBJ_DIR = MSVC_obj
|
||||
|
||||
NGHTTP2_PDB_R = $(OBJ_DIR)/nghttp2.pdb
|
||||
NGHTTP2_PDB_D = $(OBJ_DIR)/nghttp2d.pdb
|
||||
|
||||
CC = cl
|
||||
CFLAGS = -I./includes -I$(ZLIB_ROOT) -DHAVE_WINSOCK2_H -Dssize_t=long
|
||||
|
||||
CFLAGS_R = -nologo -MD -W3 -Zi -Fd./$(NGHTTP2_PDB_R)
|
||||
CFLAGS_D = -nologo -MDd -W3 -Zi -Fd./$(NGHTTP2_PDB_D) \
|
||||
-Ot -D_DEBUG -GF -RTCs -RTCu # -RTCc -GS
|
||||
|
||||
LDFLAGS = -nologo -machine:i386 -map -debug -incremental:no # -verbose
|
||||
|
||||
NGHTTP2_SRC = nghttp2_buf.c \
|
||||
nghttp2_callbacks.c \
|
||||
nghttp2_frame.c \
|
||||
nghttp2_helper.c \
|
||||
nghttp2_hd.c \
|
||||
nghttp2_hd_huffman.c \
|
||||
nghttp2_hd_huffman_data.c \
|
||||
nghttp2_map.c \
|
||||
nghttp2_npn.c \
|
||||
nghttp2_option.c \
|
||||
nghttp2_outbound_item.c \
|
||||
nghttp2_priority_spec.c \
|
||||
nghttp2_pq.c \
|
||||
nghttp2_queue.c \
|
||||
nghttp2_session.c \
|
||||
nghttp2_stream.c \
|
||||
nghttp2_submit.c \
|
||||
nghttp2_version.c
|
||||
|
||||
NGHTTP2_OBJ_R = $(addprefix $(OBJ_DIR)/r_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
||||
NGHTTP2_OBJ_D = $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
||||
|
||||
all: intro $(OBJ_DIR) $(TARGETS)
|
||||
@echo 'Welcome to NgHTTP2 (release + debug).'
|
||||
@echo 'Do a "make -f Makefile.MSVC install" at own risk!'
|
||||
|
||||
intro:
|
||||
@echo 'Building NgHTTP (MSVC) ver. "$(VERSION)".'
|
||||
|
||||
test_ver:
|
||||
@echo '$$(VERSION): "$(VERSION)".'
|
||||
@echo '$$(_VERSION): "$(_VERSION)".'
|
||||
@echo '$$(VER_MAJOR): "$(VER_MAJOR)".'
|
||||
@echo '$$(VER_MINOR): "$(VER_MINOR)".'
|
||||
@echo '$$(VER_MICRO): "$(VER_MICRO)".'
|
||||
|
||||
$(OBJ_DIR):
|
||||
- mkdir $(OBJ_DIR)
|
||||
|
||||
install: includes/nghttp2/nghttp2.h includes/nghttp2/nghttp2ver.h \
|
||||
nghttp2.dll nghttp2.lib nghttp2_imp.lib \
|
||||
nghttp2d.dll nghttp2d.lib nghttp2d_imp.lib \
|
||||
copy_headers_and_libs install_nghttp2_pyd_$(USE_CYTHON)
|
||||
|
||||
#
|
||||
# This MUST be done before using the 'install_nghttp2_pyd_1' rule.
|
||||
#
|
||||
copy_headers_and_libs:
|
||||
- mkdir $(INSTALL_HDR)/nghttp2
|
||||
cp --update $(addprefix includes/nghttp2/, nghttp2.h nghttp2ver.h) $(INSTALL_HDR)/nghttp2
|
||||
cp --update nghttp2.dll nghttp2d.dll $(NGHTTP2_PDB_R) $(NGHTTP2_PDB_D) $(INSTALL_BIN)
|
||||
cp --update nghttp2.lib nghttp2d.lib nghttp2_imp.lib nghttp2d_imp.lib $(INSTALL_LIB)
|
||||
@echo
|
||||
|
||||
nghttp2.lib: $(NGHTTP2_OBJ_R)
|
||||
lib -nologo -out:$@ $^
|
||||
@echo
|
||||
|
||||
nghttp2d.lib: $(NGHTTP2_OBJ_D)
|
||||
lib -nologo -out:$@ $^
|
||||
@echo
|
||||
|
||||
nghttp2.dll nghttp2_imp.lib: $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(OBJ_DIR)/r_nghttp2.def
|
||||
link $(LDFLAGS) -dll -out:nghttp2.dll -implib:nghttp2_imp.lib -def:$(OBJ_DIR)/r_nghttp2.def \
|
||||
$(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(EXT_LIBS)
|
||||
@echo
|
||||
|
||||
nghttp2d.dll nghttp2d_imp.lib: $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(OBJ_DIR)/d_nghttp2.def
|
||||
link $(LDFLAGS) -dll -out:nghttp2d.dll -implib:nghttp2d_imp.lib -def:$(OBJ_DIR)/d_nghttp2.def \
|
||||
$(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(EXT_LIBS)
|
||||
@echo
|
||||
|
||||
install_nghttp2_pyd_0: ;
|
||||
|
||||
install_nghttp2_pyd_1: $(addprefix ../python/, setup.py.in nghttp2.pyx)
|
||||
cd ../python ; \
|
||||
echo '# $(GENERATED). DO NOT EDIT.' > setup.py ; \
|
||||
sed -e 's/@top_srcdir@/../' \
|
||||
-e 's/@top_builddir@/../' \
|
||||
-e 's/@PACKAGE_VERSION@/$(VERSION)/' setup.py.in >> setup.py ; \
|
||||
cython -v nghttp2.pyx ; \
|
||||
python setup.py install
|
||||
|
||||
clean_nghttp2_pyd_0: ;
|
||||
|
||||
clean_nghttp2_pyd_1:
|
||||
cd ../python ; \
|
||||
rm -f setup.py nghttp2.c ; \
|
||||
rm -fR build/*
|
||||
|
||||
$(OBJ_DIR)/r_%.obj: %.c
|
||||
$(CC) $(CFLAGS_R) $(CFLAGS) -Fo$@ -c $<
|
||||
@echo
|
||||
|
||||
$(OBJ_DIR)/d_%.obj: %.c
|
||||
$(CC) $(CFLAGS_D) $(CFLAGS) -Fo$@ -c $<
|
||||
@echo
|
||||
|
||||
$(OBJ_DIR)/r_nghttp2.res: nghttp2.rc
|
||||
rc -nologo -D_RELEASE -Fo $@ $<
|
||||
@echo
|
||||
|
||||
$(OBJ_DIR)/d_nghttp2.res: nghttp2.rc
|
||||
rc -nologo -D_DEBUG -Fo $@ $<
|
||||
@echo
|
||||
|
||||
includes/nghttp2/nghttp2ver.h: includes/nghttp2/nghttp2ver.h.in
|
||||
sed < includes/nghttp2/nghttp2ver.h.in \
|
||||
-e 's/@PACKAGE_VERSION@/$(VERSION)/g' \
|
||||
-e 's/@PACKAGE_VERSION_NUM@/($(VERSION_NUM))/g' > $@
|
||||
touch --reference=includes/nghttp2/nghttp2ver.h.in $@
|
||||
|
||||
|
||||
define RES_FILE
|
||||
#include <winver.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION $(VER_MAJOR), $(VER_MINOR), $(VER_MICRO), 0
|
||||
PRODUCTVERSION $(VER_MAJOR), $(VER_MINOR), $(VER_MICRO), 0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
#ifdef _DEBUG
|
||||
#define VER_STR "$(VERSION).0 (MSVC debug)"
|
||||
#define DBG "d"
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
#define VER_STR "$(VERSION).0 (MSVC release)"
|
||||
#define DBG ""
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "http://tatsuhiro-t.github.io/nghttp2/"
|
||||
VALUE "FileDescription", "nghttp2; HTTP/2 C library"
|
||||
VALUE "FileVersion", VER_STR
|
||||
VALUE "InternalName", "nghttp2" DBG
|
||||
VALUE "LegalCopyright", "The MIT License"
|
||||
VALUE "LegalTrademarks", ""
|
||||
VALUE "OriginalFilename", "nghttp2" DBG ".dll"
|
||||
VALUE "ProductName", "NGHTTP2."
|
||||
VALUE "ProductVersion", VER_STR
|
||||
VALUE "PrivateBuild", "The privat build of <gvanem@yahoo.no>."
|
||||
VALUE "SpecialBuild", ""
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
endef
|
||||
|
||||
export RES_FILE
|
||||
|
||||
nghttp2.rc: Makefile.MSVC
|
||||
@echo 'Generating $@...'
|
||||
@echo ' /* $(GENERATED). DO NOT EDIT.' > $@
|
||||
@echo ' */' >> $@
|
||||
@echo "$$RES_FILE" >> $@
|
||||
|
||||
$(OBJ_DIR)/r_nghttp2.def: Makefile.MSVC
|
||||
@echo 'Generating $@...'
|
||||
@echo '; $(GENERATED). DO NOT EDIT.' > $@
|
||||
@echo ';' >> $@
|
||||
@echo 'LIBRARY nghttp2.dll' >> $@
|
||||
@echo 'EXPORTS' >> $@
|
||||
nm $(NGHTTP2_OBJ_R) | grep ' T .*_nghttp2' | sed 's/^.* _/ /' >> $@
|
||||
@echo 'NGHTTP2_STATIC_TABLE_LENGTH DATA' >> $@
|
||||
|
||||
$(OBJ_DIR)/d_nghttp2.def: Makefile.MSVC
|
||||
@echo 'Generating $@...'
|
||||
@echo '; $(GENERATED). DO NOT EDIT.' > $@
|
||||
@echo ';' >> $@
|
||||
@echo 'LIBRARY nghttp2d.dll' >> $@
|
||||
@echo 'EXPORTS' >> $@
|
||||
nm $(NGHTTP2_OBJ_D) | grep ' T .*_nghttp2' | sed 's/^.* _/ /' >> $@
|
||||
@echo 'NGHTTP2_STATIC_TABLE_LENGTH DATA' >> $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ_DIR)/* nghttp2_imp.exp nghttp2_imp.exp \
|
||||
nghttp2.map nghttp2d.map nghttp2.rc includes/nghttp2/nghttp2ver.h
|
||||
@echo
|
||||
|
||||
vclean realclean: clean clean_nghttp2_pyd_$(USE_CYTHON)
|
||||
rm -f $(TARGETS) nghttp2.pdb nghttp2d.pdb nghttp2_imp.exp nghttp2d_imp.exp .depend.MSVC
|
||||
- rmdir $(OBJ_DIR)
|
||||
|
||||
#
|
||||
# Use gcc to generated the dependencies. No MSVC specific args please!
|
||||
#
|
||||
REPLACE_R = 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/r_\1.obj: /'
|
||||
REPLACE_D = 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/d_\1.obj: /'
|
||||
|
||||
depend: includes/nghttp2/nghttp2ver.h
|
||||
@echo '# $(GENERATED). DO NOT EDIT.' > .depend.MSVC
|
||||
gcc -MM $(CFLAGS) $(NGHTTP2_SRC) >> .depend.tmp
|
||||
@echo '#' >> .depend.MSVC
|
||||
@echo '# Release lib objects:' >> .depend.MSVC
|
||||
sed -e $(REPLACE_R) .depend.tmp >> .depend.MSVC
|
||||
@echo '#' >> .depend.MSVC
|
||||
@echo '# Debug lib objects:' >> .depend.MSVC
|
||||
sed -e $(REPLACE_D) .depend.tmp >> .depend.MSVC
|
||||
rm -f .depend.tmp
|
||||
|
||||
-include .depend.MSVC
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,12 @@ int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial)
|
||||
|
||||
void nghttp2_buf_free(nghttp2_buf *buf)
|
||||
{
|
||||
if(buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(buf->begin);
|
||||
buf->begin = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
|
||||
@@ -75,16 +80,6 @@ int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap)
|
||||
{
|
||||
return nghttp2_buf_reserve(buf, nghttp2_buf_pos_offset(buf) + new_rel_cap);
|
||||
}
|
||||
|
||||
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap)
|
||||
{
|
||||
return nghttp2_buf_reserve(buf, nghttp2_buf_last_offset(buf) + new_rel_cap);
|
||||
}
|
||||
|
||||
void nghttp2_buf_reset(nghttp2_buf *buf)
|
||||
{
|
||||
buf->pos = buf->last = buf->mark = buf->begin;
|
||||
@@ -164,10 +159,41 @@ int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
if(chunk_length < bufs->offset) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
rv = buf_chain_new(&chain, chunk_length);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nghttp2_bufs_free(bufs);
|
||||
|
||||
bufs->head = chain;
|
||||
bufs->cur = bufs->head;
|
||||
|
||||
nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
|
||||
|
||||
bufs->chunk_length = chunk_length;
|
||||
bufs->chunk_used = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_free(nghttp2_bufs *bufs)
|
||||
{
|
||||
nghttp2_buf_chain *chain, *next_chain;
|
||||
|
||||
if(bufs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(chain = bufs->head; chain;) {
|
||||
next_chain = chain->next;
|
||||
|
||||
@@ -175,6 +201,8 @@ void nghttp2_bufs_free(nghttp2_bufs *bufs)
|
||||
|
||||
chain = next_chain;
|
||||
}
|
||||
|
||||
bufs->head = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len)
|
||||
@@ -205,7 +233,12 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len)
|
||||
|
||||
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs)
|
||||
{
|
||||
if(bufs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(bufs->head);
|
||||
bufs->head = NULL;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs)
|
||||
@@ -236,8 +269,8 @@ ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs)
|
||||
|
||||
static ssize_t bufs_avail(nghttp2_bufs *bufs)
|
||||
{
|
||||
return (ssize_t)nghttp2_buf_avail(&bufs->cur->buf) +
|
||||
(bufs->chunk_length - bufs->offset) * (bufs->max_chunk - bufs->chunk_used);
|
||||
return (ssize_t)(nghttp2_buf_avail(&bufs->cur->buf) +
|
||||
(bufs->chunk_length - bufs->offset) * (bufs->max_chunk - bufs->chunk_used));
|
||||
}
|
||||
|
||||
static int bufs_alloc_chain(nghttp2_bufs *bufs)
|
||||
|
||||
@@ -107,22 +107,6 @@ void nghttp2_buf_free(nghttp2_buf *buf);
|
||||
*/
|
||||
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap);
|
||||
|
||||
/*
|
||||
* This function behaves like nghttp2_buf_reserve(), but new capacity
|
||||
* is calculated as nghttp2_buf_pos_offset(buf) + new_rel_cap. In
|
||||
* other words, this function reserves memory at least |new_rel_cap|
|
||||
* bytes from buf->pos.
|
||||
*/
|
||||
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap);
|
||||
|
||||
/*
|
||||
* This function behaves like nghttp2_buf_reserve(), but new capacity
|
||||
* is calculated as nghttp2_buf_last_offset(buf) + new_rel_cap. In
|
||||
* other words, this function reserves memory at least |new_rel_cap|
|
||||
* bytes from buf->last.
|
||||
*/
|
||||
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap);
|
||||
|
||||
/*
|
||||
* Resets pos, last, mark member of |buf| to buf->begin.
|
||||
*/
|
||||
@@ -228,6 +212,22 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len);
|
||||
*/
|
||||
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs);
|
||||
|
||||
/*
|
||||
* Reallocates internal buffer using |chunk_length|. The max_chunk,
|
||||
* chunk_keep and offset do not change. After successful allocation
|
||||
* of new buffer, previous buffers are deallocated without copying
|
||||
* anything into new buffers. chunk_used is reset to 1.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* chunk_length < offset
|
||||
*/
|
||||
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length);
|
||||
|
||||
/*
|
||||
* Appends the |data| of length |len| to the |bufs|. The write starts
|
||||
* at bufs->cur->buf.last. A new buffers will be allocated to store
|
||||
|
||||
139
lib/nghttp2_callbacks.c
Normal file
139
lib/nghttp2_callbacks.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_callbacks.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr)
|
||||
{
|
||||
*callbacks_ptr = calloc(1, sizeof(nghttp2_session_callbacks));
|
||||
|
||||
if(*callbacks_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks)
|
||||
{
|
||||
free(callbacks);
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_send_callback
|
||||
(nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback)
|
||||
{
|
||||
cbs->send_callback = send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_recv_callback
|
||||
(nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback)
|
||||
{
|
||||
cbs->recv_callback = recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback)
|
||||
{
|
||||
cbs->on_frame_recv_callback = on_frame_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback)
|
||||
{
|
||||
cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback)
|
||||
{
|
||||
cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_before_frame_send_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback)
|
||||
{
|
||||
cbs->before_frame_send_callback = before_frame_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_send_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback)
|
||||
{
|
||||
cbs->on_frame_send_callback = on_frame_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_not_send_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback)
|
||||
{
|
||||
cbs->on_frame_not_send_callback = on_frame_not_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback)
|
||||
{
|
||||
cbs->on_stream_close_callback = on_stream_close_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback)
|
||||
{
|
||||
cbs->on_begin_headers_callback = on_begin_headers_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_header_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback on_header_callback)
|
||||
{
|
||||
cbs->on_header_callback = on_header_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_select_padding_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_select_padding_callback select_padding_callback)
|
||||
{
|
||||
cbs->select_padding_callback = select_padding_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_data_source_read_length_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_data_source_read_length_callback data_source_read_length_callback)
|
||||
{
|
||||
cbs->read_length_callback = data_source_read_length_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_frame_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback)
|
||||
{
|
||||
cbs->on_begin_frame_callback = on_begin_frame_callback;
|
||||
}
|
||||
111
lib/nghttp2_callbacks.h
Normal file
111
lib/nghttp2_callbacks.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_CALLBACKS_H
|
||||
#define NGHTTP2_CALLBACKS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/*
|
||||
* Callback functions.
|
||||
*/
|
||||
struct nghttp2_session_callbacks {
|
||||
/**
|
||||
* Callback function invoked when the session wants to send data to
|
||||
* the remote peer. This callback is not necessary if the
|
||||
* application uses solely `nghttp2_session_mem_send()` to serialize
|
||||
* data to transmit.
|
||||
*/
|
||||
nghttp2_send_callback send_callback;
|
||||
/**
|
||||
* Callback function invoked when the session wants to receive data
|
||||
* from the remote peer. This callback is not necessary if the
|
||||
* application uses solely `nghttp2_session_mem_recv()` to process
|
||||
* received data.
|
||||
*/
|
||||
nghttp2_recv_callback recv_callback;
|
||||
/**
|
||||
* Callback function invoked by `nghttp2_session_recv()` when a
|
||||
* frame is received.
|
||||
*/
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback;
|
||||
/**
|
||||
* Callback function invoked by `nghttp2_session_recv()` when an
|
||||
* invalid non-DATA frame is received.
|
||||
*/
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback;
|
||||
/**
|
||||
* Callback function invoked when a chunk of data in DATA frame is
|
||||
* received.
|
||||
*/
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback;
|
||||
/**
|
||||
* Callback function invoked before a non-DATA frame is sent.
|
||||
*/
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback;
|
||||
/**
|
||||
* Callback function invoked after a frame is sent.
|
||||
*/
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback;
|
||||
/**
|
||||
* The callback function invoked when a non-DATA frame is not sent
|
||||
* because of an error.
|
||||
*/
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback;
|
||||
/**
|
||||
* Callback function invoked when the stream is closed.
|
||||
*/
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback;
|
||||
/**
|
||||
* Callback function invoked when the reception of header block in
|
||||
* HEADERS or PUSH_PROMISE is started.
|
||||
*/
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback;
|
||||
/**
|
||||
* Callback function invoked when a header name/value pair is
|
||||
* received.
|
||||
*/
|
||||
nghttp2_on_header_callback on_header_callback;
|
||||
/**
|
||||
* Callback function invoked when the library asks application how
|
||||
* many padding bytes are required for the transmission of the given
|
||||
* frame.
|
||||
*/
|
||||
nghttp2_select_padding_callback select_padding_callback;
|
||||
/**
|
||||
* The callback function used to determine the length allowed in
|
||||
* `nghttp2_data_source_read_callback()`
|
||||
*/
|
||||
nghttp2_data_source_read_length_callback read_length_callback;
|
||||
/**
|
||||
* Sets callback function invoked when a frame header is received.
|
||||
*/
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback;
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_CALLBACKS_H */
|
||||
@@ -33,35 +33,33 @@
|
||||
#include "nghttp2_net.h"
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
int nghttp2_frame_is_data_frame(uint8_t *head)
|
||||
{
|
||||
return head[2] == 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_pack_frame_hd(uint8_t* buf, const nghttp2_frame_hd *hd)
|
||||
{
|
||||
nghttp2_put_uint16be(&buf[0], hd->length);
|
||||
buf[2]= hd->type;
|
||||
buf[3] = hd->flags;
|
||||
nghttp2_put_uint32be(&buf[4], hd->stream_id);
|
||||
nghttp2_put_uint32be(&buf[0], (uint32_t)(hd->length << 8));
|
||||
buf[3]= hd->type;
|
||||
buf[4] = hd->flags;
|
||||
nghttp2_put_uint32be(&buf[5], hd->stream_id);
|
||||
/* ignore hd->reserved for now */
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf)
|
||||
{
|
||||
hd->length = nghttp2_get_uint16(&buf[0]) & NGHTTP2_FRAME_LENGTH_MASK;
|
||||
hd->type = buf[2];
|
||||
hd->flags = buf[3];
|
||||
hd->stream_id = nghttp2_get_uint32(&buf[4]) & NGHTTP2_STREAM_ID_MASK;
|
||||
hd->length = nghttp2_get_uint32(&buf[0]) >> 8;
|
||||
hd->type = buf[3];
|
||||
hd->flags = buf[4];
|
||||
hd->stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK;
|
||||
hd->reserved = 0;
|
||||
}
|
||||
|
||||
static void frame_set_hd(nghttp2_frame_hd *hd, uint16_t length,
|
||||
uint8_t type, uint8_t flags,
|
||||
int32_t stream_id)
|
||||
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length,
|
||||
uint8_t type, uint8_t flags,
|
||||
int32_t stream_id)
|
||||
{
|
||||
hd->length = length;
|
||||
hd->type = type;
|
||||
hd->flags = flags;
|
||||
hd->stream_id = stream_id;
|
||||
hd->reserved = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_headers_init(nghttp2_headers *frame,
|
||||
@@ -70,7 +68,7 @@ void nghttp2_frame_headers_init(nghttp2_headers *frame,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
frame_set_hd(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id);
|
||||
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id);
|
||||
frame->padlen = 0;
|
||||
frame->nva = nva;
|
||||
frame->nvlen = nvlen;
|
||||
@@ -91,8 +89,8 @@ void nghttp2_frame_headers_free(nghttp2_headers *frame)
|
||||
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
frame_set_hd(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY,
|
||||
NGHTTP2_FLAG_NONE, stream_id);
|
||||
nghttp2_frame_hd_init(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY,
|
||||
NGHTTP2_FLAG_NONE, stream_id);
|
||||
frame->pri_spec = *pri_spec;
|
||||
}
|
||||
|
||||
@@ -101,10 +99,10 @@ void nghttp2_frame_priority_free(nghttp2_priority *frame)
|
||||
|
||||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame,
|
||||
int32_t stream_id,
|
||||
nghttp2_error_code error_code)
|
||||
uint32_t error_code)
|
||||
{
|
||||
frame_set_hd(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE,
|
||||
stream_id);
|
||||
nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE,
|
||||
stream_id);
|
||||
frame->error_code = error_code;
|
||||
}
|
||||
|
||||
@@ -115,8 +113,8 @@ void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame)
|
||||
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
|
||||
nghttp2_settings_entry *iv, size_t niv)
|
||||
{
|
||||
frame_set_hd(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
|
||||
NGHTTP2_SETTINGS, flags, 0);
|
||||
nghttp2_frame_hd_init(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
|
||||
NGHTTP2_SETTINGS, flags, 0);
|
||||
frame->niv = niv;
|
||||
frame->iv = iv;
|
||||
}
|
||||
@@ -131,11 +129,12 @@ void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame,
|
||||
int32_t promised_stream_id,
|
||||
nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
frame_set_hd(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id);
|
||||
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id);
|
||||
frame->padlen = 0;
|
||||
frame->nva = nva;
|
||||
frame->nvlen = nvlen;
|
||||
frame->promised_stream_id = promised_stream_id;
|
||||
frame->reserved = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame)
|
||||
@@ -146,7 +145,7 @@ void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame)
|
||||
void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
|
||||
const uint8_t *opaque_data)
|
||||
{
|
||||
frame_set_hd(&frame->hd, 8, NGHTTP2_PING, flags, 0);
|
||||
nghttp2_frame_hd_init(&frame->hd, 8, NGHTTP2_PING, flags, 0);
|
||||
if(opaque_data) {
|
||||
memcpy(frame->opaque_data, opaque_data, sizeof(frame->opaque_data));
|
||||
} else {
|
||||
@@ -158,15 +157,16 @@ void nghttp2_frame_ping_free(nghttp2_ping *frame)
|
||||
{}
|
||||
|
||||
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
|
||||
nghttp2_error_code error_code,
|
||||
uint32_t error_code,
|
||||
uint8_t *opaque_data, size_t opaque_data_len)
|
||||
{
|
||||
frame_set_hd(&frame->hd, 8+opaque_data_len, NGHTTP2_GOAWAY,
|
||||
NGHTTP2_FLAG_NONE, 0);
|
||||
nghttp2_frame_hd_init(&frame->hd, 8+opaque_data_len, NGHTTP2_GOAWAY,
|
||||
NGHTTP2_FLAG_NONE, 0);
|
||||
frame->last_stream_id = last_stream_id;
|
||||
frame->error_code = error_code;
|
||||
frame->opaque_data = opaque_data;
|
||||
frame->opaque_data_len = opaque_data_len;
|
||||
frame->reserved = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_goaway_free(nghttp2_goaway *frame)
|
||||
@@ -179,8 +179,10 @@ void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
|
||||
int32_t stream_id,
|
||||
int32_t window_size_increment)
|
||||
{
|
||||
frame_set_hd(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags, stream_id);
|
||||
nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags,
|
||||
stream_id);
|
||||
frame->window_size_increment = window_size_increment;
|
||||
frame->reserved = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame)
|
||||
@@ -201,8 +203,8 @@ void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||
|
||||
payloadlen = NGHTTP2_ALTSVC_MINLEN + protocol_id_len + host_len + origin_len;
|
||||
|
||||
frame_set_hd(&frame->hd, payloadlen, NGHTTP2_EXT_ALTSVC, NGHTTP2_FLAG_NONE,
|
||||
stream_id);
|
||||
nghttp2_frame_hd_init(&frame->hd, payloadlen, NGHTTP2_EXT_ALTSVC,
|
||||
NGHTTP2_FLAG_NONE, stream_id);
|
||||
|
||||
altsvc->max_age = max_age;
|
||||
altsvc->port = port;
|
||||
@@ -227,36 +229,20 @@ void nghttp2_frame_altsvc_free(nghttp2_extension *frame)
|
||||
free(altsvc->protocol_id);
|
||||
}
|
||||
|
||||
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata)
|
||||
{
|
||||
frame->hd = pdata->hd;
|
||||
frame->padlen = pdata->padlen;
|
||||
/* flags may have NGHTTP2_FLAG_END_STREAM or
|
||||
NGHTTP2_FLAG_END_SEGMENT even if the sent chunk is not the end of
|
||||
the stream */
|
||||
if(!pdata->eof) {
|
||||
frame->hd.flags &= ~(NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT);
|
||||
}
|
||||
}
|
||||
|
||||
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen)
|
||||
{
|
||||
return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0);
|
||||
}
|
||||
|
||||
void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_data_provider *data_prd)
|
||||
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
|
||||
int32_t stream_id)
|
||||
{
|
||||
/* At this moment, the length of DATA frame is unknown */
|
||||
frame_set_hd(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id);
|
||||
frame->data_prd = *data_prd;
|
||||
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id);
|
||||
frame->padlen = 0;
|
||||
frame->eof = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_private_data_free(nghttp2_private_data *frame)
|
||||
void nghttp2_frame_data_free(nghttp2_data *frame)
|
||||
{}
|
||||
|
||||
size_t nghttp2_frame_priority_len(uint8_t flags)
|
||||
@@ -478,33 +464,11 @@ int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static nghttp2_error_code normalize_error_code(uint32_t error_code)
|
||||
{
|
||||
switch(error_code) {
|
||||
case NGHTTP2_NO_ERROR:
|
||||
case NGHTTP2_PROTOCOL_ERROR:
|
||||
case NGHTTP2_INTERNAL_ERROR:
|
||||
case NGHTTP2_FLOW_CONTROL_ERROR:
|
||||
case NGHTTP2_SETTINGS_TIMEOUT:
|
||||
case NGHTTP2_STREAM_CLOSED:
|
||||
case NGHTTP2_FRAME_SIZE_ERROR:
|
||||
case NGHTTP2_REFUSED_STREAM:
|
||||
case NGHTTP2_CANCEL:
|
||||
case NGHTTP2_COMPRESSION_ERROR:
|
||||
case NGHTTP2_CONNECT_ERROR:
|
||||
case NGHTTP2_ENHANCE_YOUR_CALM:
|
||||
case NGHTTP2_INADEQUATE_SECURITY:
|
||||
return error_code;
|
||||
default:
|
||||
return NGHTTP2_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen)
|
||||
{
|
||||
frame->error_code = normalize_error_code(nghttp2_get_uint32(payload));
|
||||
frame->error_code = nghttp2_get_uint32(payload);
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame)
|
||||
@@ -713,7 +677,7 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
|
||||
size_t var_gift_payloadlen)
|
||||
{
|
||||
frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
|
||||
frame->error_code = normalize_error_code(nghttp2_get_uint32(payload + 4));
|
||||
frame->error_code = nghttp2_get_uint32(payload + 4);
|
||||
|
||||
frame->opaque_data = var_gift_payload;
|
||||
frame->opaque_data_len = var_gift_payloadlen;
|
||||
@@ -1037,8 +1001,14 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
|
||||
if(iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
|
||||
iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
@@ -1047,6 +1017,7 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
|
||||
static void frame_set_pad(nghttp2_buf *buf, size_t padlen)
|
||||
{
|
||||
size_t trail_padlen;
|
||||
size_t newlen;
|
||||
|
||||
DEBUGF(fprintf(stderr, "send: padlen=%zu, shift left 1 bytes\n", padlen));
|
||||
|
||||
@@ -1054,9 +1025,10 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen)
|
||||
|
||||
--buf->pos;
|
||||
|
||||
buf->pos[3] |= NGHTTP2_FLAG_PADDED;
|
||||
buf->pos[4] |= NGHTTP2_FLAG_PADDED;
|
||||
|
||||
nghttp2_put_uint16be(buf->pos, nghttp2_get_uint16(buf->pos) + padlen);
|
||||
newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen;
|
||||
nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3]));
|
||||
|
||||
trail_padlen = padlen - 1;
|
||||
buf->pos[NGHTTP2_FRAME_HDLEN] = trail_padlen;
|
||||
@@ -1087,12 +1059,12 @@ int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | |Frame header | Frame payload... :
|
||||
* +-+---------------+---------------------------------------------+
|
||||
* | |Frame header | Frame payload... :
|
||||
* +-+---------------+---------------------------------------------+
|
||||
* | |Frame header | Frame payload... :
|
||||
* +-+---------------+---------------------------------------------+
|
||||
* | |Frame header | Frame payload... :
|
||||
* +-+-----------------+-------------------------------------------+
|
||||
* | |Frame header | Frame payload... :
|
||||
* +-+-----------------+-------------------------------------------+
|
||||
* | |Frame header | Frame payload... :
|
||||
* +-+-----------------+-------------------------------------------+
|
||||
*
|
||||
* We arranged padding so that it is included in the first frame
|
||||
* completely. For padded frame, we are going to adjust buf->pos of
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_buf.h"
|
||||
|
||||
#define NGHTTP2_FRAME_LENGTH_MASK ((1 << 14) - 1)
|
||||
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
|
||||
@@ -41,9 +40,12 @@
|
||||
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
|
||||
|
||||
/* The number of bytes of frame header. */
|
||||
#define NGHTTP2_FRAME_HDLEN 8
|
||||
#define NGHTTP2_FRAME_HDLEN 9
|
||||
|
||||
#define NGHTTP2_MAX_PAYLOADLEN 16383
|
||||
#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1)
|
||||
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
|
||||
|
||||
#define NGHTTP2_MAX_PAYLOADLEN 16384
|
||||
/* The one frame buffer length for tranmission. We may use several of
|
||||
them to support CONTINUATION. To account for Pad Length field, we
|
||||
allocate extra 1 byte, which saves extra large memcopying. */
|
||||
@@ -53,11 +55,12 @@
|
||||
/* Number of inbound buffer */
|
||||
#define NGHTTP2_FRAMEBUF_MAX_NUM 5
|
||||
|
||||
/* The maximum length of DATA frame payload. */
|
||||
#define NGHTTP2_DATA_PAYLOADLEN 4096
|
||||
/* The default length of DATA frame payload. This should be small enough
|
||||
* for the data payload and the header to fit into 1 TLS record */
|
||||
#define NGHTTP2_DATA_PAYLOADLEN ((NGHTTP2_MAX_FRAME_SIZE_MIN) - (NGHTTP2_FRAME_HDLEN))
|
||||
|
||||
/* Maximum headers payload length, calculated in compressed form.
|
||||
This applies to both transmission and reception. */
|
||||
This applies to transmission only. */
|
||||
#define NGHTTP2_MAX_HEADERSLEN 65536
|
||||
|
||||
/* The number of bytes for each SETTINGS entry */
|
||||
@@ -77,50 +80,26 @@
|
||||
NGHTTP2_ALTSVC_FIXED_PARTLEN + Host-Len. */
|
||||
#define NGHTTP2_ALTSVC_MINLEN 8
|
||||
|
||||
/* Category of frames. */
|
||||
typedef enum {
|
||||
/* non-DATA frame */
|
||||
NGHTTP2_CAT_CTRL,
|
||||
/* DATA frame */
|
||||
NGHTTP2_CAT_DATA
|
||||
} nghttp2_frame_category;
|
||||
/* Maximum length of padding in bytes. */
|
||||
#define NGHTTP2_MAX_PADLEN 256
|
||||
|
||||
/* Union of extension frame payload */
|
||||
typedef union {
|
||||
nghttp2_ext_altsvc altsvc;
|
||||
} nghttp2_ext_frame_payload;
|
||||
|
||||
/**
|
||||
* @struct
|
||||
*
|
||||
* The DATA frame used in the library privately. It has the following
|
||||
* members:
|
||||
*/
|
||||
typedef struct {
|
||||
nghttp2_frame_hd hd;
|
||||
/**
|
||||
* The data to be sent for this DATA frame.
|
||||
*/
|
||||
nghttp2_data_provider data_prd;
|
||||
/**
|
||||
* The number of bytes added as padding. This includes Pad Length
|
||||
* field (1 byte).
|
||||
*/
|
||||
size_t padlen;
|
||||
/**
|
||||
* The flag to indicate whether EOF was reached or not. Initially
|
||||
* |eof| is 0. It becomes 1 after all data were read. This is used
|
||||
* exclusively by nghttp2 library and not in the spec.
|
||||
*/
|
||||
uint8_t eof;
|
||||
} nghttp2_private_data;
|
||||
|
||||
int nghttp2_frame_is_data_frame(uint8_t *head);
|
||||
|
||||
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
||||
|
||||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf);
|
||||
|
||||
/**
|
||||
* Initializes frame header |hd| with given parameters. Reserved bit
|
||||
* is set to 0.
|
||||
*/
|
||||
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length,
|
||||
uint8_t type, uint8_t flags,
|
||||
int32_t stream_id);
|
||||
|
||||
/**
|
||||
* Returns the number of priority field depending on the |flags|. If
|
||||
* |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor
|
||||
@@ -471,7 +450,7 @@ void nghttp2_frame_priority_free(nghttp2_priority *frame);
|
||||
|
||||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame,
|
||||
int32_t stream_id,
|
||||
nghttp2_error_code error_code);
|
||||
uint32_t error_code);
|
||||
|
||||
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
|
||||
|
||||
@@ -513,7 +492,7 @@ void nghttp2_frame_ping_free(nghttp2_ping *frame);
|
||||
* free it. If the |opaque_data_len| is 0, opaque_data could be NULL.
|
||||
*/
|
||||
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
|
||||
nghttp2_error_code error_code,
|
||||
uint32_t error_code,
|
||||
uint8_t *opaque_data, size_t opaque_data_len);
|
||||
|
||||
void nghttp2_frame_goaway_free(nghttp2_goaway *frame);
|
||||
@@ -545,8 +524,6 @@ void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||
*/
|
||||
void nghttp2_frame_altsvc_free(nghttp2_extension *frame);
|
||||
|
||||
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
|
||||
|
||||
/*
|
||||
* Returns the number of padding bytes after payload. The total
|
||||
* padding length is given in the |padlen|. The returned value does
|
||||
@@ -554,12 +531,10 @@ void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
|
||||
*/
|
||||
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
|
||||
|
||||
void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_data_provider *data_prd);
|
||||
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
|
||||
int32_t stream_id);
|
||||
|
||||
void nghttp2_frame_private_data_free(nghttp2_private_data *frame);
|
||||
void nghttp2_frame_data_free(nghttp2_data *frame);
|
||||
|
||||
/*
|
||||
* Makes copy of |iv| and return the copy. The |niv| is the number of
|
||||
|
||||
785
lib/nghttp2_hd.c
785
lib/nghttp2_hd.c
File diff suppressed because it is too large
Load Diff
@@ -47,10 +47,8 @@
|
||||
encoder only uses the memory up to this value. */
|
||||
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_ROLE_DEFLATE,
|
||||
NGHTTP2_HD_ROLE_INFLATE
|
||||
} nghttp2_hd_role;
|
||||
/* Exported for unit test */
|
||||
extern const size_t NGHTTP2_STATIC_TABLE_LENGTH;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_FLAG_NONE = 0,
|
||||
@@ -58,18 +56,12 @@ typedef enum {
|
||||
NGHTTP2_HD_FLAG_NAME_ALLOC = 1,
|
||||
/* Indicates value was dynamically allocated and must be freed */
|
||||
NGHTTP2_HD_FLAG_VALUE_ALLOC = 1 << 1,
|
||||
/* Indicates that the entry is in the reference set */
|
||||
NGHTTP2_HD_FLAG_REFSET = 1 << 2,
|
||||
/* Indicates that the entry is emitted in the current header
|
||||
processing. */
|
||||
NGHTTP2_HD_FLAG_EMIT = 1 << 3,
|
||||
NGHTTP2_HD_FLAG_IMPLICIT_EMIT = 1 << 4,
|
||||
/* Indicates that the name was gifted to the entry and no copying
|
||||
necessary. */
|
||||
NGHTTP2_HD_FLAG_NAME_GIFT = 1 << 5,
|
||||
NGHTTP2_HD_FLAG_NAME_GIFT = 1 << 2,
|
||||
/* Indicates that the value was gifted to the entry and no copying
|
||||
necessary. */
|
||||
NGHTTP2_HD_FLAG_VALUE_GIFT = 1 << 6
|
||||
NGHTTP2_HD_FLAG_VALUE_GIFT = 1 << 3
|
||||
} nghttp2_hd_flags;
|
||||
|
||||
typedef struct {
|
||||
@@ -81,6 +73,11 @@ typedef struct {
|
||||
uint8_t flags;
|
||||
} nghttp2_hd_entry;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_hd_entry ent;
|
||||
size_t index;
|
||||
} nghttp2_hd_static_entry;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_hd_entry **buffer;
|
||||
size_t mask;
|
||||
@@ -97,7 +94,6 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_STATE_OPCODE,
|
||||
NGHTTP2_HD_STATE_CLEAR_REFSET,
|
||||
NGHTTP2_HD_STATE_READ_TABLE_SIZE,
|
||||
NGHTTP2_HD_STATE_READ_INDEX,
|
||||
NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
|
||||
@@ -119,8 +115,6 @@ typedef struct {
|
||||
size_t hd_table_bufsize;
|
||||
/* The effective header table size. */
|
||||
size_t hd_table_bufsize_max;
|
||||
/* Role of this context; deflate or infalte */
|
||||
nghttp2_hd_role role;
|
||||
/* If inflate/deflate error occurred, this value is set to 1 and
|
||||
further invocation of inflate/deflate will fail with
|
||||
NGHTTP2_ERR_HEADER_COMP. */
|
||||
@@ -131,9 +125,8 @@ struct nghttp2_hd_deflater {
|
||||
nghttp2_hd_context ctx;
|
||||
/* The upper limit of the header table size the deflater accepts. */
|
||||
size_t deflate_hd_table_bufsize_max;
|
||||
/* Set to this nonzero to clear reference set on each deflation each
|
||||
time. */
|
||||
uint8_t no_refset;
|
||||
/* Minimum header table size notified in the next context update */
|
||||
size_t min_hd_table_bufsize_max;
|
||||
/* If nonzero, send header table size using encoding context update
|
||||
in the next deflate process */
|
||||
uint8_t notify_table_size_change;
|
||||
@@ -152,16 +145,10 @@ struct nghttp2_hd_inflater {
|
||||
/* Pointer to the name/value pair buffer which is used in the
|
||||
current header emission. */
|
||||
uint8_t *nv_keep;
|
||||
/* Pointers to the name/value pair which is referred as indexed
|
||||
name. This entry must be in header table. */
|
||||
nghttp2_hd_entry *ent_name;
|
||||
/* The number of bytes to read */
|
||||
size_t left;
|
||||
/* The index in indexed repr or indexed name */
|
||||
size_t index;
|
||||
/* The index of header table to toggle off the entry from reference
|
||||
set at the end of decompression. */
|
||||
size_t end_headers_index;
|
||||
/* The length of new name encoded in literal. For huffman encoded
|
||||
string, this is the length after it is decoded. */
|
||||
size_t newnamelen;
|
||||
@@ -186,7 +173,9 @@ struct nghttp2_hd_inflater {
|
||||
* set in the |flags|, the content pointed by the |name| with length
|
||||
* |namelen| is copied. Likewise, if NGHTTP2_HD_FLAG_VALUE_ALLOC bit
|
||||
* set in the |flags|, the content pointed by the |value| with length
|
||||
* |valuelen| is copied.
|
||||
* |valuelen| is copied. The |name_hash| and |value_hash| are hash
|
||||
* value for |name| and |value| respectively. The hash function is
|
||||
* defined in nghttp2_hd.c.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
@@ -196,7 +185,8 @@ struct nghttp2_hd_inflater {
|
||||
*/
|
||||
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags,
|
||||
uint8_t *name, size_t namelen,
|
||||
uint8_t *value, size_t valuelen);
|
||||
uint8_t *value, size_t valuelen,
|
||||
uint32_t name_hash, uint32_t value_hash);
|
||||
|
||||
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
*/
|
||||
#include "nghttp2_hd_huffman.h"
|
||||
|
||||
/* Generated by mkhufftbl.py */
|
||||
|
||||
const nghttp2_huff_sym huff_sym_table[] = {
|
||||
{ 13, 0x1ff8u },
|
||||
{ 23, 0x7fffd8u },
|
||||
|
||||
@@ -55,23 +55,6 @@ uint32_t nghttp2_get_uint32(const uint8_t *data)
|
||||
return ntohl(n);
|
||||
}
|
||||
|
||||
int nghttp2_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||
size_t min_length)
|
||||
{
|
||||
if(min_length > *buflen_ptr) {
|
||||
uint8_t *temp;
|
||||
min_length = (min_length+4095)/4096*4096;
|
||||
temp = realloc(*buf_ptr, min_length);
|
||||
if(temp == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
} else {
|
||||
*buf_ptr = temp;
|
||||
*buflen_ptr = min_length;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* nghttp2_memdup(const void* src, size_t n)
|
||||
{
|
||||
void* dest;
|
||||
@@ -88,16 +71,108 @@ void* nghttp2_memdup(const void* src, size_t n)
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Generated by gendowncasetbl.py */
|
||||
static const int DOWNCASE_TBL[] = {
|
||||
0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */,
|
||||
4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */,
|
||||
8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */,
|
||||
12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */,
|
||||
16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */,
|
||||
20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */,
|
||||
24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */,
|
||||
28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */,
|
||||
32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */,
|
||||
36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */,
|
||||
40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */,
|
||||
44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */,
|
||||
48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */,
|
||||
52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
|
||||
56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */,
|
||||
60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */,
|
||||
64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */,
|
||||
100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */,
|
||||
104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */,
|
||||
108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */,
|
||||
112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */,
|
||||
116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */,
|
||||
120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */,
|
||||
92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */,
|
||||
96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */,
|
||||
100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
|
||||
104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
|
||||
108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
|
||||
112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
|
||||
116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
|
||||
120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */,
|
||||
124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */,
|
||||
128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */,
|
||||
132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */,
|
||||
136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */,
|
||||
140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */,
|
||||
144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */,
|
||||
148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */,
|
||||
152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */,
|
||||
156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */,
|
||||
160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */,
|
||||
164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */,
|
||||
168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */,
|
||||
172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */,
|
||||
176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */,
|
||||
180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */,
|
||||
184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */,
|
||||
188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */,
|
||||
192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */,
|
||||
196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */,
|
||||
200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */,
|
||||
204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */,
|
||||
208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */,
|
||||
212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */,
|
||||
216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */,
|
||||
220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */,
|
||||
224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */,
|
||||
228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */,
|
||||
232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */,
|
||||
236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */,
|
||||
240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */,
|
||||
244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */,
|
||||
248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */,
|
||||
252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */,
|
||||
};
|
||||
|
||||
void nghttp2_downcase(uint8_t *s, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < len; ++i) {
|
||||
if('A' <= s[i] && s[i] <= 'Z') {
|
||||
s[i] += 'a'-'A';
|
||||
}
|
||||
s[i] = DOWNCASE_TBL[s[i]];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* local_window_size
|
||||
* ^ *
|
||||
* | * recv_window_size
|
||||
* | * * ^
|
||||
* | * * |
|
||||
* 0+++++++++
|
||||
* | * * \
|
||||
* | * * | This rage is hidden in flow control. But it must be
|
||||
* v * * / kept in order to restore it when window size is enlarged.
|
||||
* recv_reduction
|
||||
* (+ for negative direction)
|
||||
*
|
||||
* recv_window_size could be negative if we decrease
|
||||
* local_window_size more than recv_window_size:
|
||||
*
|
||||
* local_window_size
|
||||
* ^ *
|
||||
* | *
|
||||
* | *
|
||||
* 0++++++++
|
||||
* | * ^ recv_window_size (negative)
|
||||
* | * |
|
||||
* v * *
|
||||
* recv_reduction
|
||||
*/
|
||||
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
@@ -123,10 +198,11 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||
if(*recv_window_size_ptr < 0) {
|
||||
*recv_window_size_ptr += recv_reduction_diff;
|
||||
} else {
|
||||
/* If *recv_window_size_ptr > 0, then those bytes are
|
||||
considered to be backed to the remote peer (by
|
||||
WINDOW_UPDATE with the adjusted *delta_ptr), so it is
|
||||
effectively 0 now. */
|
||||
/* If *recv_window_size_ptr > 0, then those bytes are going to
|
||||
be backed to the remote peer (by WINDOW_UPDATE with the
|
||||
adjusted *delta_ptr), so it is effectively 0 now. We set
|
||||
to *recv_reduction_diff, because caller does not take into
|
||||
account it in *delta_ptr. */
|
||||
*recv_window_size_ptr = recv_reduction_diff;
|
||||
}
|
||||
/* recv_reduction_diff must be paied from *delta_ptr, since it
|
||||
@@ -225,6 +301,8 @@ const char* nghttp2_strerror(int error_code)
|
||||
return "Out of memory";
|
||||
case NGHTTP2_ERR_CALLBACK_FAILURE:
|
||||
return "The user callback function failed";
|
||||
case NGHTTP2_ERR_BAD_PREFACE:
|
||||
return "Received bad connection preface";
|
||||
default:
|
||||
return "Unknown error code";
|
||||
}
|
||||
@@ -235,6 +313,7 @@ void nghttp2_free(void *ptr)
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/* Generated by gennmchartbl.py */
|
||||
static int VALID_HD_NAME_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
@@ -323,8 +402,9 @@ int nghttp2_check_header_name(const uint8_t *name, size_t len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generated by genvchartbl.py */
|
||||
static int VALID_HD_VALUE_CHARS[] = {
|
||||
1 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
|
||||
@@ -58,25 +58,6 @@ uint16_t nghttp2_get_uint16(const uint8_t *data);
|
||||
*/
|
||||
uint32_t nghttp2_get_uint32(const uint8_t *data);
|
||||
|
||||
/*
|
||||
* Ensures that buffer |*buf_ptr| with |*buflen_ptr| length has at
|
||||
* least |min_length| bytes. If |min_length| > |*buflen_ptr|,
|
||||
* allocates new buffer having at least |min_length| bytes and assigns
|
||||
* its pointer to |*buf_ptr| and allocated number of bytes to
|
||||
* |*buflen_ptr|. The memory pointed by |*buf_ptr| previously may
|
||||
* change. No memory copy is done between old and new buffer.
|
||||
* |*buf_ptr| and |*buflen_ptr| are only updated iff this function
|
||||
* succeeds.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||
size_t min_length);
|
||||
|
||||
/*
|
||||
* Allocates |n| bytes of memory and copy the memory region pointed by
|
||||
* |src| with the length |n| bytes into it. Returns the allocated memory.
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define INITIAL_TABLE_LENGTH 16
|
||||
#define INITIAL_TABLE_LENGTH 256
|
||||
|
||||
int nghttp2_map_init(nghttp2_map *map)
|
||||
{
|
||||
@@ -138,6 +138,7 @@ static int resize(nghttp2_map *map, size_t new_tablelen)
|
||||
free(map->table);
|
||||
map->tablelen = new_tablelen;
|
||||
map->table = new_table;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,18 +40,10 @@ void nghttp2_option_del(nghttp2_option *option)
|
||||
free(option);
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_auto_stream_window_update(nghttp2_option *option,
|
||||
int val)
|
||||
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val)
|
||||
{
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE;
|
||||
option->no_auto_stream_window_update = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_auto_connection_window_update
|
||||
(nghttp2_option *option, int val)
|
||||
{
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE;
|
||||
option->no_auto_connection_window_update = val;
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE;
|
||||
option->no_auto_window_update = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
|
||||
@@ -60,3 +52,10 @@ void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
|
||||
option->opt_set_mask |= NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS;
|
||||
option->peer_max_concurrent_streams = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_recv_client_preface
|
||||
(nghttp2_option *option, int val)
|
||||
{
|
||||
option->opt_set_mask |= NGHTTP2_OPT_RECV_CLIENT_PREFACE;
|
||||
option->recv_client_preface = val;
|
||||
}
|
||||
|
||||
@@ -37,22 +37,12 @@
|
||||
typedef enum {
|
||||
/**
|
||||
* This option prevents the library from sending WINDOW_UPDATE for a
|
||||
* stream automatically. If this option is set to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for a stream and the application
|
||||
* is responsible for sending WINDOW_UPDATE using
|
||||
* `nghttp2_submit_window_update`. By default, this option is set to
|
||||
* zero.
|
||||
* connection automatically. If this option is set to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for DATA until application calls
|
||||
* nghttp2_session_consume() to indicate the amount of consumed
|
||||
* DATA. By default, this option is set to zero.
|
||||
*/
|
||||
NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE = 1,
|
||||
/**
|
||||
* This option prevents the library from sending WINDOW_UPDATE for a
|
||||
* connection automatically. If this option is set to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for a connection and the
|
||||
* application is responsible for sending WINDOW_UPDATE with stream
|
||||
* ID 0 using `nghttp2_submit_window_update`. By default, this
|
||||
* option is set to zero.
|
||||
*/
|
||||
NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1,
|
||||
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1,
|
||||
/**
|
||||
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
|
||||
* remote endpoint as if it is received in SETTINGS frame. Without
|
||||
@@ -66,7 +56,8 @@ typedef enum {
|
||||
* will be overwritten if the local endpoint receives
|
||||
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
|
||||
*/
|
||||
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 2
|
||||
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
|
||||
NGHTTP2_OPT_RECV_CLIENT_PREFACE = 1 << 2,
|
||||
} nghttp2_option_flag;
|
||||
|
||||
/**
|
||||
@@ -83,13 +74,13 @@ struct nghttp2_option {
|
||||
*/
|
||||
uint32_t peer_max_concurrent_streams;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE
|
||||
* NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
|
||||
*/
|
||||
uint8_t no_auto_stream_window_update;
|
||||
uint8_t no_auto_window_update;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE
|
||||
* NGHTTP2_OPT_RECV_CLIENT_PREFACE
|
||||
*/
|
||||
uint8_t no_auto_connection_window_update;
|
||||
uint8_t recv_client_preface;
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_OPTION_H */
|
||||
|
||||
@@ -28,53 +28,45 @@
|
||||
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item)
|
||||
{
|
||||
nghttp2_frame *frame;
|
||||
|
||||
if(item == NULL) {
|
||||
return;
|
||||
}
|
||||
if(item->frame_cat == NGHTTP2_CAT_CTRL) {
|
||||
nghttp2_frame *frame;
|
||||
frame = nghttp2_outbound_item_get_ctrl_frame(item);
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
nghttp2_frame_headers_free(&frame->headers);
|
||||
if(item->aux_data) {
|
||||
free(((nghttp2_headers_aux_data*)item->aux_data)->data_prd);
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_PRIORITY:
|
||||
nghttp2_frame_priority_free(&frame->priority);
|
||||
break;
|
||||
case NGHTTP2_RST_STREAM:
|
||||
nghttp2_frame_rst_stream_free(&frame->rst_stream);
|
||||
break;
|
||||
case NGHTTP2_SETTINGS:
|
||||
nghttp2_frame_settings_free(&frame->settings);
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
nghttp2_frame_push_promise_free(&frame->push_promise);
|
||||
break;
|
||||
case NGHTTP2_PING:
|
||||
nghttp2_frame_ping_free(&frame->ping);
|
||||
break;
|
||||
case NGHTTP2_GOAWAY:
|
||||
nghttp2_frame_goaway_free(&frame->goaway);
|
||||
break;
|
||||
case NGHTTP2_WINDOW_UPDATE:
|
||||
nghttp2_frame_window_update_free(&frame->window_update);
|
||||
break;
|
||||
case NGHTTP2_EXT_ALTSVC:
|
||||
nghttp2_frame_altsvc_free(&frame->ext);
|
||||
free(frame->ext.payload);
|
||||
break;
|
||||
}
|
||||
} else if(item->frame_cat == NGHTTP2_CAT_DATA) {
|
||||
nghttp2_private_data *data_frame;
|
||||
data_frame = nghttp2_outbound_item_get_data_frame(item);
|
||||
nghttp2_frame_private_data_free(data_frame);
|
||||
} else {
|
||||
/* Unreachable */
|
||||
assert(0);
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
nghttp2_frame_data_free(&frame->data);
|
||||
break;
|
||||
case NGHTTP2_HEADERS:
|
||||
nghttp2_frame_headers_free(&frame->headers);
|
||||
break;
|
||||
case NGHTTP2_PRIORITY:
|
||||
nghttp2_frame_priority_free(&frame->priority);
|
||||
break;
|
||||
case NGHTTP2_RST_STREAM:
|
||||
nghttp2_frame_rst_stream_free(&frame->rst_stream);
|
||||
break;
|
||||
case NGHTTP2_SETTINGS:
|
||||
nghttp2_frame_settings_free(&frame->settings);
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
nghttp2_frame_push_promise_free(&frame->push_promise);
|
||||
break;
|
||||
case NGHTTP2_PING:
|
||||
nghttp2_frame_ping_free(&frame->ping);
|
||||
break;
|
||||
case NGHTTP2_GOAWAY:
|
||||
nghttp2_frame_goaway_free(&frame->goaway);
|
||||
break;
|
||||
case NGHTTP2_WINDOW_UPDATE:
|
||||
nghttp2_frame_window_update_free(&frame->window_update);
|
||||
break;
|
||||
case NGHTTP2_EXT_ALTSVC:
|
||||
nghttp2_frame_altsvc_free(&frame->ext);
|
||||
free(frame->ext.payload);
|
||||
break;
|
||||
}
|
||||
free(item->frame);
|
||||
free(item->aux_data);
|
||||
}
|
||||
|
||||
@@ -39,21 +39,46 @@
|
||||
/* Highest weight for PING */
|
||||
#define NGHTTP2_OB_PING_WEIGHT 302
|
||||
|
||||
/* struct used for HEADERS and PUSH_PROMISE frame */
|
||||
typedef struct {
|
||||
nghttp2_data_provider *data_prd;
|
||||
nghttp2_data_provider data_prd;
|
||||
void *stream_user_data;
|
||||
} nghttp2_headers_aux_data;
|
||||
|
||||
/* struct used for DATA frame */
|
||||
typedef struct {
|
||||
/**
|
||||
* The data to be sent for this DATA frame.
|
||||
*/
|
||||
nghttp2_data_provider data_prd;
|
||||
/**
|
||||
* The flags of DATA frame. We use separate flags here and
|
||||
* nghttp2_data frame. The latter contains flags actually sent to
|
||||
* peer. This |flags| may contain NGHTTP2_FLAG_END_STREAM and only
|
||||
* when |eof| becomes nonzero, flags in nghttp2_data has
|
||||
* NGHTTP2_FLAG_END_STREAM set.
|
||||
*/
|
||||
uint8_t flags;
|
||||
/**
|
||||
* The flag to indicate whether EOF was reached or not. Initially
|
||||
* |eof| is 0. It becomes 1 after all data were read.
|
||||
*/
|
||||
uint8_t eof;
|
||||
} nghttp2_data_aux_data;
|
||||
|
||||
/* Additional data which cannot be stored in nghttp2_frame struct */
|
||||
typedef union {
|
||||
nghttp2_data_aux_data data;
|
||||
nghttp2_headers_aux_data headers;
|
||||
} nghttp2_aux_data;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_frame frame;
|
||||
nghttp2_aux_data aux_data;
|
||||
int64_t seq;
|
||||
/* Reset count of weight. See comment for last_cycle in
|
||||
nghttp2_session.h */
|
||||
uint64_t cycle;
|
||||
void *frame;
|
||||
void *aux_data;
|
||||
/* Type of |frame|. NGHTTP2_CTRL: nghttp2_frame*, NGHTTP2_DATA:
|
||||
nghttp2_private_data* */
|
||||
nghttp2_frame_category frame_cat;
|
||||
/* The priority used in priority comparion. Larger is served
|
||||
ealier. */
|
||||
int32_t weight;
|
||||
@@ -67,11 +92,4 @@ typedef struct {
|
||||
*/
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item);
|
||||
|
||||
/* Macros to cast nghttp2_outbound_item.frame to the proper type. */
|
||||
#define nghttp2_outbound_item_get_ctrl_frame(ITEM) ((nghttp2_frame*)ITEM->frame)
|
||||
#define nghttp2_outbound_item_get_ctrl_frame_type(ITEM) \
|
||||
(((nghttp2_frame*)ITEM->frame)->hd.type)
|
||||
#define nghttp2_outbound_item_get_data_frame(ITEM) \
|
||||
((nghttp2_private_data*)ITEM->frame)
|
||||
|
||||
#endif /* NGHTTP2_OUTBOUND_ITEM_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,13 +38,14 @@
|
||||
#include "nghttp2_outbound_item.h"
|
||||
#include "nghttp2_int.h"
|
||||
#include "nghttp2_buf.h"
|
||||
#include "nghttp2_callbacks.h"
|
||||
|
||||
/*
|
||||
* Option flags.
|
||||
*/
|
||||
typedef enum {
|
||||
NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE = 1 << 0,
|
||||
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1
|
||||
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
|
||||
NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE = 1 << 1,
|
||||
} nghttp2_optmask;
|
||||
|
||||
typedef enum {
|
||||
@@ -65,6 +66,8 @@ typedef struct {
|
||||
/* Internal state when receiving incoming frame */
|
||||
typedef enum {
|
||||
/* Receiving frame header */
|
||||
NGHTTP2_IB_READ_CLIENT_PREFACE,
|
||||
NGHTTP2_IB_READ_FIRST_SETTINGS,
|
||||
NGHTTP2_IB_READ_HEAD,
|
||||
NGHTTP2_IB_READ_NBYTE,
|
||||
NGHTTP2_IB_READ_HEADER_BLOCK,
|
||||
@@ -81,7 +84,7 @@ typedef enum {
|
||||
NGHTTP2_IB_IGN_DATA
|
||||
} nghttp2_inbound_state;
|
||||
|
||||
#define NGHTTP2_INBOUND_NUM_IV 5
|
||||
#define NGHTTP2_INBOUND_NUM_IV 7
|
||||
|
||||
typedef struct {
|
||||
nghttp2_frame frame;
|
||||
@@ -105,11 +108,11 @@ typedef struct {
|
||||
size_t payloadleft;
|
||||
/* padding length for the current frame */
|
||||
size_t padlen;
|
||||
/* Sum of payload of (HEADERS | PUSH_PROMISE) + possible
|
||||
CONTINUATION received so far. */
|
||||
size_t headers_payload_length;
|
||||
nghttp2_inbound_state state;
|
||||
uint8_t raw_sbuf[8];
|
||||
/* Small buffer. Currently the largest contiguous chunk to buffer
|
||||
is frame header. We buffer part of payload, but they are smaller
|
||||
than frame header. */
|
||||
uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
|
||||
} nghttp2_inbound_frame;
|
||||
|
||||
typedef struct {
|
||||
@@ -117,6 +120,8 @@ typedef struct {
|
||||
uint32_t enable_push;
|
||||
uint32_t max_concurrent_streams;
|
||||
uint32_t initial_window_size;
|
||||
uint32_t max_frame_size;
|
||||
uint32_t max_header_list_size;
|
||||
} nghttp2_settings_storage;
|
||||
|
||||
typedef enum {
|
||||
@@ -132,10 +137,13 @@ typedef enum {
|
||||
struct nghttp2_session {
|
||||
nghttp2_map /* <nghttp2_stream*> */ streams;
|
||||
nghttp2_stream_roots roots;
|
||||
/* Queue for outbound frames other than stream-creating HEADERS */
|
||||
/* Queue for outbound frames other than stream-creating HEADERS and
|
||||
DATA */
|
||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq;
|
||||
/* Queue for outbound stream-creating HEADERS frame */
|
||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_ss_pq;
|
||||
/* QUeue for DATA frame */
|
||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_da_pq;
|
||||
nghttp2_active_outbound_item aob;
|
||||
nghttp2_inbound_frame iframe;
|
||||
nghttp2_hd_deflater hd_deflater;
|
||||
@@ -206,15 +214,10 @@ struct nghttp2_session {
|
||||
WINDOW_UPDATE. This could be negative after submitting negative
|
||||
value to WINDOW_UPDATE. */
|
||||
int32_t recv_window_size;
|
||||
/* The number of bytes in ignored DATA frame received without
|
||||
connection-level WINDOW_UPDATE. Since we do not call
|
||||
on_data_chunk_recv_callback for ignored DATA chunk, if
|
||||
nghttp2_option_set_no_auto_connection_window_update is used,
|
||||
application may not have a chance to send connection
|
||||
WINDOW_UPDATE. To fix this, we accumulate those received bytes,
|
||||
and if it exceeds certain number, we automatically send
|
||||
connection-level WINDOW_UPDATE. */
|
||||
int32_t recv_ign_window_size;
|
||||
/* The number of bytes consumed by the application and now is
|
||||
subject to WINDOW_UPDATE. This is only used when auto
|
||||
WINDOW_UPDATE is turned off. */
|
||||
int32_t consumed_size;
|
||||
/* The amount of recv_window_size cut using submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_reduction;
|
||||
@@ -257,24 +260,28 @@ int nghttp2_session_is_my_stream_id(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
* Adds frame |frame| to the outbound queue in |session|. The
|
||||
* |frame_cat| must be either NGHTTP2_CTRL or NGHTTP2_DATA. If the
|
||||
* |frame_cat| is NGHTTP2_CTRL, the |frame| must be a pointer to
|
||||
* nghttp2_frame. If the |frame_cat| is NGHTTP2_DATA, it must be a
|
||||
* pointer to nghttp2_private_data. |aux_data| is a pointer to the arbitrary
|
||||
* data. Its interpretation is defined per the type of the frame. When
|
||||
* this function succeeds, it takes ownership of |frame| and
|
||||
* |aux_data|, so caller must not free them on success.
|
||||
* Initializes |item|. No memory allocation is done in this function.
|
||||
* Don't call nghttp2_outbound_item_free() until frame member is
|
||||
* initialized.
|
||||
*/
|
||||
void nghttp2_session_outbound_item_init(nghttp2_session* session,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Adds |item| to the outbound queue in |session|. When this function
|
||||
* succeeds, it takes ownership of |item|. So caller must not free it
|
||||
* on success.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_STREAM_CLOSED
|
||||
* Stream already closed (DATA frame only)
|
||||
*/
|
||||
int nghttp2_session_add_frame(nghttp2_session *session,
|
||||
nghttp2_frame_category frame_cat,
|
||||
void *abs_frame, void *aux_data);
|
||||
int nghttp2_session_add_item(nghttp2_session *session,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Adds RST_STREAM frame for the stream |stream_id| with the error
|
||||
@@ -293,7 +300,7 @@ int nghttp2_session_add_frame(nghttp2_session *session,
|
||||
*/
|
||||
int nghttp2_session_add_rst_stream(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
nghttp2_error_code error_code);
|
||||
uint32_t error_code);
|
||||
|
||||
/*
|
||||
* Adds PING frame. This is a convenient functin built on top of
|
||||
@@ -327,7 +334,7 @@ int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
|
||||
*/
|
||||
int nghttp2_session_add_goaway(nghttp2_session *session,
|
||||
int32_t last_stream_id,
|
||||
nghttp2_error_code error_code,
|
||||
uint32_t error_code,
|
||||
const uint8_t *opaque_data,
|
||||
size_t opaque_data_len);
|
||||
|
||||
@@ -399,7 +406,7 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
|
||||
nghttp2_error_code error_code);
|
||||
uint32_t error_code);
|
||||
|
||||
/*
|
||||
* Deletes |stream| from memory. After this function returns, stream
|
||||
@@ -644,13 +651,8 @@ nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session,
|
||||
|
||||
/*
|
||||
* Packs DATA frame |frame| in wire frame format and stores it in
|
||||
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
|
||||
* length. This function expands |*buf_ptr| as necessary to store
|
||||
* given |frame|. It packs header in first 8 bytes starting
|
||||
* |*bufoff_ptr| offset. The |*bufoff_ptr| is calculated based on
|
||||
* usage of padding. Remaining bytes are the DATA apyload and are
|
||||
* filled using |frame->data_prd|. The length of payload is at most
|
||||
* |datamax| bytes.
|
||||
* |bufs|. Payload will be read using |aux_data->data_prd|. The
|
||||
* length of payload is at most |datamax| bytes.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
@@ -667,7 +669,8 @@ nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session,
|
||||
int nghttp2_session_pack_data(nghttp2_session *session,
|
||||
nghttp2_bufs *bufs,
|
||||
size_t datamax,
|
||||
nghttp2_private_data *frame);
|
||||
nghttp2_frame *frame,
|
||||
nghttp2_data_aux_data *aux_data);
|
||||
|
||||
/*
|
||||
* Returns top of outbound frame queue. This function returns NULL if
|
||||
@@ -742,6 +745,6 @@ int nghttp2_session_reprioritize_stream
|
||||
* The |reason| is too long.
|
||||
*/
|
||||
int nghttp2_session_terminate_session_with_reason
|
||||
(nghttp2_session *session, nghttp2_error_code error_code, const char *reason);
|
||||
(nghttp2_session *session, uint32_t error_code, const char *reason);
|
||||
|
||||
#endif /* NGHTTP2_SESSION_H */
|
||||
|
||||
@@ -48,6 +48,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
stream->remote_window_size = remote_initial_window_size;
|
||||
stream->local_window_size = local_initial_window_size;
|
||||
stream->recv_window_size = 0;
|
||||
stream->consumed_size = 0;
|
||||
stream->recv_reduction = 0;
|
||||
stream->blocked_sent = 0;
|
||||
|
||||
@@ -64,6 +65,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
stream->effective_weight = stream->weight;
|
||||
stream->sum_dep_weight = 0;
|
||||
stream->sum_norest_weight = 0;
|
||||
stream->sum_top_weight = 0;
|
||||
|
||||
stream->roots = roots;
|
||||
stream->root_prev = NULL;
|
||||
@@ -72,12 +74,10 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
|
||||
void nghttp2_stream_free(nghttp2_stream *stream)
|
||||
{
|
||||
if(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
|
||||
nghttp2_outbound_item_free(stream->data_item);
|
||||
free(stream->data_item);
|
||||
}
|
||||
|
||||
/* We don't free stream->data_item otherwise. */
|
||||
/* We don't free stream->data_item. If it is assigned to aob, then
|
||||
active_outbound_item_reset() will delete it. If it is queued,
|
||||
then it is deleted when pq is deleted in nghttp2_session_del().
|
||||
Otherwise, nghttp2_session_del() will delete it. */
|
||||
}
|
||||
|
||||
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag)
|
||||
@@ -86,13 +86,19 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag)
|
||||
}
|
||||
|
||||
static int stream_push_data(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
uint64_t cycle)
|
||||
uint64_t cycle, nghttp2_outbound_item *active_item)
|
||||
{
|
||||
int rv;
|
||||
|
||||
assert(stream->data_item);
|
||||
assert(stream->data_item->queued == 0);
|
||||
|
||||
/* If stream->data_item is now sent, don't push it to the queue.
|
||||
Otherwise, we may push same item twice. */
|
||||
if(active_item == stream->data_item) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(stream->data_item->weight > stream->effective_weight) {
|
||||
stream->data_item->weight = stream->effective_weight;
|
||||
}
|
||||
@@ -158,6 +164,20 @@ int32_t nghttp2_stream_dep_distributed_effective_weight
|
||||
return nghttp2_max(1, weight);
|
||||
}
|
||||
|
||||
static int32_t stream_dep_distributed_top_effective_weight
|
||||
(nghttp2_stream *stream, int32_t weight)
|
||||
{
|
||||
if(stream->sum_top_weight == 0) {
|
||||
return stream->effective_weight;
|
||||
}
|
||||
|
||||
weight = stream->effective_weight * weight / stream->sum_top_weight;
|
||||
|
||||
return nghttp2_max(1, weight);
|
||||
}
|
||||
|
||||
static void stream_update_dep_set_rest(nghttp2_stream *stream);
|
||||
|
||||
/* Updates effective_weight of descendant streams in subtree of
|
||||
|stream|. We assume that stream->effective_weight is already set
|
||||
right. */
|
||||
@@ -166,9 +186,10 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream)
|
||||
nghttp2_stream *si;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight "
|
||||
"stream(%p)=%d, weight=%d, sum_norest_weight=%d\n",
|
||||
"stream(%p)=%d, weight=%d, sum_norest_weight=%d, "
|
||||
"sum_top_weight=%d\n",
|
||||
stream, stream->stream_id, stream->weight,
|
||||
stream->sum_norest_weight));
|
||||
stream->sum_norest_weight, stream->sum_top_weight));
|
||||
|
||||
/* stream->sum_norest_weight == 0 means there is no
|
||||
NGHTTP2_STREAM_DPRI_TOP under stream */
|
||||
@@ -177,13 +198,47 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream)
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is no direct descendant whose dpri is
|
||||
NGHTTP2_STREAM_DPRI_TOP, indirect descendants have the chance to
|
||||
send data, so recursively set weight for descendants. */
|
||||
if(stream->sum_top_weight == 0) {
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
if(si->dpri != NGHTTP2_STREAM_DPRI_REST) {
|
||||
si->effective_weight = nghttp2_stream_dep_distributed_effective_weight
|
||||
(stream, si->weight);
|
||||
}
|
||||
|
||||
stream_update_dep_effective_weight(si);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is at least one direct descendant whose dpri is
|
||||
NGHTTP2_STREAM_DPRI_TOP, we won't give a chance to indirect
|
||||
descendants, since closed or blocked stream's weight is
|
||||
distributed among its siblings */
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
if(si->dpri != NGHTTP2_STREAM_DPRI_REST) {
|
||||
si->effective_weight = nghttp2_stream_dep_distributed_effective_weight
|
||||
if(si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
si->effective_weight = stream_dep_distributed_top_effective_weight
|
||||
(stream, si->weight);
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d top eweight=%d\n",
|
||||
si->stream_id, si->effective_weight));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
stream_update_dep_effective_weight(si);
|
||||
if(si->dpri == NGHTTP2_STREAM_DPRI_NO_DATA) {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d no_data, ignored\n",
|
||||
si->stream_id));
|
||||
|
||||
/* Since we marked NGHTTP2_STREAM_DPRI_TOP under si, we make
|
||||
them NGHTTP2_STREAM_DPRI_REST again. */
|
||||
stream_update_dep_set_rest(si->dep_next);
|
||||
} else {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d rest, ignored\n",
|
||||
si->stream_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +248,8 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream)
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d is rest\n", stream->stream_id));
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
return;
|
||||
}
|
||||
@@ -211,7 +268,33 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream)
|
||||
|
||||
/*
|
||||
* Performs dfs starting |stream|, search stream which can become
|
||||
* NGHTTP2_STREAM_DPRI_TOP and queues its data_item.
|
||||
* NGHTTP2_STREAM_DPRI_TOP and set its dpri.
|
||||
*/
|
||||
static void stream_update_dep_set_top(nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *si;
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d data is top\n",
|
||||
stream->stream_id));
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
stream_update_dep_set_top(si);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs dfs starting |stream|, and dueue stream whose dpri is
|
||||
* NGHTTP2_STREAM_DPRI_TOP and has not been queued yet.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
@@ -219,35 +302,33 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream)
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
static int stream_update_dep_set_top(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
uint64_t cycle)
|
||||
static int stream_update_dep_queue_top(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_stream *si;
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d data is top\n",
|
||||
stream->stream_id));
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
if(!stream->data_item->queued) {
|
||||
rv = stream_push_data(stream, pq, cycle);
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d enqueue\n",
|
||||
stream->stream_id));
|
||||
rv = stream_push_data(stream, pq, cycle, active_item);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
rv = stream_update_dep_set_top(si, pq, cycle);
|
||||
rv = stream_update_dep_queue_top(si, pq, cycle, active_item);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
@@ -258,14 +339,18 @@ static int stream_update_dep_set_top(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates stream->sum_norest_weight recursively. We have to gather
|
||||
* effective sum of weight of descendants. If stream->dpri ==
|
||||
* NGHTTP2_STREAM_DPRI_NO_DATA, we have to go deeper and check that
|
||||
* any of its descendants has dpri value of NGHTTP2_STREAM_DPRI_TOP.
|
||||
* If so, we have to add weight of its direct descendants to
|
||||
* stream->sum_norest_weight. To make this work, this function
|
||||
* returns 1 if any of its descendants has dpri value of
|
||||
* NGHTTP2_STREAM_DPRI_TOP, otherwise 0.
|
||||
* Updates stream->sum_norest_weight and stream->sum_top_weight
|
||||
* recursively. We have to gather effective sum of weight of
|
||||
* descendants. If stream->dpri == NGHTTP2_STREAM_DPRI_NO_DATA, we
|
||||
* have to go deeper and check that any of its descendants has dpri
|
||||
* value of NGHTTP2_STREAM_DPRI_TOP. If so, we have to add weight of
|
||||
* its direct descendants to stream->sum_norest_weight. To make this
|
||||
* work, this function returns 1 if any of its descendants has dpri
|
||||
* value of NGHTTP2_STREAM_DPRI_TOP, otherwise 0.
|
||||
*
|
||||
* Calculating stream->sum_top-weight is very simple compared to
|
||||
* stream->sum_norest_weight. It just adds up the weight of direct
|
||||
* descendants whose dpri is NGHTTP2_STREAM_DPRI_TOP.
|
||||
*/
|
||||
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream)
|
||||
{
|
||||
@@ -273,6 +358,7 @@ static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream)
|
||||
int rv;
|
||||
|
||||
stream->sum_norest_weight = 0;
|
||||
stream->sum_top_weight = 0;
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
return 1;
|
||||
@@ -290,15 +376,19 @@ static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream)
|
||||
rv = 1;
|
||||
stream->sum_norest_weight += si->weight;
|
||||
}
|
||||
|
||||
if(si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
stream->sum_top_weight += si->weight;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int stream_update_dep_on_attach_data(nghttp2_stream *stream,
|
||||
nghttp2_pq *pq, uint64_t cycle)
|
||||
nghttp2_pq *pq, uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_REST;
|
||||
@@ -309,44 +399,37 @@ static int stream_update_dep_on_attach_data(nghttp2_stream *stream,
|
||||
|
||||
DEBUGF(fprintf(stderr, "root=%p, stream=%p\n", root_stream, stream));
|
||||
|
||||
rv = stream_update_dep_set_top(root_stream, pq, cycle);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
stream_update_dep_set_top(root_stream);
|
||||
|
||||
stream_update_dep_sum_norest_weight(root_stream);
|
||||
stream_update_dep_effective_weight(root_stream);
|
||||
|
||||
return 0;
|
||||
return stream_update_dep_queue_top(root_stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
static int stream_update_dep_on_detach_data(nghttp2_stream *stream,
|
||||
nghttp2_pq *pq, uint64_t cycle)
|
||||
nghttp2_pq *pq, uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA;
|
||||
|
||||
root_stream = nghttp2_stream_get_dep_root(stream);
|
||||
|
||||
rv = stream_update_dep_set_top(root_stream, pq, cycle);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
stream_update_dep_set_top(root_stream);
|
||||
|
||||
stream_update_dep_sum_norest_weight(root_stream);
|
||||
stream_update_dep_effective_weight(root_stream);
|
||||
|
||||
return 0;
|
||||
return stream_update_dep_queue_top(root_stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
int nghttp2_stream_attach_data(nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *data_item,
|
||||
nghttp2_pq *pq,
|
||||
uint64_t cycle)
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0);
|
||||
assert(stream->data_item == NULL);
|
||||
@@ -356,11 +439,12 @@ int nghttp2_stream_attach_data(nghttp2_stream *stream,
|
||||
|
||||
stream->data_item = data_item;
|
||||
|
||||
return stream_update_dep_on_attach_data(stream, pq, cycle);
|
||||
return stream_update_dep_on_attach_data(stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
uint64_t cycle)
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d detach data=%p\n",
|
||||
stream->stream_id, stream->data_item));
|
||||
@@ -368,11 +452,12 @@ int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
stream->data_item = NULL;
|
||||
stream->flags &= ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL;
|
||||
|
||||
return stream_update_dep_on_detach_data(stream, pq, cycle);
|
||||
return stream_update_dep_on_detach_data(stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags,
|
||||
nghttp2_pq *pq, uint64_t cycle)
|
||||
nghttp2_pq *pq, uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
assert(stream->data_item);
|
||||
|
||||
@@ -381,20 +466,25 @@ int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags,
|
||||
|
||||
stream->flags |= flags;
|
||||
|
||||
return stream_update_dep_on_detach_data(stream, pq, cycle);
|
||||
return stream_update_dep_on_detach_data(stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream,
|
||||
nghttp2_pq *pq, uint64_t cycle)
|
||||
int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream, uint8_t flags,
|
||||
nghttp2_pq *pq, uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
assert(stream->data_item);
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d resume data=%p\n",
|
||||
stream->stream_id, stream->data_item));
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d resume data=%p flags=%02x\n",
|
||||
stream->stream_id, stream->data_item, flags));
|
||||
|
||||
stream->flags &= ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL;
|
||||
stream->flags &= ~flags;
|
||||
|
||||
return stream_update_dep_on_attach_data(stream, pq, cycle);
|
||||
if(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stream_update_dep_on_attach_data(stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
int nghttp2_stream_check_deferred_data(nghttp2_stream *stream)
|
||||
@@ -524,10 +614,111 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
++stream->roots->num_streams;
|
||||
}
|
||||
|
||||
static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream)
|
||||
{
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
}
|
||||
|
||||
static void link_sib(nghttp2_stream *prev_stream, nghttp2_stream *stream)
|
||||
{
|
||||
prev_stream->sib_next = stream;
|
||||
stream->sib_prev = prev_stream;
|
||||
}
|
||||
|
||||
static void insert_link_dep(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *sib_next;
|
||||
|
||||
assert(stream->sib_prev == NULL);
|
||||
|
||||
sib_next = dep_stream->dep_next;
|
||||
|
||||
link_sib(stream, sib_next);
|
||||
|
||||
sib_next->dep_prev = NULL;
|
||||
|
||||
link_dep(dep_stream, stream);
|
||||
}
|
||||
|
||||
static void unlink_sib(nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *prev, *next, *dep_next;
|
||||
|
||||
prev = stream->sib_prev;
|
||||
dep_next = stream->dep_next;
|
||||
|
||||
assert(prev);
|
||||
|
||||
if(dep_next) {
|
||||
/*
|
||||
* prev--stream(--sib_next--...)
|
||||
* |
|
||||
* dep_next
|
||||
*/
|
||||
dep_next->dep_prev = NULL;
|
||||
|
||||
link_sib(prev, dep_next);
|
||||
|
||||
if(stream->sib_next) {
|
||||
link_sib(stream_last_sib(dep_next), stream->sib_next);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* prev--stream(--sib_next--...)
|
||||
*/
|
||||
next = stream->sib_next;
|
||||
|
||||
prev->sib_next = next;
|
||||
|
||||
if(next) {
|
||||
next->sib_prev = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void unlink_dep(nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *prev, *next, *dep_next;
|
||||
|
||||
prev = stream->dep_prev;
|
||||
dep_next = stream->dep_next;
|
||||
|
||||
assert(prev);
|
||||
|
||||
if(dep_next) {
|
||||
/*
|
||||
* prev
|
||||
* |
|
||||
* stream(--sib_next--...)
|
||||
* |
|
||||
* dep_next
|
||||
*/
|
||||
link_dep(prev, dep_next);
|
||||
|
||||
if(stream->sib_next) {
|
||||
link_sib(stream_last_sib(dep_next), stream->sib_next);
|
||||
}
|
||||
} else if(stream->sib_next) {
|
||||
/*
|
||||
* prev
|
||||
* |
|
||||
* stream--sib_next
|
||||
*/
|
||||
next = stream->sib_next;
|
||||
|
||||
next->sib_prev = NULL;
|
||||
|
||||
link_dep(prev, next);
|
||||
} else {
|
||||
prev->dep_next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *last_sib;
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
assert(stream->data_item == NULL);
|
||||
@@ -542,12 +733,9 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
||||
dep_stream->sum_dep_weight += stream->weight;
|
||||
|
||||
if(dep_stream->dep_next == NULL) {
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
link_dep(dep_stream, stream);
|
||||
} else {
|
||||
last_sib = stream_last_sib(dep_stream->dep_next);
|
||||
last_sib->sib_next = stream;
|
||||
stream->sib_prev = last_sib;
|
||||
insert_link_dep(dep_stream, stream);
|
||||
}
|
||||
|
||||
stream_update_dep_sum_norest_weight(root_stream);
|
||||
@@ -558,7 +746,7 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
||||
|
||||
void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *prev, *next, *dep_next, *dep_prev, *si, *root_stream;
|
||||
nghttp2_stream *prev, *next, *dep_prev, *si, *root_stream;
|
||||
int32_t sum_dep_weight_delta;
|
||||
|
||||
root_stream = NULL;
|
||||
@@ -586,46 +774,12 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
}
|
||||
|
||||
if(stream->sib_prev) {
|
||||
prev = stream->sib_prev;
|
||||
dep_next = stream->dep_next;
|
||||
|
||||
if(dep_next) {
|
||||
dep_next->dep_prev = NULL;
|
||||
|
||||
prev->sib_next = dep_next;
|
||||
dep_next->sib_prev = prev;
|
||||
} else {
|
||||
next = stream->sib_next;
|
||||
|
||||
prev->sib_next = next;
|
||||
|
||||
if(next) {
|
||||
next->sib_prev = prev;
|
||||
}
|
||||
}
|
||||
unlink_sib(stream);
|
||||
} else if(stream->dep_prev) {
|
||||
prev = stream->dep_prev;
|
||||
dep_next = stream->dep_next;
|
||||
|
||||
if(dep_next) {
|
||||
prev->dep_next = dep_next;
|
||||
dep_next->dep_prev = prev;
|
||||
} else if(stream->sib_next) {
|
||||
next = stream->sib_next;
|
||||
|
||||
prev->dep_next = next;
|
||||
next->dep_prev = prev;
|
||||
|
||||
next->sib_prev = NULL;
|
||||
} else {
|
||||
prev->dep_next = NULL;
|
||||
dep_next = NULL;
|
||||
}
|
||||
unlink_dep(stream);
|
||||
} else {
|
||||
nghttp2_stream_roots_remove(stream->roots, stream);
|
||||
|
||||
dep_next = NULL;
|
||||
|
||||
/* stream is a root of tree. Removing stream makes its
|
||||
descendants a root of its own subtree. */
|
||||
|
||||
@@ -645,14 +799,6 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
}
|
||||
}
|
||||
|
||||
if(dep_next && stream->sib_next) {
|
||||
prev = stream_last_sib(dep_next);
|
||||
next = stream->sib_next;
|
||||
|
||||
prev->sib_next = next;
|
||||
next->sib_prev = prev;
|
||||
}
|
||||
|
||||
if(root_stream) {
|
||||
stream_update_dep_sum_norest_weight(root_stream);
|
||||
stream_update_dep_effective_weight(root_stream);
|
||||
@@ -672,13 +818,13 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq,
|
||||
uint64_t cycle)
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
nghttp2_stream *last_sib;
|
||||
nghttp2_stream *dep_next;
|
||||
nghttp2_stream *root_stream;
|
||||
size_t delta_substreams;
|
||||
int rv;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d "
|
||||
"stream(%p)=%d\n",
|
||||
@@ -700,23 +846,19 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
|
||||
stream_update_dep_set_rest(dep_next);
|
||||
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
link_dep(dep_stream, stream);
|
||||
|
||||
if(stream->dep_next) {
|
||||
last_sib = stream_last_sib(stream->dep_next);
|
||||
|
||||
last_sib->sib_next = dep_next;
|
||||
dep_next->sib_prev = last_sib;
|
||||
link_sib(last_sib, dep_next);
|
||||
|
||||
dep_next->dep_prev = NULL;
|
||||
} else {
|
||||
stream->dep_next = dep_next;
|
||||
dep_next->dep_prev = stream;
|
||||
link_dep(stream, dep_next);
|
||||
}
|
||||
} else {
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
link_dep(dep_stream, stream);
|
||||
|
||||
assert(dep_stream->sum_dep_weight == 0);
|
||||
dep_stream->sum_dep_weight = stream->weight;
|
||||
@@ -724,26 +866,21 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
|
||||
root_stream = stream_update_dep_length(dep_stream, delta_substreams);
|
||||
|
||||
rv = stream_update_dep_set_top(root_stream, pq, cycle);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
stream_update_dep_set_top(root_stream);
|
||||
|
||||
stream_update_dep_sum_norest_weight(root_stream);
|
||||
stream_update_dep_effective_weight(root_stream);
|
||||
|
||||
return 0;
|
||||
return stream_update_dep_queue_top(root_stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq,
|
||||
uint64_t cycle)
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
nghttp2_stream *last_sib;
|
||||
nghttp2_stream *root_stream;
|
||||
int rv;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d "
|
||||
"stream(%p)=%d\n",
|
||||
@@ -755,13 +892,9 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
if(dep_stream->dep_next) {
|
||||
dep_stream->sum_dep_weight += stream->weight;
|
||||
|
||||
last_sib = stream_last_sib(dep_stream->dep_next);
|
||||
|
||||
last_sib->sib_next = stream;
|
||||
stream->sib_prev = last_sib;
|
||||
insert_link_dep(dep_stream, stream);
|
||||
} else {
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
link_dep(dep_stream, stream);
|
||||
|
||||
assert(dep_stream->sum_dep_weight == 0);
|
||||
dep_stream->sum_dep_weight = stream->weight;
|
||||
@@ -769,16 +902,12 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
|
||||
root_stream = stream_update_dep_length(dep_stream, stream->num_substreams);
|
||||
|
||||
rv = stream_update_dep_set_top(root_stream, pq, cycle);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
stream_update_dep_set_top(root_stream);
|
||||
|
||||
stream_update_dep_sum_norest_weight(root_stream);
|
||||
stream_update_dep_effective_weight(root_stream);
|
||||
|
||||
return 0;
|
||||
return stream_update_dep_queue_top(root_stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
|
||||
@@ -833,10 +962,9 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
uint64_t cycle)
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
int rv;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n",
|
||||
stream, stream->stream_id));
|
||||
|
||||
@@ -846,20 +974,17 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
|
||||
stream->effective_weight = stream->weight;
|
||||
|
||||
rv = stream_update_dep_set_top(stream, pq, cycle);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
stream_update_dep_set_top(stream);
|
||||
|
||||
stream_update_dep_sum_norest_weight(stream);
|
||||
stream_update_dep_effective_weight(stream);
|
||||
|
||||
return 0;
|
||||
return stream_update_dep_queue_top(stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_all_your_stream_are_belong_to_us
|
||||
(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle)
|
||||
(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item)
|
||||
{
|
||||
nghttp2_stream *first, *si;
|
||||
|
||||
@@ -893,28 +1018,28 @@ int nghttp2_stream_dep_all_your_stream_are_belong_to_us
|
||||
stream->sum_dep_weight += si->weight;
|
||||
stream->num_substreams += si->num_substreams;
|
||||
|
||||
si->sib_prev = prev;
|
||||
prev->sib_next = si;
|
||||
link_sib(prev, si);
|
||||
|
||||
prev = si;
|
||||
}
|
||||
|
||||
if(stream->dep_next) {
|
||||
nghttp2_stream *last_sib;
|
||||
nghttp2_stream *sib_next;
|
||||
|
||||
last_sib = stream_last_sib(stream->dep_next);
|
||||
sib_next = stream->dep_next;
|
||||
|
||||
last_sib->sib_next = first;
|
||||
first->sib_prev = last_sib;
|
||||
sib_next->dep_prev = NULL;
|
||||
|
||||
link_sib(first, sib_next);
|
||||
link_dep(stream, prev);
|
||||
} else {
|
||||
stream->dep_next = first;
|
||||
first->dep_prev = stream;
|
||||
link_dep(stream, first);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_stream_roots_remove_all(stream->roots);
|
||||
|
||||
return nghttp2_stream_dep_make_root(stream, pq, cycle);
|
||||
return nghttp2_stream_dep_make_root(stream, pq, cycle, active_item);
|
||||
}
|
||||
|
||||
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream)
|
||||
|
||||
@@ -151,6 +151,10 @@ struct nghttp2_stream {
|
||||
WINDOW_UPDATE. This could be negative after submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_window_size;
|
||||
/* The number of bytes consumed by the application and now is
|
||||
subject to WINDOW_UPDATE. This is only used when auto
|
||||
WINDOW_UPDATE is turned off. */
|
||||
int32_t consumed_size;
|
||||
/* The amount of recv_window_size cut using submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_reduction;
|
||||
@@ -168,6 +172,9 @@ struct nghttp2_stream {
|
||||
descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this
|
||||
value to calculate effective weight. */
|
||||
int32_t sum_norest_weight;
|
||||
/* sum of weight of direct descendants whose dpri value is
|
||||
NGHTTP2_STREAM_DPRI_TOP */
|
||||
int32_t sum_top_weight;
|
||||
nghttp2_stream_state state;
|
||||
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
|
||||
uint8_t flags;
|
||||
@@ -209,16 +216,20 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags,
|
||||
nghttp2_pq *pq, uint64_t cycle);
|
||||
nghttp2_pq *pq, uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item);
|
||||
|
||||
/*
|
||||
* Detaches deferred data in this stream and it is back to active
|
||||
* state. The flags NGHTTP2_STREAM_FLAG_DEFERRED_USER and
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL are cleared if they are
|
||||
* set.
|
||||
* Put back deferred data in this stream to active state. The |flags|
|
||||
* are one or more of bitwise OR of the following values:
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_USER and
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are
|
||||
* cleared if they are set. So even if this function is called, if
|
||||
* one of flag is still set, data does not become active.
|
||||
*/
|
||||
int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream,
|
||||
nghttp2_pq *pq, uint64_t cycle);
|
||||
int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream, uint8_t flags,
|
||||
nghttp2_pq *pq, uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item);
|
||||
|
||||
/*
|
||||
* Returns nonzero if data item is deferred by whatever reason.
|
||||
@@ -330,7 +341,8 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream);
|
||||
int nghttp2_stream_attach_data(nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *data_item,
|
||||
nghttp2_pq *pq,
|
||||
uint64_t cycle);
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item);
|
||||
|
||||
/*
|
||||
* Detaches |stream->data_item|. Updates dpri members in this
|
||||
@@ -344,7 +356,8 @@ int nghttp2_stream_attach_data(nghttp2_stream *stream,
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
uint64_t cycle);
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item);
|
||||
|
||||
|
||||
/*
|
||||
@@ -360,7 +373,8 @@ int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq,
|
||||
uint64_t cycle);
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
@@ -375,7 +389,8 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq,
|
||||
uint64_t cycle);
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item);
|
||||
|
||||
/*
|
||||
* Removes subtree whose root stream is |stream|. Removing subtree
|
||||
@@ -401,7 +416,8 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
uint64_t cycle);
|
||||
uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item);
|
||||
|
||||
/*
|
||||
* Makes the |stream| as root and all existing root streams become
|
||||
@@ -414,7 +430,8 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq,
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_all_your_stream_are_belong_to_us
|
||||
(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle);
|
||||
(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle,
|
||||
nghttp2_outbound_item *active_item);
|
||||
|
||||
/*
|
||||
* Returns nonzero if |stream| is in any dependency tree.
|
||||
|
||||
@@ -47,9 +47,8 @@ static int32_t submit_headers_shared
|
||||
{
|
||||
int rv;
|
||||
uint8_t flags_copy;
|
||||
nghttp2_outbound_item *item = NULL;
|
||||
nghttp2_frame *frame = NULL;
|
||||
nghttp2_data_provider *data_prd_copy = NULL;
|
||||
nghttp2_headers_aux_data *aux_data = NULL;
|
||||
nghttp2_headers_category hcat;
|
||||
|
||||
if(stream_id == 0) {
|
||||
@@ -57,33 +56,22 @@ static int32_t submit_headers_shared
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(data_prd != NULL && data_prd->read_callback != NULL) {
|
||||
data_prd_copy = malloc(sizeof(nghttp2_data_provider));
|
||||
if(data_prd_copy == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail;
|
||||
}
|
||||
*data_prd_copy = *data_prd;
|
||||
}
|
||||
if(data_prd || stream_user_data) {
|
||||
aux_data = malloc(sizeof(nghttp2_headers_aux_data));
|
||||
if(aux_data == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail;
|
||||
}
|
||||
aux_data->data_prd = data_prd_copy;
|
||||
aux_data->stream_user_data = stream_user_data;
|
||||
}
|
||||
frame = malloc(sizeof(nghttp2_frame));
|
||||
if(frame == NULL) {
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
if(item == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
|
||||
if(data_prd != NULL && data_prd->read_callback != NULL) {
|
||||
item->aux_data.headers.data_prd = *data_prd;
|
||||
}
|
||||
|
||||
item->aux_data.headers.stream_user_data = stream_user_data;
|
||||
|
||||
flags_copy =
|
||||
(flags & (NGHTTP2_FLAG_END_STREAM |
|
||||
NGHTTP2_FLAG_END_SEGMENT |
|
||||
NGHTTP2_FLAG_PRIORITY)) |
|
||||
(flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) |
|
||||
NGHTTP2_FLAG_END_HEADERS;
|
||||
|
||||
if(stream_id == -1) {
|
||||
@@ -101,12 +89,12 @@ static int32_t submit_headers_shared
|
||||
hcat = NGHTTP2_HCAT_HEADERS;
|
||||
}
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id,
|
||||
hcat, pri_spec, nva_copy, nvlen);
|
||||
|
||||
|
||||
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame,
|
||||
aux_data);
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if(rv != 0) {
|
||||
nghttp2_frame_headers_free(&frame->headers);
|
||||
@@ -123,9 +111,8 @@ static int32_t submit_headers_shared
|
||||
/* nghttp2_frame_headers_init() takes ownership of nva_copy. */
|
||||
nghttp2_nv_array_del(nva_copy);
|
||||
fail2:
|
||||
free(frame);
|
||||
free(aux_data);
|
||||
free(data_prd_copy);
|
||||
free(item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -199,6 +186,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_priority_spec copy_pri_spec;
|
||||
|
||||
@@ -214,19 +202,23 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
||||
|
||||
adjust_priority_spec_weight(©_pri_spec);
|
||||
|
||||
frame = malloc(sizeof(nghttp2_frame));
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
|
||||
if(frame == NULL) {
|
||||
if(item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
nghttp2_frame_priority_init(&frame->priority, stream_id, ©_pri_spec);
|
||||
|
||||
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if(rv != 0) {
|
||||
nghttp2_frame_priority_free(&frame->priority);
|
||||
free(frame);
|
||||
free(item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -236,7 +228,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
||||
|
||||
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
nghttp2_error_code error_code)
|
||||
uint32_t error_code)
|
||||
{
|
||||
if(stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
@@ -247,7 +239,7 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
|
||||
|
||||
int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
|
||||
int32_t last_stream_id,
|
||||
nghttp2_error_code error_code,
|
||||
uint32_t error_code,
|
||||
const uint8_t *opaque_data, size_t opaque_data_len)
|
||||
{
|
||||
return nghttp2_session_add_goaway(session, last_stream_id,
|
||||
@@ -265,10 +257,10 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
void *promised_stream_user_data)
|
||||
{
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_nv *nva_copy;
|
||||
uint8_t flags_copy;
|
||||
nghttp2_headers_aux_data *aux_data = NULL;
|
||||
int32_t promised_stream_id;
|
||||
int rv;
|
||||
|
||||
@@ -280,36 +272,30 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
|
||||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
frame = malloc(sizeof(nghttp2_frame));
|
||||
if(frame == NULL) {
|
||||
/* All 32bit signed stream IDs are spent. */
|
||||
if(session->next_stream_id > INT32_MAX) {
|
||||
return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
if(item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
if(promised_stream_user_data) {
|
||||
aux_data = malloc(sizeof(nghttp2_headers_aux_data));
|
||||
if(aux_data == NULL) {
|
||||
free(frame);
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
aux_data->data_prd = NULL;
|
||||
aux_data->stream_user_data = promised_stream_user_data;
|
||||
}
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
|
||||
item->aux_data.headers.stream_user_data = promised_stream_user_data;
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen);
|
||||
if(rv < 0) {
|
||||
free(aux_data);
|
||||
free(frame);
|
||||
free(item);
|
||||
return rv;
|
||||
}
|
||||
|
||||
flags_copy = NGHTTP2_FLAG_END_HEADERS;
|
||||
|
||||
/* All 32bit signed stream IDs are spent. */
|
||||
if(session->next_stream_id > INT32_MAX) {
|
||||
free(aux_data);
|
||||
free(frame);
|
||||
|
||||
return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
promised_stream_id = session->next_stream_id;
|
||||
session->next_stream_id += 2;
|
||||
|
||||
@@ -317,12 +303,11 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
|
||||
stream_id, promised_stream_id,
|
||||
nva_copy, nvlen);
|
||||
|
||||
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, aux_data);
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if(rv != 0) {
|
||||
nghttp2_frame_push_promise_free(&frame->push_promise);
|
||||
free(aux_data);
|
||||
free(frame);
|
||||
free(item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -335,7 +320,7 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||
int32_t window_size_increment)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_stream *stream;
|
||||
nghttp2_stream *stream = 0;
|
||||
if(window_size_increment == 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -348,27 +333,30 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* recv_ign_window_size keeps track of ignored DATA bytes before
|
||||
any connection-level WINDOW_UPDATE therefore, we can reset it
|
||||
here. */
|
||||
session->recv_ign_window_size = 0;
|
||||
} else {
|
||||
stream = nghttp2_session_get_stream(session, stream_id);
|
||||
if(stream) {
|
||||
rv = nghttp2_adjust_local_window_size(&stream->local_window_size,
|
||||
&stream->recv_window_size,
|
||||
&stream->recv_reduction,
|
||||
&window_size_increment);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
if(!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = nghttp2_adjust_local_window_size(&stream->local_window_size,
|
||||
&stream->recv_window_size,
|
||||
&stream->recv_reduction,
|
||||
&window_size_increment);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if(window_size_increment > 0) {
|
||||
if(stream_id == 0) {
|
||||
session->consumed_size =
|
||||
nghttp2_max(0, session->consumed_size - window_size_increment);
|
||||
} else {
|
||||
stream->consumed_size =
|
||||
nghttp2_max(0, stream->consumed_size - window_size_increment);
|
||||
}
|
||||
|
||||
return nghttp2_session_add_window_update(session, flags, stream_id,
|
||||
window_size_increment);
|
||||
}
|
||||
@@ -385,6 +373,7 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||
int rv;
|
||||
size_t varlen;
|
||||
uint8_t *var, *varp;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_ext_altsvc *altsvc;
|
||||
uint8_t *copy_protocol_id, *copy_host, *copy_origin;
|
||||
@@ -439,25 +428,28 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||
copy_origin = varp;
|
||||
}
|
||||
|
||||
frame = malloc(sizeof(nghttp2_frame));
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
|
||||
if(frame == NULL) {
|
||||
if(item == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
|
||||
goto frame_alloc_fail;
|
||||
}
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
|
||||
frame = &item->frame;
|
||||
frame->ext.payload = altsvc;
|
||||
|
||||
nghttp2_frame_altsvc_init(&frame->ext, stream_id, max_age, port,
|
||||
copy_protocol_id, protocol_id_len,
|
||||
copy_host, host_len, copy_origin, origin_len);
|
||||
|
||||
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if(rv != 0) {
|
||||
nghttp2_frame_altsvc_free(&frame->ext);
|
||||
free(frame);
|
||||
free(item);
|
||||
free(altsvc);
|
||||
|
||||
return rv;
|
||||
@@ -534,23 +526,35 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_data_provider *data_prd)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_private_data *data_frame;
|
||||
uint8_t nflags = flags & (NGHTTP2_FLAG_END_STREAM |
|
||||
NGHTTP2_FLAG_END_SEGMENT);
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_data_aux_data *aux_data;
|
||||
uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM;
|
||||
|
||||
if(stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
data_frame = malloc(sizeof(nghttp2_private_data));
|
||||
if(data_frame == NULL) {
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
if(item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
nghttp2_frame_private_data_init(data_frame, nflags, stream_id, data_prd);
|
||||
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_DATA, data_frame, NULL);
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
|
||||
frame = &item->frame;
|
||||
aux_data = &item->aux_data.data;
|
||||
aux_data->data_prd = *data_prd;
|
||||
aux_data->eof = 0;
|
||||
aux_data->flags = nflags;
|
||||
|
||||
/* flags are sent on transmission */
|
||||
nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if(rv != 0) {
|
||||
nghttp2_frame_private_data_free(data_frame);
|
||||
free(data_frame);
|
||||
nghttp2_frame_data_free(&frame->data);
|
||||
free(item);
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
|
||||
110
m4/ax_boost_asio.m4
Normal file
110
m4/ax_boost_asio.m4
Normal file
@@ -0,0 +1,110 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_boost_asio.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_ASIO
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for Asio library from the Boost C++ libraries. The macro requires a
|
||||
# preceding call to AX_BOOST_BASE. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_ASIO_LIB)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST_ASIO
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2008 Pete Greenwell <pete@mu.org>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 16
|
||||
|
||||
AC_DEFUN([AX_BOOST_ASIO],
|
||||
[
|
||||
AC_ARG_WITH([boost-asio],
|
||||
AS_HELP_STRING([--with-boost-asio@<:@=special-lib@:>@],
|
||||
[use the ASIO library from boost - it is possible to specify a certain library for the linker
|
||||
e.g. --with-boost-asio=boost_system-gcc41-mt-1_34 ]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ax_boost_user_asio_lib=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ax_boost_user_asio_lib="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_CACHE_CHECK(whether the Boost::ASIO library is available,
|
||||
ax_cv_boost_asio,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @%:@include <boost/asio.hpp>
|
||||
]],
|
||||
[[
|
||||
|
||||
boost::asio::io_service io;
|
||||
boost::system::error_code timer_result;
|
||||
boost::asio::deadline_timer t(io);
|
||||
t.cancel();
|
||||
io.run_one();
|
||||
return 0;
|
||||
]])],
|
||||
ax_cv_boost_asio=yes, ax_cv_boost_asio=no)
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
if test "x$ax_cv_boost_asio" = "xyes"; then
|
||||
AC_DEFINE(HAVE_BOOST_ASIO,,[define if the Boost::ASIO library is available])
|
||||
BN=boost_system
|
||||
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
|
||||
if test "x$ax_boost_user_asio_lib" = "x"; then
|
||||
for ax_lib in `ls $BOOSTLIBDIR/libboost_system*.so* $BOOSTLIBDIR/libboost_system*.dylib* $BOOSTLIBDIR/libboost_system*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_system.*\)\.so.*$;\1;' -e 's;^lib\(boost_system.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_system.*\)\.a.*$;\1;' ` ; do
|
||||
AC_CHECK_LIB($ax_lib, main, [BOOST_ASIO_LIB="-l$ax_lib" AC_SUBST(BOOST_ASIO_LIB) link_thread="yes" break],
|
||||
[link_thread="no"])
|
||||
done
|
||||
else
|
||||
for ax_lib in $ax_boost_user_asio_lib $BN-$ax_boost_user_asio_lib; do
|
||||
AC_CHECK_LIB($ax_lib, main,
|
||||
[BOOST_ASIO_LIB="-l$ax_lib" AC_SUBST(BOOST_ASIO_LIB) link_asio="yes" break],
|
||||
[link_asio="no"])
|
||||
done
|
||||
|
||||
fi
|
||||
if test "x$ax_lib" = "x"; then
|
||||
AC_MSG_ERROR(Could not find a version of the library!)
|
||||
fi
|
||||
if test "x$link_asio" = "xno"; then
|
||||
AC_MSG_ERROR(Could not link against $ax_lib !)
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
])
|
||||
275
m4/ax_boost_base.m4
Normal file
275
m4/ax_boost_base.m4
Normal file
@@ -0,0 +1,275 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_boost_base.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for the Boost C++ libraries of a particular version (or newer)
|
||||
#
|
||||
# If no path to the installed boost library is given the macro searchs
|
||||
# under /usr, /usr/local, /opt and /opt/local and evaluates the
|
||||
# $BOOST_ROOT environment variable. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2009 Peter Adolphs
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 25
|
||||
|
||||
AC_DEFUN([AX_BOOST_BASE],
|
||||
[
|
||||
AC_ARG_WITH([boost],
|
||||
[AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
|
||||
[use Boost library from a standard location (ARG=yes),
|
||||
from the specified location (ARG=<path>),
|
||||
or disable it (ARG=no)
|
||||
@<:@ARG=yes@:>@ ])],
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ac_boost_path=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ac_boost_path="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"])
|
||||
|
||||
|
||||
AC_ARG_WITH([boost-libdir],
|
||||
AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
|
||||
[Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]),
|
||||
[
|
||||
if test -d "$withval"
|
||||
then
|
||||
ac_boost_lib_path="$withval"
|
||||
else
|
||||
AC_MSG_ERROR(--with-boost-libdir expected directory name)
|
||||
fi
|
||||
],
|
||||
[ac_boost_lib_path=""]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
boost_lib_version_req=ifelse([$1], ,1.20.0,$1)
|
||||
boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'`
|
||||
boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'`
|
||||
boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
|
||||
boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
|
||||
if test "x$boost_lib_version_req_sub_minor" = "x" ; then
|
||||
boost_lib_version_req_sub_minor="0"
|
||||
fi
|
||||
WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor`
|
||||
AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req)
|
||||
succeeded=no
|
||||
|
||||
dnl On 64-bit systems check for system libraries in both lib64 and lib.
|
||||
dnl The former is specified by FHS, but e.g. Debian does not adhere to
|
||||
dnl this (as it rises problems for generic multi-arch support).
|
||||
dnl The last entry in the list is chosen by default when no libraries
|
||||
dnl are found, e.g. when only header-only libraries are installed!
|
||||
libsubdirs="lib"
|
||||
ax_arch=`uname -m`
|
||||
case $ax_arch in
|
||||
x86_64)
|
||||
libsubdirs="lib64 libx32 lib lib64"
|
||||
;;
|
||||
ppc64|s390x|sparc64|aarch64|ppc64le)
|
||||
libsubdirs="lib64 lib lib64 ppc64le"
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
|
||||
dnl them priority over the other paths since, if libs are found there, they
|
||||
dnl are almost assuredly the ones desired.
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
libsubdirs="lib/${host_cpu}-${host_os} $libsubdirs"
|
||||
|
||||
case ${host_cpu} in
|
||||
i?86)
|
||||
libsubdirs="lib/i386-${host_os} $libsubdirs"
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl first we check the system location for boost libraries
|
||||
dnl this location ist chosen if boost libraries are installed with the --layout=system option
|
||||
dnl or if you install boost with RPM
|
||||
if test "$ac_boost_path" != ""; then
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path/include"
|
||||
for ac_boost_path_tmp in $libsubdirs; do
|
||||
if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then
|
||||
BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp"
|
||||
break
|
||||
fi
|
||||
done
|
||||
elif test "$cross_compiling" != yes; then
|
||||
for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
|
||||
if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then
|
||||
for libsubdir in $libsubdirs ; do
|
||||
if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir"
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
dnl overwrite ld flags if we have required special directory with
|
||||
dnl --with-boost-libdir parameter
|
||||
if test "$ac_boost_lib_path" != ""; then
|
||||
BOOST_LDFLAGS="-L$ac_boost_lib_path"
|
||||
fi
|
||||
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_REQUIRE([AC_PROG_CXX])
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <boost/version.hpp>
|
||||
]], [[
|
||||
#if BOOST_VERSION >= $WANT_BOOST_VERSION
|
||||
// Everything is okay
|
||||
#else
|
||||
# error Boost version is too old
|
||||
#endif
|
||||
]])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
succeeded=yes
|
||||
found_system=yes
|
||||
],[
|
||||
])
|
||||
AC_LANG_POP([C++])
|
||||
|
||||
|
||||
|
||||
dnl if we found no boost with system layout we search for boost libraries
|
||||
dnl built and installed without the --layout=system option or for a staged(not installed) version
|
||||
if test "x$succeeded" != "xyes"; then
|
||||
_version=0
|
||||
if test "$ac_boost_path" != ""; then
|
||||
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
|
||||
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
|
||||
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
|
||||
V_CHECK=`expr $_version_tmp \> $_version`
|
||||
if test "$V_CHECK" = "1" ; then
|
||||
_version=$_version_tmp
|
||||
fi
|
||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
|
||||
done
|
||||
fi
|
||||
else
|
||||
if test "$cross_compiling" != yes; then
|
||||
for ac_boost_path in /usr /usr/local /opt /opt/local ; do
|
||||
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
|
||||
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
|
||||
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
|
||||
V_CHECK=`expr $_version_tmp \> $_version`
|
||||
if test "$V_CHECK" = "1" ; then
|
||||
_version=$_version_tmp
|
||||
best_path=$ac_boost_path
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
||||
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
|
||||
if test "$ac_boost_lib_path" = ""; then
|
||||
for libsubdir in $libsubdirs ; do
|
||||
if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
BOOST_LDFLAGS="-L$best_path/$libsubdir"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$BOOST_ROOT" != "x"; then
|
||||
for libsubdir in $libsubdirs ; do
|
||||
if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then
|
||||
version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
|
||||
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
|
||||
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
|
||||
V_CHECK=`expr $stage_version_shorten \>\= $_version`
|
||||
if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then
|
||||
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
|
||||
BOOST_CPPFLAGS="-I$BOOST_ROOT"
|
||||
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <boost/version.hpp>
|
||||
]], [[
|
||||
#if BOOST_VERSION >= $WANT_BOOST_VERSION
|
||||
// Everything is okay
|
||||
#else
|
||||
# error Boost version is too old
|
||||
#endif
|
||||
]])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
succeeded=yes
|
||||
found_system=yes
|
||||
],[
|
||||
])
|
||||
AC_LANG_POP([C++])
|
||||
fi
|
||||
|
||||
if test "$succeeded" != "yes" ; then
|
||||
if test "$_version" = "0" ; then
|
||||
AC_MSG_NOTICE([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
|
||||
else
|
||||
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
|
||||
fi
|
||||
# execute ACTION-IF-NOT-FOUND (if present):
|
||||
ifelse([$3], , :, [$3])
|
||||
else
|
||||
AC_SUBST(BOOST_CPPFLAGS)
|
||||
AC_SUBST(BOOST_LDFLAGS)
|
||||
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
|
||||
# execute ACTION-IF-FOUND (if present):
|
||||
ifelse([$2], , :, [$2])
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
|
||||
])
|
||||
120
m4/ax_boost_system.m4
Normal file
120
m4/ax_boost_system.m4
Normal file
@@ -0,0 +1,120 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_boost_system.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_SYSTEM
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for System library from the Boost C++ libraries. The macro requires
|
||||
# a preceding call to AX_BOOST_BASE. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_SYSTEM_LIB)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST_SYSTEM
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2008 Michael Tindal
|
||||
# Copyright (c) 2008 Daniel Casimiro <dan.casimiro@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 17
|
||||
|
||||
AC_DEFUN([AX_BOOST_SYSTEM],
|
||||
[
|
||||
AC_ARG_WITH([boost-system],
|
||||
AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@],
|
||||
[use the System library from boost - it is possible to specify a certain library for the linker
|
||||
e.g. --with-boost-system=boost_system-gcc-mt ]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ax_boost_user_system_lib=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ax_boost_user_system_lib="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_CANONICAL_BUILD])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_CACHE_CHECK(whether the Boost::System library is available,
|
||||
ax_cv_boost_system,
|
||||
[AC_LANG_PUSH([C++])
|
||||
CXXFLAGS_SAVE=$CXXFLAGS
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/system/error_code.hpp>]],
|
||||
[[boost::system::system_category]])],
|
||||
ax_cv_boost_system=yes, ax_cv_boost_system=no)
|
||||
CXXFLAGS=$CXXFLAGS_SAVE
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
if test "x$ax_cv_boost_system" = "xyes"; then
|
||||
AC_SUBST(BOOST_CPPFLAGS)
|
||||
|
||||
AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available])
|
||||
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
|
||||
|
||||
LDFLAGS_SAVE=$LDFLAGS
|
||||
if test "x$ax_boost_user_system_lib" = "x"; then
|
||||
for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
|
||||
[link_system="no"])
|
||||
done
|
||||
if test "x$link_system" != "xyes"; then
|
||||
for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
|
||||
[link_system="no"])
|
||||
done
|
||||
fi
|
||||
|
||||
else
|
||||
for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
|
||||
[link_system="no"])
|
||||
done
|
||||
|
||||
fi
|
||||
if test "x$ax_lib" = "x"; then
|
||||
AC_MSG_ERROR(Could not find a version of the library!)
|
||||
fi
|
||||
if test "x$link_system" = "xno"; then
|
||||
AC_MSG_ERROR(Could not link against $ax_lib !)
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
])
|
||||
149
m4/ax_boost_thread.m4
Normal file
149
m4/ax_boost_thread.m4
Normal file
@@ -0,0 +1,149 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_boost_thread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_THREAD
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for Thread library from the Boost C++ libraries. The macro requires
|
||||
# a preceding call to AX_BOOST_BASE. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_THREAD_LIB)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST_THREAD
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2009 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2009 Michael Tindal
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 27
|
||||
|
||||
AC_DEFUN([AX_BOOST_THREAD],
|
||||
[
|
||||
AC_ARG_WITH([boost-thread],
|
||||
AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@],
|
||||
[use the Thread library from boost - it is possible to specify a certain library for the linker
|
||||
e.g. --with-boost-thread=boost_thread-gcc-mt ]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ax_boost_user_thread_lib=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ax_boost_user_thread_lib="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_CANONICAL_BUILD])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_CACHE_CHECK(whether the Boost::Thread library is available,
|
||||
ax_cv_boost_thread,
|
||||
[AC_LANG_PUSH([C++])
|
||||
CXXFLAGS_SAVE=$CXXFLAGS
|
||||
|
||||
if test "x$host_os" = "xsolaris" ; then
|
||||
CXXFLAGS="-pthreads $CXXFLAGS"
|
||||
elif test "x$host_os" = "xmingw32" ; then
|
||||
CXXFLAGS="-mthreads $CXXFLAGS"
|
||||
else
|
||||
CXXFLAGS="-pthread $CXXFLAGS"
|
||||
fi
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/thread/thread.hpp>]],
|
||||
[[boost::thread_group thrds;
|
||||
return 0;]])],
|
||||
ax_cv_boost_thread=yes, ax_cv_boost_thread=no)
|
||||
CXXFLAGS=$CXXFLAGS_SAVE
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
if test "x$ax_cv_boost_thread" = "xyes"; then
|
||||
if test "x$host_os" = "xsolaris" ; then
|
||||
BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS"
|
||||
elif test "x$host_os" = "xmingw32" ; then
|
||||
BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS"
|
||||
else
|
||||
BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS"
|
||||
fi
|
||||
|
||||
AC_SUBST(BOOST_CPPFLAGS)
|
||||
|
||||
AC_DEFINE(HAVE_BOOST_THREAD,,[define if the Boost::Thread library is available])
|
||||
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
|
||||
|
||||
LDFLAGS_SAVE=$LDFLAGS
|
||||
case "x$host_os" in
|
||||
*bsd* )
|
||||
LDFLAGS="-pthread $LDFLAGS"
|
||||
break;
|
||||
;;
|
||||
esac
|
||||
if test "x$ax_boost_user_thread_lib" = "x"; then
|
||||
for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
|
||||
[link_thread="no"])
|
||||
done
|
||||
if test "x$link_thread" != "xyes"; then
|
||||
for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
|
||||
[link_thread="no"])
|
||||
done
|
||||
fi
|
||||
|
||||
else
|
||||
for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
|
||||
[link_thread="no"])
|
||||
done
|
||||
|
||||
fi
|
||||
if test "x$ax_lib" = "x"; then
|
||||
AC_MSG_ERROR(Could not find a version of the library!)
|
||||
fi
|
||||
if test "x$link_thread" = "xno"; then
|
||||
AC_MSG_ERROR(Could not link against $ax_lib !)
|
||||
else
|
||||
case "x$host_os" in
|
||||
*bsd* )
|
||||
BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS"
|
||||
break;
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
])
|
||||
104
m4/ax_have_epoll.m4
Normal file
104
m4/ax_have_epoll.m4
Normal file
@@ -0,0 +1,104 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_have_epoll.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_HAVE_EPOLL([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
# AX_HAVE_EPOLL_PWAIT([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro determines whether the system supports the epoll I/O event
|
||||
# interface. A neat usage example would be:
|
||||
#
|
||||
# AX_HAVE_EPOLL(
|
||||
# [AX_CONFIG_FEATURE_ENABLE(epoll)],
|
||||
# [AX_CONFIG_FEATURE_DISABLE(epoll)])
|
||||
# AX_CONFIG_FEATURE(
|
||||
# [epoll], [This platform supports epoll(7)],
|
||||
# [HAVE_EPOLL], [This platform supports epoll(7).])
|
||||
#
|
||||
# The epoll interface was added to the Linux kernel in version 2.5.45, and
|
||||
# the macro verifies that a kernel newer than this is installed. This
|
||||
# check is somewhat unreliable if <linux/version.h> doesn't match the
|
||||
# running kernel, but it is necessary regardless, because glibc comes with
|
||||
# stubs for the epoll_create(), epoll_wait(), etc. that allow programs to
|
||||
# compile and link even if the kernel is too old; the problem would then
|
||||
# be detected only at runtime.
|
||||
#
|
||||
# Linux kernel version 2.6.19 adds the epoll_pwait() call in addition to
|
||||
# epoll_wait(). The availability of that function can be tested with the
|
||||
# second macro. Generally speaking, it is safe to assume that
|
||||
# AX_HAVE_EPOLL would succeed if AX_HAVE_EPOLL_PWAIT has, but not the
|
||||
# other way round.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Peter Simons <simons@cryp.to>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 10
|
||||
|
||||
AC_DEFUN([AX_HAVE_EPOLL], [dnl
|
||||
ax_have_epoll_cppflags="${CPPFLAGS}"
|
||||
AC_CHECK_HEADER([linux/version.h], [CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"])
|
||||
AC_MSG_CHECKING([for Linux epoll(7) interface])
|
||||
AC_CACHE_VAL([ax_cv_have_epoll], [dnl
|
||||
AC_LINK_IFELSE([dnl
|
||||
AC_LANG_PROGRAM([dnl
|
||||
#include <sys/epoll.h>
|
||||
#ifdef HAVE_LINUX_VERSION_H
|
||||
# include <linux/version.h>
|
||||
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
|
||||
# error linux kernel version is too old to have epoll
|
||||
# endif
|
||||
#endif
|
||||
], [dnl
|
||||
int fd, rc;
|
||||
struct epoll_event ev;
|
||||
fd = epoll_create(128);
|
||||
rc = epoll_wait(fd, &ev, 1, 0);])],
|
||||
[ax_cv_have_epoll=yes],
|
||||
[ax_cv_have_epoll=no])])
|
||||
CPPFLAGS="${ax_have_epoll_cppflags}"
|
||||
AS_IF([test "${ax_cv_have_epoll}" = "yes"],
|
||||
[AC_MSG_RESULT([yes])
|
||||
$1],[AC_MSG_RESULT([no])
|
||||
$2])
|
||||
])dnl
|
||||
|
||||
AC_DEFUN([AX_HAVE_EPOLL_PWAIT], [dnl
|
||||
ax_have_epoll_cppflags="${CPPFLAGS}"
|
||||
AC_CHECK_HEADER([linux/version.h],
|
||||
[CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"])
|
||||
AC_MSG_CHECKING([for Linux epoll(7) interface with signals extension])
|
||||
AC_CACHE_VAL([ax_cv_have_epoll_pwait], [dnl
|
||||
AC_LINK_IFELSE([dnl
|
||||
AC_LANG_PROGRAM([dnl
|
||||
#ifdef HAVE_LINUX_VERSION_H
|
||||
# include <linux/version.h>
|
||||
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
# error linux kernel version is too old to have epoll_pwait
|
||||
# endif
|
||||
#endif
|
||||
#include <sys/epoll.h>
|
||||
#include <signal.h>
|
||||
], [dnl
|
||||
int fd, rc;
|
||||
struct epoll_event ev;
|
||||
fd = epoll_create(128);
|
||||
rc = epoll_wait(fd, &ev, 1, 0);
|
||||
rc = epoll_pwait(fd, &ev, 1, 0, (sigset_t const *)(0));])],
|
||||
[ax_cv_have_epoll_pwait=yes],
|
||||
[ax_cv_have_epoll_pwait=no])])
|
||||
CPPFLAGS="${ax_have_epoll_cppflags}"
|
||||
AS_IF([test "${ax_cv_have_epoll_pwait}" = "yes"],
|
||||
[AC_MSG_RESULT([yes])
|
||||
$1],[AC_MSG_RESULT([no])
|
||||
$2])
|
||||
])dnl
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This script reads man page from stdin and converts it to rst
|
||||
# document and outputs to stdout.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import sys
|
||||
import re
|
||||
@@ -8,6 +12,9 @@ def man2rst(f):
|
||||
expect_arg = False
|
||||
in_arg = False
|
||||
|
||||
sys.stdout.write('.. DO NOT MODIFY THIS FILE! '
|
||||
'It was generated by man2rst.py\n\n')
|
||||
|
||||
for line in f:
|
||||
line = line.rstrip()
|
||||
|
||||
@@ -106,6 +113,7 @@ def process_text(text):
|
||||
text = re.sub(r'\\fB(.*?)\\fR', '\\1', text)
|
||||
text = re.sub(r'\\-', '-', text)
|
||||
text = re.sub(r'\*', '\\*', text)
|
||||
text = re.sub(r'\\&', '', text)
|
||||
|
||||
return text
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This script read cipher suite list csv file [1] and prints out ECDHE
|
||||
# or DHE with AEAD ciphers only. The output is used by
|
||||
# src/shrpx_ssl.cc.
|
||||
#
|
||||
# [1] http://www.iana.org/assignments/tls-parameters/tls-parameters-4.csv
|
||||
# [2] http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import re
|
||||
import sys
|
||||
import csv
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This script reads Huffman Code table [1] and generates symbol table
|
||||
# and decoding tables in C language. The resulting code is used in
|
||||
# lib/nghttp2_hd_huffman.h and lib/nghttp2_hd_huffman_data.c
|
||||
#
|
||||
# [1] http://http2.github.io/http2-spec/compression.html
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This scripts reads static table entries [1] and generates
|
||||
# nghttp2_hd_static_entry table. This table is used in
|
||||
# lib/nghttp2_hd.c.
|
||||
#
|
||||
# [1] http://http2.github.io/http2-spec/compression.html
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import re, sys
|
||||
|
||||
def hash(s):
|
||||
@@ -13,8 +22,27 @@ for line in sys.stdin:
|
||||
val = m.group(3).strip() if m.group(3) else ''
|
||||
entries.append((hash(m.group(2)), int(m.group(1)), m.group(2), val))
|
||||
|
||||
print 'static nghttp2_hd_entry static_table[] = {'
|
||||
entries.sort()
|
||||
|
||||
print '/* Sorted by hash(name) and its table index */'
|
||||
print 'static nghttp2_hd_static_entry static_table[] = {'
|
||||
for ent in entries:
|
||||
print 'MAKE_ENT("{}", "{}", {}u, {}u),'\
|
||||
.format(ent[2], ent[3], ent[0], hash(ent[3]))
|
||||
print 'MAKE_STATIC_ENT({}, "{}", "{}", {}u, {}u),'\
|
||||
.format(ent[1] - 1, ent[2], ent[3], ent[0], hash(ent[3]))
|
||||
print '};'
|
||||
|
||||
print ''
|
||||
|
||||
print '/* Index to the position in static_table */'
|
||||
print 'const size_t static_table_index[] = {'
|
||||
for i in range(len(entries)):
|
||||
for j, ent in enumerate(entries):
|
||||
if ent[1] - 1 == i:
|
||||
sys.stdout.write('{: <2d},'.format(j))
|
||||
break
|
||||
if (i + 1) % 16 == 0:
|
||||
sys.stdout.write('\n')
|
||||
else:
|
||||
sys.stdout.write(' ')
|
||||
|
||||
print '};'
|
||||
|
||||
109
python/calcratio.py
Executable file
109
python/calcratio.py
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# This script takes directories which contain the hpack-test-case json
|
||||
# files, and calculates the compression ratio in each file and outputs
|
||||
# the result in table formatted in rst.
|
||||
#
|
||||
# The each directory contains the result of various HPACK compressor.
|
||||
#
|
||||
# The table is laid out so that we can see that how input header set
|
||||
# in one json file is compressed in each compressor.
|
||||
#
|
||||
# For hpack-test-case, see https://github.com/Jxck/hpack-test-case
|
||||
#
|
||||
import sys, json, os, re
|
||||
|
||||
class Stat:
|
||||
|
||||
def __init__(self, complen, srclen):
|
||||
self.complen = complen
|
||||
self.srclen = srclen
|
||||
|
||||
def compute_stat(jsdata):
|
||||
complen = 0
|
||||
srclen = 0
|
||||
for item in jsdata['cases']:
|
||||
complen += len(item['wire']) // 2
|
||||
srclen += \
|
||||
sum([len(list(x.keys())[0]) + len(list(x.values())[0]) \
|
||||
for x in item['headers']])
|
||||
return Stat(complen, srclen)
|
||||
|
||||
def format_result(r):
|
||||
return '{:.02f} ({}/{}) '.format(r.complen/r.srclen, r.complen, r.srclen)
|
||||
|
||||
if __name__ == '__main__':
|
||||
entries = [(os.path.basename(re.sub(r'/+$', '', p)), p) \
|
||||
for p in sys.argv[1:]]
|
||||
maxnamelen = 0
|
||||
maxstorynamelen = 0
|
||||
res = {}
|
||||
|
||||
stories = set()
|
||||
for name, ent in entries:
|
||||
files = [p for p in os.listdir(ent) if p.endswith('.json')]
|
||||
res[name] = {}
|
||||
maxnamelen = max(maxnamelen, len(name))
|
||||
for fn in files:
|
||||
stories.add(fn)
|
||||
maxstorynamelen = max(maxstorynamelen, len(fn))
|
||||
with open(os.path.join(ent, fn)) as f:
|
||||
input = f.read()
|
||||
rv = compute_stat(json.loads(input))
|
||||
res[name][fn] = rv
|
||||
maxnamelen = max(maxnamelen, len(format_result(rv)))
|
||||
stories = list(stories)
|
||||
stories.sort()
|
||||
|
||||
storynameformat = '{{:{}}} '.format(maxstorynamelen)
|
||||
nameformat = '{{:{}}} '.format(maxnamelen)
|
||||
|
||||
|
||||
sys.stdout.write('''\
|
||||
hpack-test-case compression ratio
|
||||
=================================
|
||||
|
||||
The each cell has ``X (Y/Z)`` format:
|
||||
|
||||
X
|
||||
Y / Z
|
||||
Y
|
||||
number of bytes after compression
|
||||
Z
|
||||
number of bytes before compression
|
||||
|
||||
''')
|
||||
|
||||
def write_border():
|
||||
sys.stdout.write('='*maxstorynamelen)
|
||||
sys.stdout.write(' ')
|
||||
for _ in entries:
|
||||
sys.stdout.write('='*maxnamelen)
|
||||
sys.stdout.write(' ')
|
||||
sys.stdout.write('\n')
|
||||
|
||||
write_border()
|
||||
|
||||
sys.stdout.write(storynameformat.format('story'))
|
||||
for name, _ in entries:
|
||||
sys.stdout.write(nameformat.format(name))
|
||||
sys.stdout.write('\n')
|
||||
|
||||
write_border()
|
||||
|
||||
for story in stories:
|
||||
sys.stdout.write(storynameformat.format(story))
|
||||
srclen = -1
|
||||
for name, _ in entries:
|
||||
stats = res[name]
|
||||
if story not in stats:
|
||||
sys.stdout.write(nameformat.format('N/A'))
|
||||
continue
|
||||
if srclen == -1:
|
||||
srclen = stats[story].srclen
|
||||
elif srclen != stats[story].srclen:
|
||||
raise Exception('Bad srclen')
|
||||
sys.stdout.write(nameformat.format(format_result(stats[story])))
|
||||
sys.stdout.write('\n')
|
||||
|
||||
write_border()
|
||||
@@ -102,7 +102,7 @@ cdef extern from 'nghttp2/nghttp2.h':
|
||||
|
||||
ctypedef struct nghttp2_rst_stream:
|
||||
nghttp2_frame_hd hd
|
||||
nghttp2_error_code error_code
|
||||
uint32_t error_code
|
||||
|
||||
|
||||
ctypedef struct nghttp2_push_promise:
|
||||
@@ -114,7 +114,7 @@ cdef extern from 'nghttp2/nghttp2.h':
|
||||
ctypedef struct nghttp2_goaway:
|
||||
nghttp2_frame_hd hd
|
||||
int32_t last_stream_id
|
||||
nghttp2_error_code error_code
|
||||
uint32_t error_code
|
||||
uint8_t *opaque_data
|
||||
size_t opaque_data_len
|
||||
|
||||
@@ -142,7 +142,7 @@ cdef extern from 'nghttp2/nghttp2.h':
|
||||
|
||||
ctypedef int (*nghttp2_on_stream_close_callback)\
|
||||
(nghttp2_session *session, int32_t stream_id,
|
||||
nghttp2_error_code error_code, void *user_data)
|
||||
uint32_t error_code, void *user_data)
|
||||
|
||||
ctypedef int (*nghttp2_on_begin_headers_callback)\
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
@@ -163,15 +163,47 @@ cdef extern from 'nghttp2/nghttp2.h':
|
||||
int lib_error_code, void *user_data)
|
||||
|
||||
ctypedef struct nghttp2_session_callbacks:
|
||||
nghttp2_send_callback send_callback
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback
|
||||
nghttp2_on_header_callback on_header_callback
|
||||
pass
|
||||
|
||||
int nghttp2_session_callbacks_new(
|
||||
nghttp2_session_callbacks **callbacks_ptr)
|
||||
|
||||
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks)
|
||||
|
||||
void nghttp2_session_callbacks_set_send_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_before_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_header_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback on_header_callback)
|
||||
|
||||
int nghttp2_session_client_new(nghttp2_session **session_ptr,
|
||||
const nghttp2_session_callbacks *callbacks,
|
||||
@@ -233,7 +265,7 @@ cdef extern from 'nghttp2/nghttp2.h':
|
||||
|
||||
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
nghttp2_error_code error_code)
|
||||
uint32_t error_code)
|
||||
|
||||
void* nghttp2_session_get_stream_user_data(nghttp2_session *session,
|
||||
uint32_t stream_id)
|
||||
@@ -243,7 +275,7 @@ cdef extern from 'nghttp2/nghttp2.h':
|
||||
void *stream_user_data)
|
||||
|
||||
int nghttp2_session_terminate_session(nghttp2_session *session,
|
||||
nghttp2_error_code error_code)
|
||||
uint32_t error_code)
|
||||
|
||||
const char* nghttp2_strerror(int lib_error_code)
|
||||
|
||||
@@ -252,9 +284,6 @@ cdef extern from 'nghttp2/nghttp2.h':
|
||||
|
||||
void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater)
|
||||
|
||||
void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater,
|
||||
uint8_t no_refset)
|
||||
|
||||
int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
|
||||
size_t hd_table_bufsize_max)
|
||||
|
||||
@@ -291,9 +320,6 @@ cdef extern from 'nghttp2_hd.h':
|
||||
# This is macro
|
||||
int NGHTTP2_HD_ENTRY_OVERHEAD
|
||||
|
||||
ctypedef enum nghttp2_hd_flags:
|
||||
NGHTTP2_HD_FLAG_REFSET
|
||||
|
||||
ctypedef enum nghttp2_hd_inflate_flag:
|
||||
NGHTTP2_HD_INFLATE_EMIT
|
||||
NGHTTP2_HD_INFLATE_FINAL
|
||||
|
||||
@@ -27,8 +27,6 @@ def testsuite(testdata):
|
||||
|
||||
expected_hdrs = [(list(x.keys())[0],
|
||||
list(x.values())[0]) for x in item['headers']]
|
||||
hdrs.sort()
|
||||
expected_hdrs.sort()
|
||||
if hdrs != expected_hdrs:
|
||||
if 'seqno' in item:
|
||||
seqno = item['seqno']
|
||||
@@ -53,7 +51,7 @@ if __name__ == '__main__':
|
||||
|
||||
testdata = json.loads(input)
|
||||
|
||||
if 'draft' not in testdata or testdata['draft'] != 8:
|
||||
if 'draft' not in testdata or testdata['draft'] != 9:
|
||||
sys.stderr.write('Not supported\n')
|
||||
continue
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import nghttp2
|
||||
def testsuite(testdata, filename, outdir, table_size, deflate_table_size,
|
||||
simulate_table_size_change):
|
||||
res = {
|
||||
'draft':8,
|
||||
'draft':9,
|
||||
'description': '''\
|
||||
Encoded by nghttp2. The basic encoding strategy is described in \
|
||||
http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html \
|
||||
|
||||
@@ -33,12 +33,11 @@ HD_ENTRY_OVERHEAD = cnghttp2.NGHTTP2_HD_ENTRY_OVERHEAD
|
||||
|
||||
class HDTableEntry:
|
||||
|
||||
def __init__(self, name, namelen, value, valuelen, ref):
|
||||
def __init__(self, name, namelen, value, valuelen):
|
||||
self.name = name
|
||||
self.namelen = namelen
|
||||
self.value = value
|
||||
self.valuelen = valuelen
|
||||
self.ref = ref
|
||||
|
||||
def space(self):
|
||||
return self.namelen + self.valuelen + HD_ENTRY_OVERHEAD
|
||||
@@ -52,8 +51,7 @@ cdef _get_hd_table(cnghttp2.nghttp2_hd_context *ctx):
|
||||
k = _get_pybytes(entry.nv.name, entry.nv.namelen)
|
||||
v = _get_pybytes(entry.nv.value, entry.nv.valuelen)
|
||||
res.append(HDTableEntry(k, entry.nv.namelen,
|
||||
v, entry.nv.valuelen,
|
||||
(entry.flags & cnghttp2.NGHTTP2_HD_FLAG_REFSET) != 0))
|
||||
v, entry.nv.valuelen))
|
||||
return res
|
||||
|
||||
cdef _get_pybytes(uint8_t *b, uint16_t blen):
|
||||
@@ -143,15 +141,6 @@ cdef class HDDeflater:
|
||||
|
||||
return res
|
||||
|
||||
def set_no_refset(self, no_refset):
|
||||
'''Tells the compressor not to use reference set if |no_refset| is
|
||||
nonzero. If |no_refset| is nonzero, on each invocation of
|
||||
deflate(), compressor first emits index=0 to clear up
|
||||
reference set.
|
||||
|
||||
'''
|
||||
cnghttp2.nghttp2_hd_deflate_set_no_refset(self._deflater, no_refset)
|
||||
|
||||
def change_table_size(self, hd_table_bufsize_max):
|
||||
'''Changes header table size to |hd_table_bufsize_max| byte.
|
||||
|
||||
@@ -243,16 +232,14 @@ def print_hd_table(hdtable):
|
||||
function does not work if header name/value cannot be decoded using
|
||||
UTF-8 encoding.
|
||||
|
||||
s=N means the entry occupies N bytes in header table. if r=y, then
|
||||
the entry is in the reference set.
|
||||
s=N means the entry occupies N bytes in header table.
|
||||
|
||||
'''
|
||||
idx = 0
|
||||
for entry in hdtable:
|
||||
idx += 1
|
||||
print('[{}] (s={}) (r={}) {}: {}'\
|
||||
print('[{}] (s={}) {}: {}'\
|
||||
.format(idx, entry.space(),
|
||||
'y' if entry.ref else 'n',
|
||||
entry.name.decode('utf-8'),
|
||||
entry.value.decode('utf-8')))
|
||||
|
||||
@@ -443,7 +430,7 @@ cdef int server_on_frame_not_send(cnghttp2.nghttp2_session *session,
|
||||
|
||||
cdef int server_on_stream_close(cnghttp2.nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
cnghttp2.nghttp2_error_code error_code,
|
||||
uint32_t error_code,
|
||||
void *user_data):
|
||||
cdef http2 = <_HTTP2SessionCore>user_data
|
||||
|
||||
@@ -492,7 +479,7 @@ cdef class _HTTP2SessionCore:
|
||||
cdef settings_timer
|
||||
|
||||
def __cinit__(self, transport, handler_class):
|
||||
cdef cnghttp2.nghttp2_session_callbacks callbacks
|
||||
cdef cnghttp2.nghttp2_session_callbacks *callbacks
|
||||
cdef cnghttp2.nghttp2_settings_entry iv[2]
|
||||
cdef int rv
|
||||
|
||||
@@ -503,17 +490,32 @@ cdef class _HTTP2SessionCore:
|
||||
self.handlers = set()
|
||||
self.settings_timer = None
|
||||
|
||||
memset(&callbacks, 0, sizeof(callbacks))
|
||||
callbacks.on_header_callback = server_on_header
|
||||
callbacks.on_begin_headers_callback = server_on_begin_headers
|
||||
callbacks.on_frame_recv_callback = server_on_frame_recv
|
||||
callbacks.on_stream_close_callback = server_on_stream_close
|
||||
callbacks.on_frame_send_callback = server_on_frame_send
|
||||
callbacks.on_frame_not_send_callback = server_on_frame_not_send
|
||||
callbacks.on_data_chunk_recv_callback = server_on_data_chunk_recv
|
||||
rv = cnghttp2.nghttp2_session_callbacks_new(&callbacks)
|
||||
|
||||
rv = cnghttp2.nghttp2_session_server_new(&self.session, &callbacks,
|
||||
if rv != 0:
|
||||
raise Exception('nghttp2_session_callbacks_new failed: {}'.format\
|
||||
(_strerror(rv)))
|
||||
|
||||
cnghttp2.nghttp2_session_callbacks_set_on_header_callback(
|
||||
callbacks, server_on_header)
|
||||
cnghttp2.nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
callbacks, server_on_begin_headers)
|
||||
cnghttp2.nghttp2_session_callbacks_set_on_frame_recv_callback(
|
||||
callbacks, server_on_frame_recv)
|
||||
cnghttp2.nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, server_on_stream_close)
|
||||
cnghttp2.nghttp2_session_callbacks_set_on_frame_send_callback(
|
||||
callbacks, server_on_frame_send)
|
||||
cnghttp2.nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||
callbacks, server_on_frame_not_send)
|
||||
cnghttp2.nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
callbacks, server_on_data_chunk_recv)
|
||||
|
||||
rv = cnghttp2.nghttp2_session_server_new(&self.session, callbacks,
|
||||
<void*>self)
|
||||
|
||||
cnghttp2.nghttp2_session_callbacks_del(callbacks)
|
||||
|
||||
if rv != 0:
|
||||
raise Exception('nghttp2_session_server_new failed: {}'.format\
|
||||
(_strerror(rv)))
|
||||
|
||||
@@ -34,6 +34,7 @@ setup(
|
||||
name = 'python-nghttp2',
|
||||
description = 'Python HTTP/2 library on top of nghttp2',
|
||||
author = 'Tatsuhiro Tsujikawa',
|
||||
version = '@PACKAGE_VERSION@',
|
||||
author_email = 'tatsuhiro.t@gmail.com',
|
||||
url = 'http://tatsuhiro-t.github.io/nghttp2/',
|
||||
keywords = [],
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
#include <event.h>
|
||||
#include <event2/listener.h>
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/bufferevent_ssl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -58,6 +58,7 @@ extern "C" {
|
||||
#include "app_helper.h"
|
||||
#include "http2.h"
|
||||
#include "util.h"
|
||||
#include "libevent_util.h"
|
||||
#include "ssl.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
@@ -68,6 +69,7 @@ namespace nghttp2 {
|
||||
|
||||
namespace {
|
||||
const std::string STATUS_200 = "200";
|
||||
const std::string STATUS_301 = "301";
|
||||
const std::string STATUS_304 = "304";
|
||||
const std::string STATUS_400 = "400";
|
||||
const std::string STATUS_404 = "404";
|
||||
@@ -94,9 +96,9 @@ namespace {
|
||||
void append_nv(Stream *stream, const std::vector<nghttp2_nv>& nva)
|
||||
{
|
||||
for(auto& nv : nva) {
|
||||
http2::split_add_header(stream->headers,
|
||||
nv.name, nv.namelen, nv.value, nv.valuelen,
|
||||
nv.flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||
http2::add_header(stream->headers,
|
||||
nv.name, nv.namelen, nv.value, nv.valuelen,
|
||||
nv.flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
@@ -104,6 +106,7 @@ void append_nv(Stream *stream, const std::vector<nghttp2_nv>& nva)
|
||||
Config::Config()
|
||||
: stream_read_timeout{60, 0},
|
||||
stream_write_timeout{60, 0},
|
||||
session_option(nullptr),
|
||||
data_ptr(nullptr),
|
||||
padding(0),
|
||||
num_worker(1),
|
||||
@@ -115,7 +118,15 @@ Config::Config()
|
||||
no_tls(false),
|
||||
error_gzip(false),
|
||||
early_response(false)
|
||||
{}
|
||||
{
|
||||
nghttp2_option_new(&session_option);
|
||||
nghttp2_option_set_recv_client_preface(session_option, 1);
|
||||
}
|
||||
|
||||
Config::~Config()
|
||||
{
|
||||
nghttp2_option_del(session_option);
|
||||
}
|
||||
|
||||
Stream::Stream(Http2Handler *handler, int32_t stream_id)
|
||||
: handler(handler),
|
||||
@@ -213,19 +224,29 @@ void remove_stream_write_timeout(Stream *stream)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config);
|
||||
} // namespace
|
||||
|
||||
class Sessions {
|
||||
public:
|
||||
Sessions(event_base *evbase, const Config *config, SSL_CTX *ssl_ctx)
|
||||
: evbase_(evbase),
|
||||
config_(config),
|
||||
ssl_ctx_(ssl_ctx),
|
||||
callbacks_(nullptr),
|
||||
next_session_id_(1)
|
||||
{}
|
||||
{
|
||||
nghttp2_session_callbacks_new(&callbacks_);
|
||||
|
||||
fill_callback(callbacks_, config_);
|
||||
}
|
||||
~Sessions()
|
||||
{
|
||||
for(auto handler : handlers_) {
|
||||
delete handler;
|
||||
}
|
||||
nghttp2_session_callbacks_del(callbacks_);
|
||||
}
|
||||
void add_handler(Http2Handler *handler)
|
||||
{
|
||||
@@ -269,6 +290,10 @@ public:
|
||||
}
|
||||
return session_id;
|
||||
}
|
||||
const nghttp2_session_callbacks* get_callbacks() const
|
||||
{
|
||||
return callbacks_;
|
||||
}
|
||||
void accept_connection(int fd)
|
||||
{
|
||||
int val = 1;
|
||||
@@ -297,6 +322,7 @@ private:
|
||||
event_base *evbase_;
|
||||
const Config *config_;
|
||||
SSL_CTX *ssl_ctx_;
|
||||
nghttp2_session_callbacks *callbacks_;
|
||||
int64_t next_session_id_;
|
||||
};
|
||||
|
||||
@@ -311,36 +337,20 @@ void on_session_closed(Http2Handler *hd, int64_t session_id)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config);
|
||||
} // namespace
|
||||
|
||||
Http2Handler::Http2Handler(Sessions *sessions,
|
||||
int fd, SSL *ssl, int64_t session_id)
|
||||
: session_id_(session_id),
|
||||
session_(nullptr),
|
||||
sessions_(sessions),
|
||||
ssl_(ssl),
|
||||
rev_(nullptr),
|
||||
wev_(nullptr),
|
||||
bev_(nullptr),
|
||||
settings_timerev_(nullptr),
|
||||
pending_data_(nullptr),
|
||||
pending_datalen_(0),
|
||||
left_connhd_len_(NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN),
|
||||
fd_(fd)
|
||||
{
|
||||
nghttp2_buf_wrap_init(&sendbuf_, sendbufarray_, sizeof(sendbufarray_));
|
||||
}
|
||||
{}
|
||||
|
||||
Http2Handler::~Http2Handler()
|
||||
{
|
||||
on_session_closed(this, session_id_);
|
||||
if(rev_) {
|
||||
event_free(rev_);
|
||||
}
|
||||
if(wev_) {
|
||||
event_free(wev_);
|
||||
}
|
||||
if(settings_timerev_) {
|
||||
event_free(settings_timerev_);
|
||||
}
|
||||
@@ -349,6 +359,10 @@ Http2Handler::~Http2Handler()
|
||||
SSL_set_shutdown(ssl_, SSL_RECEIVED_SHUTDOWN);
|
||||
SSL_shutdown(ssl_);
|
||||
}
|
||||
if(bev_) {
|
||||
bufferevent_disable(bev_, EV_READ | EV_WRITE);
|
||||
bufferevent_free(bev_);
|
||||
}
|
||||
if(ssl_) {
|
||||
SSL_free(ssl_);
|
||||
}
|
||||
@@ -362,329 +376,93 @@ void Http2Handler::remove_self()
|
||||
}
|
||||
|
||||
namespace {
|
||||
void rev_cb(evutil_socket_t fd, short what, void *arg)
|
||||
void readcb(bufferevent *bev, void *arg)
|
||||
{
|
||||
int rv;
|
||||
auto handler = static_cast<Http2Handler*>(arg);
|
||||
|
||||
if(what & EV_READ) {
|
||||
rv = handler->on_read();
|
||||
if(rv == -1) {
|
||||
delete_handler(handler);
|
||||
}
|
||||
rv = handler->on_read();
|
||||
if(rv == -1) {
|
||||
delete_handler(handler);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void wev_cb(evutil_socket_t fd, short what, void *arg)
|
||||
void writecb(bufferevent *bev, void *arg)
|
||||
{
|
||||
int rv;
|
||||
auto handler = static_cast<Http2Handler*>(arg);
|
||||
|
||||
if(what & EV_WRITE) {
|
||||
rv = handler->on_write();
|
||||
if(rv == -1) {
|
||||
delete_handler(handler);
|
||||
}
|
||||
rv = handler->on_write();
|
||||
if(rv == -1) {
|
||||
delete_handler(handler);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int Http2Handler::handle_ssl_temporal_error(int err)
|
||||
{
|
||||
auto sslerr = SSL_get_error(ssl_, err);
|
||||
|
||||
switch(sslerr) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
event_add(rev_, nullptr);
|
||||
return 1;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
event_add(wev_, nullptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Http2Handler::tls_write(const uint8_t *data, size_t datalen)
|
||||
{
|
||||
int rv;
|
||||
size_t max_avail;
|
||||
|
||||
// OpenSSL sends at most 16K bytes
|
||||
max_avail = ssl_ ?
|
||||
std::min((ssize_t)16384, nghttp2_buf_avail(&sendbuf_)) :
|
||||
nghttp2_buf_avail(&sendbuf_);
|
||||
|
||||
if(max_avail < datalen) {
|
||||
if(nghttp2_buf_len(&sendbuf_) > 0) {
|
||||
rv = tls_write_pending();
|
||||
|
||||
if(rv == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(rv == 1) {
|
||||
pending_data_ = data;
|
||||
pending_datalen_ = datalen;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert(nghttp2_buf_avail(&sendbuf_) >= (ssize_t)datalen);
|
||||
}
|
||||
//std::cerr << "DBG: copy " << datalen << " bytes" << std::endl;
|
||||
sendbuf_.last = nghttp2_cpymem(sendbuf_.last, data, datalen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Http2Handler::tls_write_pending()
|
||||
{
|
||||
int rv;
|
||||
|
||||
if(nghttp2_buf_len(&sendbuf_) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
if(ssl_) {
|
||||
ERR_clear_error();
|
||||
|
||||
rv = SSL_write(ssl_, sendbuf_.pos, nghttp2_buf_len(&sendbuf_));
|
||||
|
||||
if(rv == 0) {
|
||||
return -1;
|
||||
}
|
||||
if(rv < 0) {
|
||||
return handle_ssl_temporal_error(rv);
|
||||
}
|
||||
} else {
|
||||
while((rv = write(fd_, sendbuf_.pos, nghttp2_buf_len(&sendbuf_))) &&
|
||||
rv == -1 && errno == EINTR);
|
||||
|
||||
if(rv == 0) {
|
||||
continue;
|
||||
}
|
||||
if(rv < 0) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
event_add(wev_, nullptr);
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
sendbuf_.pos += rv;
|
||||
|
||||
if(nghttp2_buf_len(&sendbuf_) == 0) {
|
||||
nghttp2_buf_reset(&sendbuf_);
|
||||
|
||||
if(pending_data_) {
|
||||
assert(nghttp2_buf_avail(&sendbuf_) >= (ssize_t)pending_datalen_);
|
||||
sendbuf_.last = nghttp2_cpymem(sendbuf_.last,
|
||||
pending_data_, pending_datalen_);
|
||||
pending_data_ = nullptr;
|
||||
pending_datalen_ = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void tls_handshake_cb(evutil_socket_t fd, short what, void *arg)
|
||||
void eventcb(bufferevent *bev, short events, void *arg)
|
||||
{
|
||||
int rv;
|
||||
auto handler = static_cast<Http2Handler*>(arg);
|
||||
|
||||
if(what & (EV_READ | EV_WRITE)) {
|
||||
rv = handler->tls_handshake();
|
||||
if(rv == -1) {
|
||||
delete_handler(handler);
|
||||
return;
|
||||
if(events & (BEV_EVENT_EOF | BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT)) {
|
||||
delete_handler(handler);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(events & BEV_EVENT_CONNECTED) {
|
||||
if(handler->get_sessions()->get_config()->verbose) {
|
||||
std::cerr << "SSL/TLS handshake completed" << std::endl;
|
||||
}
|
||||
if(rv == 1) {
|
||||
|
||||
if(handler->verify_npn_result() != 0) {
|
||||
delete_handler(handler);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rv = handler->on_connect();
|
||||
if(rv != 0) {
|
||||
if(handler->on_connect() != 0) {
|
||||
delete_handler(handler);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int Http2Handler::tls_handshake()
|
||||
{
|
||||
int rv;
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
rv = SSL_accept(ssl_);
|
||||
if(rv == 0) {
|
||||
return -1;
|
||||
}
|
||||
if(rv < 0) {
|
||||
auto sslerr = SSL_get_error(ssl_, rv);
|
||||
|
||||
switch(sslerr) {
|
||||
case SSL_ERROR_NONE:
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
event_add(rev_, nullptr);
|
||||
return 1;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
event_add(wev_, nullptr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(sessions_->get_config()->verbose) {
|
||||
std::cerr << "SSL/TLS handshake completed" << std::endl;
|
||||
}
|
||||
|
||||
if(verify_npn_result() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
event_del(rev_);
|
||||
event_del(wev_);
|
||||
|
||||
event_assign(rev_, sessions_->get_evbase(), fd_, EV_READ, rev_cb, this);
|
||||
event_assign(wev_, sessions_->get_evbase(), fd_, EV_WRITE, wev_cb, this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Http2Handler::setup_bev()
|
||||
{
|
||||
auto evbase = sessions_->get_evbase();
|
||||
|
||||
if(ssl_) {
|
||||
rev_ = event_new(sessions_->get_evbase(), fd_, EV_READ, tls_handshake_cb,
|
||||
this);
|
||||
wev_ = event_new(sessions_->get_evbase(), fd_, EV_WRITE, tls_handshake_cb,
|
||||
this);
|
||||
bev_ = bufferevent_openssl_socket_new(evbase, fd_, ssl_,
|
||||
BUFFEREVENT_SSL_ACCEPTING,
|
||||
BEV_OPT_DEFER_CALLBACKS);
|
||||
} else {
|
||||
rev_ = event_new(sessions_->get_evbase(), fd_, EV_READ, rev_cb, this);
|
||||
wev_ = event_new(sessions_->get_evbase(), fd_, EV_WRITE, wev_cb, this);
|
||||
bev_ = bufferevent_socket_new(evbase, fd_, BEV_OPT_DEFER_CALLBACKS);
|
||||
}
|
||||
|
||||
event_add(rev_, nullptr);
|
||||
// TODO set up timeout here
|
||||
bufferevent_enable(bev_, EV_READ);
|
||||
bufferevent_setcb(bev_, readcb, writecb, eventcb, this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Http2Handler::wait_events()
|
||||
{
|
||||
int active = 0;
|
||||
|
||||
if(nghttp2_session_want_read(session_)) {
|
||||
event_add(rev_, nullptr);
|
||||
active = 1;
|
||||
}
|
||||
|
||||
if(nghttp2_session_want_write(session_)) {
|
||||
event_add(wev_, nullptr);
|
||||
active = 1;
|
||||
}
|
||||
|
||||
if(pending_datalen_ > 0) {
|
||||
active = 1;
|
||||
}
|
||||
|
||||
return active ? 0 : -1;
|
||||
}
|
||||
|
||||
int Http2Handler::on_read()
|
||||
int Http2Handler::send()
|
||||
{
|
||||
int rv;
|
||||
uint8_t buf[16384];
|
||||
uint8_t *bufp;
|
||||
size_t nread;
|
||||
|
||||
if(ssl_) {
|
||||
ERR_clear_error();
|
||||
rv = SSL_read(ssl_, buf, sizeof(buf));
|
||||
|
||||
if(rv == 0) {
|
||||
return -1;
|
||||
}
|
||||
if(rv < 0) {
|
||||
return handle_ssl_temporal_error(rv);
|
||||
}
|
||||
} else {
|
||||
while((rv = read(fd_, buf, sizeof(buf))) && rv == -1 && errno == EINTR);
|
||||
|
||||
if(rv == 0) {
|
||||
return -1;
|
||||
}
|
||||
if(rv < 0) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
event_add(rev_, nullptr);
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
nread = rv;
|
||||
bufp = buf;
|
||||
|
||||
if(left_connhd_len_ > 0) {
|
||||
auto len = std::min(left_connhd_len_, nread);
|
||||
const char *conhead = NGHTTP2_CLIENT_CONNECTION_PREFACE;
|
||||
|
||||
if(memcmp(conhead + NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN -
|
||||
left_connhd_len_, bufp, len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
left_connhd_len_ -= len;
|
||||
nread -= len;
|
||||
|
||||
if(nread == 0) {
|
||||
wait_events();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bufp += len;
|
||||
}
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, bufp, nread);
|
||||
if(rv < 0) {
|
||||
std::cerr << "nghttp2_session_mem_recv() returned error: "
|
||||
<< nghttp2_strerror(rv) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return wait_events();
|
||||
}
|
||||
|
||||
int Http2Handler::on_write()
|
||||
{
|
||||
int rv;
|
||||
|
||||
//std::cerr << "DBG: on_write" << std::endl;
|
||||
|
||||
rv = tls_write_pending();
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
auto output = bufferevent_get_output(bev_);
|
||||
util::EvbufferBuffer evbbuf(output, buf, sizeof(buf));
|
||||
for(;;) {
|
||||
const uint8_t *data;
|
||||
// Check buffer length and break if it is large enough.
|
||||
if(evbuffer_get_length(output) + evbbuf.get_buflen() >= 65536) {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t *data;
|
||||
auto datalen = nghttp2_session_mem_send(session_, &data);
|
||||
|
||||
if(datalen < 0) {
|
||||
@@ -692,24 +470,65 @@ int Http2Handler::on_write()
|
||||
<< nghttp2_strerror(datalen) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(datalen == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
rv = tls_write(data, datalen);
|
||||
|
||||
rv = evbbuf.add(data, datalen);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
std::cerr << "evbuffer_add() failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rv = tls_write_pending();
|
||||
rv = evbbuf.flush();
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
std::cerr << "evbuffer_add() failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return wait_events();
|
||||
if(nghttp2_session_want_read(session_) == 0 &&
|
||||
nghttp2_session_want_write(session_) == 0 &&
|
||||
evbuffer_get_length(output) == 0) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Http2Handler::on_read()
|
||||
{
|
||||
int rv;
|
||||
|
||||
auto input = bufferevent_get_input(bev_);
|
||||
|
||||
for(;;) {
|
||||
auto len = evbuffer_get_contiguous_space(input);
|
||||
|
||||
if(len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto data = evbuffer_pullup(input, len);
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, data, len);
|
||||
if(rv < 0) {
|
||||
std::cerr << "nghttp2_session_mem_recv() returned error: "
|
||||
<< nghttp2_strerror(rv) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(evbuffer_drain(input, len) == -1) {
|
||||
std::cerr << "evbuffer_drain() failed" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return send();
|
||||
}
|
||||
|
||||
int Http2Handler::on_write()
|
||||
{
|
||||
return send();
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -724,9 +543,9 @@ void settings_timeout_cb(evutil_socket_t fd, short what, void *arg)
|
||||
int Http2Handler::on_connect()
|
||||
{
|
||||
int r;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
fill_callback(callbacks, sessions_->get_config());
|
||||
r = nghttp2_session_server_new(&session_, &callbacks, this);
|
||||
|
||||
r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
|
||||
sessions_->get_config()->session_option);
|
||||
if(r != 0) {
|
||||
return r;
|
||||
}
|
||||
@@ -814,7 +633,7 @@ int Http2Handler::submit_file_response(const std::string& status,
|
||||
int Http2Handler::submit_response
|
||||
(const std::string& status,
|
||||
int32_t stream_id,
|
||||
const std::vector<std::pair<std::string, std::string>>& headers,
|
||||
const Headers& headers,
|
||||
nghttp2_data_provider *data_prd)
|
||||
{
|
||||
std::string date_str = util::http_date(time(0));
|
||||
@@ -823,8 +642,8 @@ int Http2Handler::submit_response
|
||||
http2::make_nv_ls("server", NGHTTPD_SERVER),
|
||||
http2::make_nv_ls("date", date_str)
|
||||
};
|
||||
for(size_t i = 0; i < headers.size(); ++i) {
|
||||
nva.push_back(http2::make_nv(headers[i].first, headers[i].second, false));
|
||||
for(auto& nv : headers) {
|
||||
nva.push_back(http2::make_nv(nv.name, nv.value, nv.no_index));
|
||||
}
|
||||
int r = nghttp2_submit_response(session_, stream_id, nva.data(), nva.size(),
|
||||
data_prd);
|
||||
@@ -843,10 +662,19 @@ int Http2Handler::submit_response(const std::string& status,
|
||||
data_prd);
|
||||
}
|
||||
|
||||
int Http2Handler::submit_non_final_response(const std::string& status,
|
||||
int32_t stream_id)
|
||||
{
|
||||
auto nva = std::vector<nghttp2_nv>{
|
||||
http2::make_nv_ls(":status", status)
|
||||
};
|
||||
return nghttp2_submit_headers(session_, NGHTTP2_FLAG_NONE, stream_id,
|
||||
nullptr, nva.data(), nva.size(), nullptr);
|
||||
}
|
||||
|
||||
int Http2Handler::submit_push_promise(Stream *stream,
|
||||
const std::string& push_path)
|
||||
{
|
||||
std::string authority;
|
||||
auto itr = std::lower_bound(std::begin(stream->headers),
|
||||
std::end(stream->headers),
|
||||
Header(":authority", ""));
|
||||
@@ -877,14 +705,13 @@ int Http2Handler::submit_push_promise(Stream *stream,
|
||||
|
||||
auto promised_stream = util::make_unique<Stream>(this, promised_stream_id);
|
||||
|
||||
append_nv(promised_stream.get(), http2::sort_nva(nva.data(), nva.size()));
|
||||
append_nv(promised_stream.get(), nva);
|
||||
add_stream(promised_stream_id, std::move(promised_stream));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Http2Handler::submit_rst_stream(Stream *stream,
|
||||
nghttp2_error_code error_code)
|
||||
int Http2Handler::submit_rst_stream(Stream *stream, uint32_t error_code)
|
||||
{
|
||||
remove_stream_read_timeout(stream);
|
||||
remove_stream_write_timeout(stream);
|
||||
@@ -928,16 +755,6 @@ const Config* Http2Handler::get_config() const
|
||||
return sessions_->get_config();
|
||||
}
|
||||
|
||||
size_t Http2Handler::get_left_connhd_len() const
|
||||
{
|
||||
return left_connhd_len_;
|
||||
}
|
||||
|
||||
void Http2Handler::set_left_connhd_len(size_t left)
|
||||
{
|
||||
left_connhd_len_ = left;
|
||||
}
|
||||
|
||||
void Http2Handler::remove_settings_timer()
|
||||
{
|
||||
if(settings_timerev_) {
|
||||
@@ -947,7 +764,7 @@ void Http2Handler::remove_settings_timer()
|
||||
}
|
||||
}
|
||||
|
||||
void Http2Handler::terminate_session(nghttp2_error_code error_code)
|
||||
void Http2Handler::terminate_session(uint32_t error_code)
|
||||
{
|
||||
nghttp2_session_terminate_session(session_, error_code);
|
||||
}
|
||||
@@ -986,18 +803,6 @@ ssize_t file_read_callback
|
||||
return nread;
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool check_url(const std::string& url)
|
||||
{
|
||||
// We don't like '\' in url.
|
||||
return !url.empty() && url[0] == '/' &&
|
||||
url.find('\\') == std::string::npos &&
|
||||
url.find("/../") == std::string::npos &&
|
||||
url.find("/./") == std::string::npos &&
|
||||
!util::endsWith(url, "/..") && !util::endsWith(url, "/.");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void prepare_status_response(Stream *stream, Http2Handler *hd,
|
||||
const std::string& status)
|
||||
@@ -1020,7 +825,7 @@ void prepare_status_response(Stream *stream, Http2Handler *hd,
|
||||
body += "</address>";
|
||||
body += "</body></html>";
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> headers;
|
||||
Headers headers;
|
||||
if(hd->get_config()->error_gzip) {
|
||||
gzFile write_fd = gzdopen(pipefd[1], "w");
|
||||
gzwrite(write_fd, body.c_str(), body.size());
|
||||
@@ -1047,13 +852,35 @@ void prepare_status_response(Stream *stream, Http2Handler *hd,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void prepare_redirect_response(Stream *stream, Http2Handler *hd,
|
||||
const std::string& path,
|
||||
const std::string& status)
|
||||
{
|
||||
auto scheme = http2::get_unique_header(stream->headers, ":scheme");
|
||||
auto authority = http2::get_unique_header(stream->headers, ":authority");
|
||||
if(!authority) {
|
||||
authority = http2::get_unique_header(stream->headers, ":host");
|
||||
}
|
||||
|
||||
auto redirect_url = scheme->value;
|
||||
redirect_url += "://";
|
||||
redirect_url += authority->value;
|
||||
redirect_url += path;
|
||||
|
||||
auto headers = Headers{{"location", redirect_url}};
|
||||
|
||||
hd->submit_response(status, stream->stream_id, headers, nullptr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void prepare_response(Stream *stream, Http2Handler *hd, bool allow_push = true)
|
||||
{
|
||||
int rv;
|
||||
auto url = (*std::lower_bound(std::begin(stream->headers),
|
||||
std::end(stream->headers),
|
||||
Header(":path", ""))).value;
|
||||
auto reqpath = (*std::lower_bound(std::begin(stream->headers),
|
||||
std::end(stream->headers),
|
||||
Header(":path", ""))).value;
|
||||
auto ims = std::lower_bound(std::begin(stream->headers),
|
||||
std::end(stream->headers),
|
||||
Header("if-modified-since", ""));
|
||||
@@ -1065,17 +892,21 @@ void prepare_response(Stream *stream, Http2Handler *hd, bool allow_push = true)
|
||||
last_mod_found = true;
|
||||
last_mod = util::parse_http_date((*ims).value);
|
||||
}
|
||||
auto query_pos = url.find("?");
|
||||
auto query_pos = reqpath.find("?");
|
||||
std::string url;
|
||||
if(query_pos != std::string::npos) {
|
||||
// Do not response to this request to allow clients to test timeouts.
|
||||
if(url.find("nghttpd_do_not_respond_to_req=yes",
|
||||
query_pos) != std::string::npos) {
|
||||
if(reqpath.find("nghttpd_do_not_respond_to_req=yes",
|
||||
query_pos) != std::string::npos) {
|
||||
return;
|
||||
}
|
||||
url = url.substr(0, query_pos);
|
||||
url = reqpath.substr(0, query_pos);
|
||||
} else {
|
||||
url = reqpath;
|
||||
}
|
||||
|
||||
url = util::percentDecode(url.begin(), url.end());
|
||||
if(!check_url(url)) {
|
||||
if(!util::check_path(url)) {
|
||||
prepare_status_response(stream, hd, STATUS_404);
|
||||
return;
|
||||
}
|
||||
@@ -1109,6 +940,20 @@ void prepare_response(Stream *stream, Http2Handler *hd, bool allow_push = true)
|
||||
return;
|
||||
}
|
||||
|
||||
if(buf.st_mode & S_IFDIR) {
|
||||
close(file);
|
||||
|
||||
if(query_pos == std::string::npos) {
|
||||
reqpath += "/";
|
||||
} else {
|
||||
reqpath.insert(query_pos, "/");
|
||||
}
|
||||
|
||||
prepare_redirect_response(stream, hd, reqpath, STATUS_301);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
stream->file = file;
|
||||
|
||||
nghttp2_data_provider data_prd;
|
||||
@@ -1158,8 +1003,20 @@ int on_header_callback(nghttp2_session *session,
|
||||
if(!http2::check_nv(name, namelen, value, valuelen)) {
|
||||
return 0;
|
||||
}
|
||||
http2::split_add_header(stream->headers, name, namelen, value, valuelen,
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||
|
||||
if(namelen > 0 && name[0] == ':') {
|
||||
if((!stream->headers.empty() &&
|
||||
stream->headers.back().name.c_str()[0] != ':') ||
|
||||
!http2::check_http2_request_pseudo_header(name, namelen)) {
|
||||
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
||||
NGHTTP2_PROTOCOL_ERROR);
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
http2::add_header(stream->headers, name, namelen, value, valuelen,
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
@@ -1247,7 +1104,7 @@ int hd_on_frame_recv_callback
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
||||
|
||||
http2::normalize_headers(stream->headers);
|
||||
if(!http2::check_http2_headers(stream->headers)) {
|
||||
if(!http2::check_http2_request_headers(stream->headers)) {
|
||||
hd->submit_rst_stream(stream, NGHTTP2_PROTOCOL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
@@ -1266,6 +1123,12 @@ int hd_on_frame_recv_callback
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto expect100 = http2::get_header(stream->headers, "expect");
|
||||
|
||||
if(expect100 && util::strieq("100-continue", expect100->value.c_str())) {
|
||||
hd->submit_non_final_response("100", frame->hd.stream_id);
|
||||
}
|
||||
|
||||
if(hd->get_config()->early_response) {
|
||||
prepare_response(stream, hd);
|
||||
}
|
||||
@@ -1322,8 +1185,9 @@ int hd_on_frame_send_callback
|
||||
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
remove_stream_write_timeout(stream);
|
||||
} else if(nghttp2_session_get_stream_remote_window_size
|
||||
(session, frame->hd.stream_id) == 0) {
|
||||
} else if(std::min(nghttp2_session_get_stream_remote_window_size
|
||||
(session, frame->hd.stream_id),
|
||||
nghttp2_session_get_remote_window_size(session)) <= 0) {
|
||||
// If stream is blocked by flow control, enable write timeout.
|
||||
add_stream_read_timeout_if_pending(stream);
|
||||
add_stream_write_timeout(stream);
|
||||
@@ -1392,7 +1256,7 @@ int on_data_chunk_recv_callback
|
||||
|
||||
namespace {
|
||||
int on_stream_close_callback
|
||||
(nghttp2_session *session, int32_t stream_id, nghttp2_error_code error_code,
|
||||
(nghttp2_session *session, int32_t stream_id, uint32_t error_code,
|
||||
void *user_data)
|
||||
{
|
||||
auto hd = static_cast<Http2Handler*>(user_data);
|
||||
@@ -1408,23 +1272,34 @@ int on_stream_close_callback
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config)
|
||||
void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config)
|
||||
{
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks.on_frame_recv_callback = hd_on_frame_recv_callback;
|
||||
callbacks.on_frame_send_callback = hd_on_frame_send_callback;
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, hd_on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_send_callback
|
||||
(callbacks, hd_on_frame_send_callback);
|
||||
|
||||
if(config->verbose) {
|
||||
callbacks.on_invalid_frame_recv_callback =
|
||||
verbose_on_invalid_frame_recv_callback;
|
||||
callbacks.on_unknown_frame_recv_callback =
|
||||
verbose_on_unknown_frame_recv_callback;
|
||||
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
|
||||
(callbacks, verbose_on_invalid_frame_recv_callback);
|
||||
}
|
||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(callbacks, on_data_chunk_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_header_callback
|
||||
(callbacks, on_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(callbacks, on_begin_headers_callback);
|
||||
|
||||
if(config->padding) {
|
||||
callbacks.select_padding_callback = select_padding_callback;
|
||||
nghttp2_session_callbacks_set_select_padding_callback
|
||||
(callbacks, select_padding_callback);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
@@ -1440,7 +1315,9 @@ void worker_readcb(bufferevent *bev, void *arg)
|
||||
auto input = bufferevent_get_input(bev);
|
||||
while(evbuffer_get_length(input) >= sizeof(ClientInfo)) {
|
||||
ClientInfo client;
|
||||
evbuffer_remove(input, &client, sizeof(client));
|
||||
if(evbuffer_remove(input, &client, sizeof(client)) == -1) {
|
||||
std::cerr << "evbuffer_remove() failed" << std::endl;
|
||||
}
|
||||
sessions->accept_connection(client.fd);
|
||||
}
|
||||
}
|
||||
@@ -1676,14 +1553,14 @@ int HttpServer::run()
|
||||
}
|
||||
|
||||
SSL_CTX_set_options(ssl_ctx,
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
||||
SSL_OP_SINGLE_ECDH_USE |
|
||||
SSL_OP_NO_TICKET |
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
|
||||
SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST);
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <event2/event.h>
|
||||
#include <event2/bufferevent.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
@@ -66,6 +67,7 @@ struct Config {
|
||||
std::string dh_param_file;
|
||||
timeval stream_read_timeout;
|
||||
timeval stream_write_timeout;
|
||||
nghttp2_option *session_option;
|
||||
void *data_ptr;
|
||||
size_t padding;
|
||||
size_t num_worker;
|
||||
@@ -78,6 +80,7 @@ struct Config {
|
||||
bool error_gzip;
|
||||
bool early_response;
|
||||
Config();
|
||||
~Config();
|
||||
};
|
||||
|
||||
class Http2Handler;
|
||||
@@ -103,12 +106,11 @@ public:
|
||||
|
||||
void remove_self();
|
||||
int setup_bev();
|
||||
int send();
|
||||
int on_read();
|
||||
int on_write();
|
||||
int on_connect();
|
||||
int verify_npn_result();
|
||||
int sendcb(const uint8_t *data, size_t len);
|
||||
int recvcb(uint8_t *buf, size_t len);
|
||||
|
||||
int submit_file_response(const std::string& status,
|
||||
Stream *stream,
|
||||
@@ -123,12 +125,14 @@ public:
|
||||
int submit_response
|
||||
(const std::string& status,
|
||||
int32_t stream_id,
|
||||
const std::vector<std::pair<std::string, std::string>>& headers,
|
||||
const Headers& headers,
|
||||
nghttp2_data_provider *data_prd);
|
||||
|
||||
int submit_non_final_response(const std::string& status, int32_t stream_id);
|
||||
|
||||
int submit_push_promise(Stream *stream, const std::string& push_path);
|
||||
|
||||
int submit_rst_stream(Stream *stream, nghttp2_error_code error_code);
|
||||
int submit_rst_stream(Stream *stream, uint32_t error_code);
|
||||
|
||||
void add_stream(int32_t stream_id, std::unique_ptr<Stream> stream);
|
||||
void remove_stream(int32_t stream_id);
|
||||
@@ -136,30 +140,17 @@ public:
|
||||
int64_t session_id() const;
|
||||
Sessions* get_sessions() const;
|
||||
const Config* get_config() const;
|
||||
size_t get_left_connhd_len() const;
|
||||
void set_left_connhd_len(size_t left);
|
||||
void remove_settings_timer();
|
||||
void terminate_session(nghttp2_error_code error_code);
|
||||
int tls_handshake();
|
||||
void terminate_session(uint32_t error_code);
|
||||
private:
|
||||
int handle_ssl_temporal_error(int err);
|
||||
int tls_write(const uint8_t *data, size_t datalen);
|
||||
int tls_write_pending();
|
||||
int wait_events();
|
||||
|
||||
std::map<int32_t, std::unique_ptr<Stream>> id2stream_;
|
||||
nghttp2_buf sendbuf_;
|
||||
int64_t session_id_;
|
||||
nghttp2_session *session_;
|
||||
Sessions *sessions_;
|
||||
SSL* ssl_;
|
||||
event *rev_, *wev_;
|
||||
SSL *ssl_;
|
||||
bufferevent *bev_;
|
||||
event *settings_timerev_;
|
||||
const uint8_t *pending_data_;
|
||||
size_t pending_datalen_;
|
||||
size_t left_connhd_len_;
|
||||
int fd_;
|
||||
uint8_t sendbufarray_[65536];
|
||||
};
|
||||
|
||||
class HttpServer {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
SUBDIRS = includes
|
||||
|
||||
bin_PROGRAMS =
|
||||
check_PROGRAMS =
|
||||
@@ -30,6 +31,7 @@ AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/lib/includes \
|
||||
-I$(top_builddir)/lib/includes \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(top_srcdir)/src/includes \
|
||||
-I$(top_srcdir)/third-party \
|
||||
@LIBSPDYLAY_CFLAGS@ \
|
||||
@XML_CPPFLAGS@ \
|
||||
@@ -39,13 +41,13 @@ AM_CPPFLAGS = \
|
||||
@ZLIB_CFLAGS@ \
|
||||
@DEFS@
|
||||
AM_LDFLAGS = \
|
||||
@JEMALLOC_LIBS@ \
|
||||
@LIBSPDYLAY_LIBS@ \
|
||||
@XML_LIBS@ \
|
||||
@LIBEVENT_OPENSSL_LIBS@ \
|
||||
@OPENSSL_LIBS@ \
|
||||
@JANSSON_LIBS@ \
|
||||
@ZLIB_LIBS@ \
|
||||
@JEMALLOC_LIBS@ \
|
||||
@SRC_LIBS@
|
||||
|
||||
LDADD = \
|
||||
@@ -56,8 +58,10 @@ if ENABLE_APP
|
||||
|
||||
bin_PROGRAMS += nghttp nghttpd nghttpx
|
||||
|
||||
HELPER_OBJECTS = util.cc http2.cc timegm.c app_helper.cc nghttp2_gzip.c
|
||||
HELPER_HFILES = util.h http2.h timegm.h app_helper.h nghttp2_config.h \
|
||||
HELPER_OBJECTS = util.cc libevent_util.cc \
|
||||
http2.cc timegm.c app_helper.cc nghttp2_gzip.c
|
||||
HELPER_HFILES = util.h libevent_util.h \
|
||||
http2.h timegm.h app_helper.h nghttp2_config.h \
|
||||
nghttp2_gzip.h
|
||||
|
||||
HTML_PARSER_OBJECTS =
|
||||
@@ -74,11 +78,10 @@ nghttpd_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttpd.cc \
|
||||
ssl.cc ssl.h \
|
||||
HttpServer.cc HttpServer.h
|
||||
|
||||
if ENABLE_H2LOAD
|
||||
|
||||
bin_PROGRAMS += h2load
|
||||
|
||||
h2load_SOURCES = util.cc util.h http2.cc http2.h h2load.cc h2load.h \
|
||||
h2load_SOURCES = util.cc util.h libevent_util.cc libevent_util.h \
|
||||
http2.cc http2.h h2load.cc h2load.h \
|
||||
timegm.c timegm.h \
|
||||
ssl.cc ssl.h \
|
||||
h2load_session.h \
|
||||
@@ -88,10 +91,9 @@ if HAVE_SPDYLAY
|
||||
h2load_SOURCES += h2load_spdy_session.cc h2load_spdy_session.h
|
||||
endif # HAVE_SPDYLAY
|
||||
|
||||
endif # ENABLE_H2LOAD
|
||||
|
||||
NGHTTPX_SRCS = \
|
||||
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \
|
||||
libevent_util.cc libevent_util.h \
|
||||
app_helper.cc app_helper.h \
|
||||
ssl.cc ssl.h \
|
||||
shrpx_config.cc shrpx_config.h \
|
||||
@@ -113,7 +115,9 @@ NGHTTPX_SRCS = \
|
||||
shrpx_ssl.cc shrpx_ssl.h \
|
||||
shrpx_thread_event_receiver.cc shrpx_thread_event_receiver.h \
|
||||
shrpx_worker.cc shrpx_worker.h \
|
||||
shrpx_worker_config.cc shrpx_worker_config.h
|
||||
shrpx_worker_config.cc shrpx_worker_config.h \
|
||||
shrpx_connect_blocker.cc shrpx_connect_blocker.h \
|
||||
shrpx_downstream_connection_pool.cc shrpx_downstream_connection_pool.h
|
||||
|
||||
if HAVE_SPDYLAY
|
||||
NGHTTPX_SRCS += shrpx_spdy_upstream.cc shrpx_spdy_upstream.h
|
||||
@@ -158,3 +162,33 @@ inflatehd_SOURCES = inflatehd.cc $(HPACK_TOOLS_COMMON_SRCS)
|
||||
deflatehd_SOURCES = deflatehd.cc $(HPACK_TOOLS_COMMON_SRCS)
|
||||
|
||||
endif # ENABLE_HPACK_TOOLS
|
||||
|
||||
if ENABLE_ASIO_LIB
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libnghttp2_asio.pc
|
||||
DISTCLEANFILES = $(pkgconfig_DATA)
|
||||
|
||||
lib_LTLIBRARIES = libnghttp2_asio.la
|
||||
|
||||
libnghttp2_asio_la_SOURCES = \
|
||||
asio_connection.h \
|
||||
asio_server.cc asio_server.h \
|
||||
asio_io_service_pool.cc asio_io_service_pool.h \
|
||||
asio_http2_handler.cc asio_http2_handler.h \
|
||||
asio_http2_impl.cc asio_http2_impl.h \
|
||||
util.cc util.h http2.cc http2.h \
|
||||
ssl.cc ssl.h
|
||||
|
||||
libnghttp2_asio_la_CPPFLAGS= ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
libnghttp2_asio_la_LDFLAGS = \
|
||||
${BOOST_LDFLAGS} \
|
||||
${BOOST_ASIO_LIB} \
|
||||
${BOOST_THREAD_LIB} \
|
||||
${BOOST_SYSTEM_LIB} \
|
||||
@OPENSSL_LIBS@ \
|
||||
-no-undefined \
|
||||
-version-info 0:0:0
|
||||
libnghttp2_asio_la_LIBADD = $(top_builddir)/lib/libnghttp2.la
|
||||
|
||||
endif # ENABLE_ASIO_LIB
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace {
|
||||
const char* strstatus(nghttp2_error_code error_code)
|
||||
const char* strstatus(uint32_t error_code)
|
||||
{
|
||||
switch(error_code) {
|
||||
case NGHTTP2_NO_ERROR:
|
||||
@@ -81,6 +81,8 @@ const char* strstatus(nghttp2_error_code error_code)
|
||||
return "ENHANCE_YOUR_CALM";
|
||||
case NGHTTP2_INADEQUATE_SECURITY:
|
||||
return "INADEQUATE_SECURITY";
|
||||
case NGHTTP2_HTTP_1_1_REQUIRED:
|
||||
return "HTTP_1_1_REQUIRED";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -99,6 +101,10 @@ const char* strsettingsid(int32_t id)
|
||||
return "SETTINGS_MAX_CONCURRENT_STREAMS";
|
||||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||
return "SETTINGS_INITIAL_WINDOW_SIZE";
|
||||
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
|
||||
return "SETTINGS_MAX_FRAME_SIZE";
|
||||
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
|
||||
return "SETTINGS_MAX_HEADER_LIST_SIZE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -187,10 +193,11 @@ void print_nv(nghttp2_nv *nv)
|
||||
namespace {
|
||||
void print_nv(nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
for(auto& nv : http2::sort_nva(nva, nvlen)) {
|
||||
auto end = nva + nvlen;
|
||||
for(; nva != end; ++nva) {
|
||||
print_frame_attr_indent();
|
||||
|
||||
print_nv(&nv);
|
||||
print_nv(nva);
|
||||
}
|
||||
}
|
||||
} // namelen
|
||||
@@ -221,12 +228,6 @@ void print_flags(const nghttp2_frame_hd& hd)
|
||||
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
s += "END_STREAM";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_END_SEGMENT) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "END_SEGMENT";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PADDED) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
@@ -238,12 +239,6 @@ void print_flags(const nghttp2_frame_hd& hd)
|
||||
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
s += "END_STREAM";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_END_SEGMENT) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "END_SEGMENT";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_END_HEADERS) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
@@ -448,18 +443,17 @@ int verbose_on_header_callback(nghttp2_session *session,
|
||||
uint8_t flags,
|
||||
void *user_data)
|
||||
{
|
||||
nghttp2_nv nva = {
|
||||
nghttp2_nv nv = {
|
||||
const_cast<uint8_t*>(name), const_cast<uint8_t*>(value),
|
||||
namelen, valuelen
|
||||
};
|
||||
|
||||
for(auto& nv : http2::sort_nva(&nva, 1)) {
|
||||
print_timer();
|
||||
fprintf(outfile, " (stream_id=%d, noind=%d) ", frame->hd.stream_id,
|
||||
(flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0);
|
||||
print_timer();
|
||||
fprintf(outfile, " recv (stream_id=%d, noind=%d) ", frame->hd.stream_id,
|
||||
(flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0);
|
||||
|
||||
print_nv(&nv);
|
||||
}
|
||||
print_nv(&nv);
|
||||
fflush(outfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -476,7 +470,7 @@ int verbose_on_frame_recv_callback
|
||||
|
||||
int verbose_on_invalid_frame_recv_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
nghttp2_error_code error_code, void *user_data)
|
||||
uint32_t error_code, void *user_data)
|
||||
{
|
||||
print_timer();
|
||||
fprintf(outfile, " [INVALID; status=%s] recv ", strstatus(error_code));
|
||||
@@ -485,33 +479,6 @@ int verbose_on_invalid_frame_recv_callback
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void dump_header(const uint8_t *head, size_t headlen)
|
||||
{
|
||||
size_t i;
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "Header dump: ");
|
||||
for(i = 0; i < headlen; ++i) {
|
||||
fprintf(outfile, "%02X ", head[i]);
|
||||
}
|
||||
fprintf(outfile, "\n");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int verbose_on_unknown_frame_recv_callback(nghttp2_session *session,
|
||||
const uint8_t *head,
|
||||
size_t headlen,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen,
|
||||
void *user_data)
|
||||
{
|
||||
print_timer();
|
||||
fprintf(outfile, " recv unknown frame\n");
|
||||
dump_header(head, headlen);
|
||||
fflush(outfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verbose_on_frame_send_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
@@ -522,6 +489,23 @@ int verbose_on_frame_send_callback
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verbose_on_data_chunk_recv_callback
|
||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t len, void *user_data)
|
||||
{
|
||||
print_timer();
|
||||
auto srecv = nghttp2_session_get_stream_effective_recv_data_length
|
||||
(session, stream_id);
|
||||
auto crecv = nghttp2_session_get_effective_recv_data_length(session);
|
||||
|
||||
fprintf(outfile,
|
||||
" recv (stream_id=%d, length=%zu, srecv=%d, crecv=%d) DATA\n",
|
||||
stream_id, len, srecv, crecv);
|
||||
fflush(outfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::chrono::steady_clock::time_point base_tv;
|
||||
} // namespace
|
||||
|
||||
@@ -51,18 +51,15 @@ int verbose_on_frame_recv_callback
|
||||
|
||||
int verbose_on_invalid_frame_recv_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
nghttp2_error_code error_code, void *user_data);
|
||||
|
||||
int verbose_on_unknown_frame_recv_callback(nghttp2_session *session,
|
||||
const uint8_t *head,
|
||||
size_t headlen,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen,
|
||||
void *user_data);
|
||||
uint32_t error_code, void *user_data);
|
||||
|
||||
int verbose_on_frame_send_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data);
|
||||
|
||||
int verbose_on_data_chunk_recv_callback
|
||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t len, void *user_data);
|
||||
|
||||
// Returns difference between |a| and |b| in milliseconds, assuming
|
||||
// |a| is more recent than |b|.
|
||||
template<typename TimePoint>
|
||||
|
||||
193
src/asio_connection.h
Normal file
193
src/asio_connection.h
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// connection.hpp
|
||||
// ~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef HTTP_SERVER2_CONNECTION_HPP
|
||||
#define HTTP_SERVER2_CONNECTION_HPP
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/array.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
#include "asio_http2_handler.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
template<typename socket_type>
|
||||
class connection
|
||||
: public std::enable_shared_from_this<connection<socket_type>>,
|
||||
private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/// Construct a connection with the given io_service.
|
||||
template<typename... SocketArgs>
|
||||
explicit connection(request_cb cb,
|
||||
boost::asio::io_service& task_io_service,
|
||||
SocketArgs&&... args)
|
||||
: socket_(std::forward<SocketArgs>(args)...),
|
||||
request_cb_(std::move(cb)),
|
||||
task_io_service_(task_io_service),
|
||||
writing_(false)
|
||||
{}
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start()
|
||||
{
|
||||
handler_ = std::make_shared<http2_handler>
|
||||
(socket_.get_io_service(),
|
||||
task_io_service_,
|
||||
[this]()
|
||||
{
|
||||
do_write();
|
||||
},
|
||||
request_cb_);
|
||||
if(handler_->start() != 0) {
|
||||
return;
|
||||
}
|
||||
do_read();
|
||||
}
|
||||
|
||||
socket_type& socket()
|
||||
{
|
||||
return socket_;
|
||||
}
|
||||
|
||||
void do_read()
|
||||
{
|
||||
auto self = this->shared_from_this();
|
||||
|
||||
socket_.async_read_some
|
||||
(boost::asio::buffer(buffer_),
|
||||
[this, self](const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred)
|
||||
{
|
||||
if (!e) {
|
||||
if(handler_->on_read(buffer_, bytes_transferred) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_write();
|
||||
|
||||
if(!writing_ && handler_->should_stop()) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_read();
|
||||
}
|
||||
|
||||
// If an error occurs then no new asynchronous operations are
|
||||
// started. This means that all shared_ptr references to the
|
||||
// connection object will disappear and the object will be
|
||||
// destroyed automatically after this handler returns. The
|
||||
// connection class's destructor closes the socket.
|
||||
});
|
||||
}
|
||||
|
||||
void do_write()
|
||||
{
|
||||
auto self = this->shared_from_this();
|
||||
|
||||
if(writing_) {
|
||||
return;
|
||||
}
|
||||
|
||||
int rv;
|
||||
std::size_t nwrite;
|
||||
|
||||
rv = handler_->on_write(outbuf_, nwrite);
|
||||
|
||||
if(rv != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(nwrite == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
writing_ = true;
|
||||
|
||||
boost::asio::async_write
|
||||
(socket_, boost::asio::buffer(outbuf_, nwrite),
|
||||
[this, self](const boost::system::error_code& e,
|
||||
std::size_t)
|
||||
{
|
||||
if(!e) {
|
||||
writing_ = false;
|
||||
|
||||
do_write();
|
||||
}
|
||||
});
|
||||
|
||||
// No new asynchronous operations are started. This means that all
|
||||
// shared_ptr references to the connection object will disappear and
|
||||
// the object will be destroyed automatically after this handler
|
||||
// returns. The connection class's destructor closes the socket.
|
||||
}
|
||||
|
||||
private:
|
||||
socket_type socket_;
|
||||
|
||||
request_cb request_cb_;
|
||||
|
||||
boost::asio::io_service& task_io_service_;
|
||||
|
||||
std::shared_ptr<http2_handler> handler_;
|
||||
|
||||
/// Buffer for incoming data.
|
||||
boost::array<uint8_t, 8192> buffer_;
|
||||
|
||||
boost::array<uint8_t, 16394> outbuf_;
|
||||
|
||||
bool writing_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // HTTP_SERVER2_CONNECTION_HPP
|
||||
958
src/asio_http2_handler.cc
Normal file
958
src/asio_http2_handler.cc
Normal file
@@ -0,0 +1,958 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_http2_handler.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "http2.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
channel::channel()
|
||||
: impl_(util::make_unique<channel_impl>())
|
||||
{}
|
||||
|
||||
void channel::post(void_cb cb)
|
||||
{
|
||||
impl_->post(std::move(cb));
|
||||
}
|
||||
|
||||
channel_impl& channel::impl()
|
||||
{
|
||||
return *impl_;
|
||||
}
|
||||
|
||||
channel_impl::channel_impl()
|
||||
: strand_(nullptr)
|
||||
{}
|
||||
|
||||
void channel_impl::post(void_cb cb)
|
||||
{
|
||||
strand_->post(std::move(cb));
|
||||
}
|
||||
|
||||
void channel_impl::strand(boost::asio::io_service::strand *strand)
|
||||
{
|
||||
strand_ = strand;
|
||||
}
|
||||
|
||||
namespace server {
|
||||
|
||||
extern std::shared_ptr<std::string> cached_date;
|
||||
|
||||
request::request()
|
||||
: impl_(util::make_unique<request_impl>())
|
||||
{}
|
||||
|
||||
const std::vector<header>& request::headers() const
|
||||
{
|
||||
return impl_->headers();
|
||||
}
|
||||
|
||||
const std::string& request::method() const
|
||||
{
|
||||
return impl_->method();
|
||||
}
|
||||
|
||||
const std::string& request::scheme() const
|
||||
{
|
||||
return impl_->scheme();
|
||||
}
|
||||
|
||||
const std::string& request::authority() const
|
||||
{
|
||||
return impl_->authority();
|
||||
}
|
||||
|
||||
const std::string& request::host() const
|
||||
{
|
||||
return impl_->host();
|
||||
}
|
||||
|
||||
const std::string& request::path() const
|
||||
{
|
||||
return impl_->path();
|
||||
}
|
||||
|
||||
bool request::push(std::string method, std::string path,
|
||||
std::vector<header> headers)
|
||||
{
|
||||
return impl_->push(std::move(method), std::move(path), std::move(headers));
|
||||
}
|
||||
|
||||
bool request::pushed() const
|
||||
{
|
||||
return impl_->pushed();
|
||||
}
|
||||
|
||||
bool request::closed() const
|
||||
{
|
||||
return impl_->closed();
|
||||
}
|
||||
|
||||
void request::on_data(data_cb cb)
|
||||
{
|
||||
return impl_->on_data(std::move(cb));
|
||||
}
|
||||
|
||||
void request::on_end(void_cb cb)
|
||||
{
|
||||
return impl_->on_end(std::move(cb));
|
||||
}
|
||||
|
||||
bool request::run_task(thread_cb start)
|
||||
{
|
||||
return impl_->run_task(std::move(start));
|
||||
}
|
||||
|
||||
request_impl& request::impl()
|
||||
{
|
||||
return *impl_;
|
||||
}
|
||||
|
||||
response::response()
|
||||
: impl_(util::make_unique<response_impl>())
|
||||
{}
|
||||
|
||||
void response::write_head(unsigned int status_code,
|
||||
std::vector<header> headers)
|
||||
{
|
||||
impl_->write_head(status_code, std::move(headers));
|
||||
}
|
||||
|
||||
void response::end(std::string data)
|
||||
{
|
||||
impl_->end(std::move(data));
|
||||
}
|
||||
|
||||
void response::end(read_cb cb)
|
||||
{
|
||||
impl_->end(std::move(cb));
|
||||
}
|
||||
|
||||
void response::resume()
|
||||
{
|
||||
impl_->resume();
|
||||
}
|
||||
|
||||
unsigned int response::status_code() const
|
||||
{
|
||||
return impl_->status_code();
|
||||
}
|
||||
|
||||
bool response::started() const
|
||||
{
|
||||
return impl_->started();
|
||||
}
|
||||
|
||||
response_impl& response::impl()
|
||||
{
|
||||
return *impl_;
|
||||
}
|
||||
|
||||
request_impl::request_impl()
|
||||
: pushed_(false)
|
||||
{}
|
||||
|
||||
const std::vector<header>& request_impl::headers() const
|
||||
{
|
||||
return headers_;
|
||||
}
|
||||
|
||||
const std::string& request_impl::method() const
|
||||
{
|
||||
return method_;
|
||||
}
|
||||
|
||||
const std::string& request_impl::scheme() const
|
||||
{
|
||||
return scheme_;
|
||||
}
|
||||
|
||||
const std::string& request_impl::authority() const
|
||||
{
|
||||
return authority_;
|
||||
}
|
||||
|
||||
const std::string& request_impl::host() const
|
||||
{
|
||||
return host_;
|
||||
}
|
||||
|
||||
const std::string& request_impl::path() const
|
||||
{
|
||||
return path_;
|
||||
}
|
||||
|
||||
void request_impl::set_header(std::vector<header> headers)
|
||||
{
|
||||
headers_ = std::move(headers);
|
||||
}
|
||||
|
||||
void request_impl::add_header(std::string name, std::string value)
|
||||
{
|
||||
headers_.push_back(header{std::move(name), std::move(value)});
|
||||
}
|
||||
|
||||
void request_impl::method(std::string arg)
|
||||
{
|
||||
method_ = std::move(arg);
|
||||
}
|
||||
|
||||
void request_impl::scheme(std::string arg)
|
||||
{
|
||||
scheme_ = std::move(arg);
|
||||
}
|
||||
|
||||
void request_impl::authority(std::string arg)
|
||||
{
|
||||
authority_ = std::move(arg);
|
||||
}
|
||||
|
||||
void request_impl::host(std::string arg)
|
||||
{
|
||||
host_ = std::move(arg);
|
||||
}
|
||||
|
||||
void request_impl::path(std::string arg)
|
||||
{
|
||||
path_ = std::move(arg);
|
||||
}
|
||||
|
||||
bool request_impl::push(std::string method, std::string path,
|
||||
std::vector<header> headers)
|
||||
{
|
||||
if(closed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto handler = handler_.lock();
|
||||
auto stream = stream_.lock();
|
||||
auto rv = handler->push_promise
|
||||
(*stream, std::move(method), std::move(path), std::move(headers));
|
||||
return rv == 0;
|
||||
}
|
||||
|
||||
bool request_impl::pushed() const
|
||||
{
|
||||
return pushed_;
|
||||
}
|
||||
|
||||
void request_impl::pushed(bool f)
|
||||
{
|
||||
pushed_ = f;
|
||||
}
|
||||
|
||||
bool request_impl::closed() const
|
||||
{
|
||||
return handler_.expired() || stream_.expired();
|
||||
}
|
||||
|
||||
void request_impl::on_data(data_cb cb)
|
||||
{
|
||||
on_data_cb_ = std::move(cb);
|
||||
}
|
||||
|
||||
void request_impl::on_end(void_cb cb)
|
||||
{
|
||||
on_end_cb_ = std::move(cb);
|
||||
}
|
||||
|
||||
bool request_impl::run_task(thread_cb start)
|
||||
{
|
||||
if(closed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto handler = handler_.lock();
|
||||
|
||||
return handler->run_task(std::move(start));
|
||||
}
|
||||
|
||||
void request_impl::handler(std::weak_ptr<http2_handler> h)
|
||||
{
|
||||
handler_ = std::move(h);
|
||||
}
|
||||
|
||||
void request_impl::stream(std::weak_ptr<http2_stream> s)
|
||||
{
|
||||
stream_ = std::move(s);
|
||||
}
|
||||
|
||||
void request_impl::call_on_data(const uint8_t *data, std::size_t len)
|
||||
{
|
||||
if(on_data_cb_) {
|
||||
on_data_cb_(data, len);
|
||||
}
|
||||
}
|
||||
|
||||
void request_impl::call_on_end()
|
||||
{
|
||||
if(on_end_cb_) {
|
||||
on_end_cb_();
|
||||
}
|
||||
}
|
||||
|
||||
response_impl::response_impl()
|
||||
: status_code_(200),
|
||||
started_(false)
|
||||
{}
|
||||
|
||||
unsigned int response_impl::status_code() const
|
||||
{
|
||||
return status_code_;
|
||||
}
|
||||
|
||||
void response_impl::write_head(unsigned int status_code,
|
||||
std::vector<header> headers)
|
||||
{
|
||||
status_code_ = status_code;
|
||||
headers_ = std::move(headers);
|
||||
}
|
||||
|
||||
void response_impl::end(std::string data)
|
||||
{
|
||||
if(started_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto strio = std::make_shared<std::pair<std::string, size_t>>
|
||||
(std::move(data), data.size());
|
||||
auto read_cb = [strio](uint8_t *buf, size_t len)
|
||||
{
|
||||
auto nread = std::min(len, strio->second);
|
||||
memcpy(buf, strio->first.c_str(), nread);
|
||||
strio->second -= nread;
|
||||
if(strio->second == 0) {
|
||||
return std::make_pair(nread, true);
|
||||
}
|
||||
|
||||
return std::make_pair(nread, false);
|
||||
};
|
||||
|
||||
end(std::move(read_cb));
|
||||
}
|
||||
|
||||
void response_impl::end(read_cb cb)
|
||||
{
|
||||
if(started_ || closed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
read_cb_ = std::move(cb);
|
||||
started_ = true;
|
||||
|
||||
auto handler = handler_.lock();
|
||||
auto stream = stream_.lock();
|
||||
|
||||
if(handler->start_response(*stream) != 0) {
|
||||
handler->stream_error(stream->get_stream_id(), NGHTTP2_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!handler->inside_callback()) {
|
||||
handler->initiate_write();
|
||||
}
|
||||
}
|
||||
|
||||
bool response_impl::closed() const
|
||||
{
|
||||
return handler_.expired() || stream_.expired();
|
||||
}
|
||||
|
||||
void response_impl::resume()
|
||||
{
|
||||
if(closed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto handler = handler_.lock();
|
||||
auto stream = stream_.lock();
|
||||
handler->resume(*stream);
|
||||
|
||||
if(!handler->inside_callback()) {
|
||||
handler->initiate_write();
|
||||
}
|
||||
}
|
||||
|
||||
bool response_impl::started() const
|
||||
{
|
||||
return started_;
|
||||
}
|
||||
|
||||
const std::vector<header>& response_impl::headers() const
|
||||
{
|
||||
return headers_;
|
||||
}
|
||||
|
||||
void response_impl::handler(std::weak_ptr<http2_handler> h)
|
||||
{
|
||||
handler_ = std::move(h);
|
||||
}
|
||||
|
||||
void response_impl::stream(std::weak_ptr<http2_stream> s)
|
||||
{
|
||||
stream_ = std::move(s);
|
||||
}
|
||||
|
||||
std::pair<ssize_t, bool> response_impl::call_read
|
||||
(uint8_t *data, std::size_t len)
|
||||
{
|
||||
if(read_cb_) {
|
||||
return read_cb_(data, len);
|
||||
}
|
||||
|
||||
return std::make_pair(0, true);
|
||||
}
|
||||
|
||||
http2_stream::http2_stream(int32_t stream_id)
|
||||
: request_(std::make_shared<request>()),
|
||||
response_(std::make_shared<response>()),
|
||||
stream_id_(stream_id)
|
||||
{}
|
||||
|
||||
int32_t http2_stream::get_stream_id() const
|
||||
{
|
||||
return stream_id_;
|
||||
}
|
||||
|
||||
const std::shared_ptr<request>& http2_stream::get_request()
|
||||
{
|
||||
return request_;
|
||||
}
|
||||
|
||||
const std::shared_ptr<response>& http2_stream::get_response()
|
||||
{
|
||||
return response_;
|
||||
}
|
||||
|
||||
namespace {
|
||||
int stream_error(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code)
|
||||
{
|
||||
return nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, stream_id,
|
||||
error_code);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_begin_headers_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data)
|
||||
{
|
||||
auto handler = static_cast<http2_handler*>(user_data);
|
||||
|
||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
handler->create_stream(frame->hd.stream_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *user_data)
|
||||
{
|
||||
auto handler = static_cast<http2_handler*>(user_data);
|
||||
auto stream_id = frame->hd.stream_id;
|
||||
|
||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto stream = handler->find_stream(stream_id);
|
||||
if(!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!nghttp2_check_header_name(name, namelen) ||
|
||||
!nghttp2_check_header_value(value, valuelen)) {
|
||||
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
|
||||
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
auto& req = stream->get_request()->impl();
|
||||
|
||||
if(name[0] == ':' && !req.headers().empty()) {
|
||||
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if(util::streq(":method", name, namelen)) {
|
||||
if(!req.method().empty()) {
|
||||
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
req.method(std::string(value, value + valuelen));
|
||||
} else if(util::streq(":scheme", name, namelen)) {
|
||||
if(!req.scheme().empty()) {
|
||||
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
req.scheme(std::string(value, value + valuelen));
|
||||
} else if(util::streq(":authority", name, namelen)) {
|
||||
if(!req.authority().empty()) {
|
||||
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
req.authority(std::string(value, value + valuelen));
|
||||
} else if(util::streq(":path", name, namelen)) {
|
||||
if(!req.path().empty()) {
|
||||
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
req.path(std::string(value, value + valuelen));
|
||||
} else {
|
||||
if(name[0] == ':') {
|
||||
stream_error(session, stream_id, NGHTTP2_PROTOCOL_ERROR);
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if(util::streq("host", name, namelen)) {
|
||||
req.host(std::string(value, value + valuelen));
|
||||
}
|
||||
|
||||
req.add_header(std::string(name, name + namelen),
|
||||
std::string(value, value + valuelen));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_frame_recv_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
auto handler = static_cast<http2_handler*>(user_data);
|
||||
auto stream = handler->find_stream(frame->hd.stream_id);
|
||||
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
if(!stream) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
stream->get_request()->impl().call_on_end();
|
||||
}
|
||||
|
||||
break;
|
||||
case NGHTTP2_HEADERS: {
|
||||
if(!stream || frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto& req = stream->get_request()->impl();
|
||||
|
||||
if(req.method().empty() || req.scheme().empty() || req.path().empty() ||
|
||||
(req.authority().empty() && req.host().empty())) {
|
||||
stream_error(session, frame->hd.stream_id, NGHTTP2_PROTOCOL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(req.host().empty()) {
|
||||
req.host(req.authority());
|
||||
}
|
||||
|
||||
handler->call_on_request(*stream);
|
||||
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
stream->get_request()->impl().call_on_end();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const uint8_t *data, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
auto handler = static_cast<http2_handler*>(user_data);
|
||||
auto stream = handler->find_stream(stream_id);
|
||||
|
||||
if(!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->get_request()->impl().call_on_data(data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_stream_close_callback
|
||||
(nghttp2_session *session, int32_t stream_id, uint32_t error_code,
|
||||
void *user_data)
|
||||
{
|
||||
auto handler = static_cast<http2_handler*>(user_data);
|
||||
|
||||
handler->close_stream(stream_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_frame_send_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
auto handler = static_cast<http2_handler*>(user_data);
|
||||
|
||||
if(frame->hd.type != NGHTTP2_PUSH_PROMISE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto stream = handler->find_stream(frame->push_promise.promised_stream_id);
|
||||
|
||||
if(!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
handler->call_on_request(*stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_frame_not_send_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code,
|
||||
void *user_data)
|
||||
{
|
||||
if(frame->hd.type != NGHTTP2_HEADERS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Issue RST_STREAM so that stream does not hang around.
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
http2_handler::http2_handler
|
||||
(boost::asio::io_service& io_service,
|
||||
boost::asio::io_service& task_io_service_,
|
||||
connection_write writefun, request_cb cb)
|
||||
: writefun_(writefun),
|
||||
request_cb_(std::move(cb)),
|
||||
io_service_(io_service),
|
||||
task_io_service_(task_io_service_),
|
||||
strand_(std::make_shared<boost::asio::io_service::strand>(io_service_)),
|
||||
session_(nullptr),
|
||||
buf_(nullptr),
|
||||
buflen_(0),
|
||||
inside_callback_(false)
|
||||
{}
|
||||
|
||||
http2_handler::~http2_handler()
|
||||
{
|
||||
nghttp2_session_del(session_);
|
||||
}
|
||||
|
||||
int http2_handler::start()
|
||||
{
|
||||
int rv;
|
||||
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
rv = nghttp2_session_callbacks_new(&callbacks);
|
||||
if(rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto cb_del = util::defer(callbacks, nghttp2_session_callbacks_del);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(callbacks, on_begin_headers_callback);
|
||||
nghttp2_session_callbacks_set_on_header_callback
|
||||
(callbacks, on_header_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(callbacks, on_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_send_callback
|
||||
(callbacks, on_frame_send_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_not_send_callback
|
||||
(callbacks, on_frame_not_send_callback);
|
||||
|
||||
nghttp2_option *option;
|
||||
rv = nghttp2_option_new(&option);
|
||||
if(rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto opt_del = util::defer(option, nghttp2_option_del);
|
||||
|
||||
nghttp2_option_set_recv_client_preface(option, 1);
|
||||
|
||||
rv = nghttp2_session_server_new2(&session_, callbacks, this, option);
|
||||
if(rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
nghttp2_settings_entry ent { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 };
|
||||
nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, &ent, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<http2_stream> http2_handler::create_stream(int32_t stream_id)
|
||||
{
|
||||
auto stream = std::make_shared<http2_stream>(stream_id);
|
||||
streams_.emplace(stream_id, stream);
|
||||
|
||||
auto self = shared_from_this();
|
||||
auto& req = stream->get_request()->impl();
|
||||
auto& res = stream->get_response()->impl();
|
||||
req.handler(self);
|
||||
req.stream(stream);
|
||||
res.handler(self);
|
||||
res.stream(stream);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
void http2_handler::close_stream(int32_t stream_id)
|
||||
{
|
||||
streams_.erase(stream_id);
|
||||
}
|
||||
|
||||
std::shared_ptr<http2_stream> http2_handler::find_stream(int32_t stream_id)
|
||||
{
|
||||
auto i = streams_.find(stream_id);
|
||||
if(i == std::end(streams_)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (*i).second;
|
||||
}
|
||||
|
||||
void http2_handler::call_on_request(http2_stream& stream)
|
||||
{
|
||||
request_cb_(stream.get_request(), stream.get_response());
|
||||
}
|
||||
|
||||
bool http2_handler::should_stop() const
|
||||
{
|
||||
return
|
||||
!nghttp2_session_want_read(session_) &&
|
||||
!nghttp2_session_want_write(session_);
|
||||
}
|
||||
|
||||
int http2_handler::start_response(http2_stream& stream)
|
||||
{
|
||||
int rv;
|
||||
|
||||
auto& res = stream.get_response()->impl();
|
||||
auto& headers = res.headers();
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(2 + headers.size());
|
||||
auto status = std::to_string(res.status_code());
|
||||
auto date = cached_date;
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":status", status));
|
||||
nva.push_back(nghttp2::http2::make_nv_ls("date", *date));
|
||||
for(auto& hd : headers) {
|
||||
nva.push_back(nghttp2::http2::make_nv(hd.name, hd.value));
|
||||
}
|
||||
|
||||
nghttp2_data_provider prd;
|
||||
prd.source.ptr = &stream;
|
||||
prd.read_callback =
|
||||
[](nghttp2_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t length, uint32_t *data_flags,
|
||||
nghttp2_data_source *source, void *user_data) -> ssize_t
|
||||
{
|
||||
auto& stream = *static_cast<http2_stream*>(source->ptr);
|
||||
auto rv = stream.get_response()->impl().call_read(buf, length);
|
||||
if(rv.first < 0) {
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if(rv.second) {
|
||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||
} else if(rv.first == 0) {
|
||||
return NGHTTP2_ERR_DEFERRED;
|
||||
}
|
||||
|
||||
return rv.first;
|
||||
};
|
||||
|
||||
rv = nghttp2_submit_response(session_, stream.get_stream_id(),
|
||||
nva.data(), nva.size(), &prd);
|
||||
|
||||
if(rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void http2_handler::enter_callback()
|
||||
{
|
||||
assert(!inside_callback_);
|
||||
inside_callback_ = true;
|
||||
}
|
||||
|
||||
void http2_handler::leave_callback()
|
||||
{
|
||||
assert(inside_callback_);
|
||||
inside_callback_ = false;
|
||||
}
|
||||
|
||||
bool http2_handler::inside_callback() const
|
||||
{
|
||||
return inside_callback_;
|
||||
}
|
||||
|
||||
void http2_handler::stream_error(int32_t stream_id, uint32_t error_code)
|
||||
{
|
||||
::nghttp2::asio_http2::server::stream_error(session_, stream_id, error_code);
|
||||
}
|
||||
|
||||
void http2_handler::initiate_write()
|
||||
{
|
||||
writefun_();
|
||||
}
|
||||
|
||||
void http2_handler::resume(http2_stream& stream)
|
||||
{
|
||||
nghttp2_session_resume_data(session_, stream.get_stream_id());
|
||||
}
|
||||
|
||||
int http2_handler::push_promise(http2_stream& stream, std::string method,
|
||||
std::string path,
|
||||
std::vector<header> headers)
|
||||
{
|
||||
int rv;
|
||||
|
||||
auto& req = stream.get_request()->impl();
|
||||
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(5 + headers.size());
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":method", method));
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":scheme", req.scheme()));
|
||||
if(!req.authority().empty()) {
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":authority", req.authority()));
|
||||
}
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":path", path));
|
||||
if(!req.host().empty()) {
|
||||
nva.push_back(nghttp2::http2::make_nv_ls("host", req.host()));
|
||||
}
|
||||
|
||||
for(auto& hd : headers) {
|
||||
nva.push_back(nghttp2::http2::make_nv(hd.name, hd.value));
|
||||
}
|
||||
|
||||
rv = nghttp2_submit_push_promise(session_, NGHTTP2_FLAG_NONE,
|
||||
stream.get_stream_id(),
|
||||
nva.data(), nva.size(), nullptr);
|
||||
|
||||
if(rv < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto promised_stream = create_stream(rv);
|
||||
auto& promised_req = promised_stream->get_request()->impl();
|
||||
promised_req.pushed(true);
|
||||
promised_req.method(std::move(method));
|
||||
promised_req.scheme(req.scheme());
|
||||
promised_req.authority(req.authority());
|
||||
promised_req.path(std::move(path));
|
||||
promised_req.host(req.host());
|
||||
promised_req.set_header(std::move(headers));
|
||||
if(!req.host().empty()) {
|
||||
promised_req.add_header("host", req.host());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool http2_handler::run_task(thread_cb start)
|
||||
{
|
||||
auto strand = strand_;
|
||||
|
||||
try {
|
||||
task_io_service_.post
|
||||
([start, strand]()
|
||||
{
|
||||
channel chan;
|
||||
chan.impl().strand(strand.get());
|
||||
|
||||
start(chan);
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch(std::exception& ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boost::asio::io_service& http2_handler::io_service()
|
||||
{
|
||||
return io_service_;
|
||||
}
|
||||
|
||||
callback_guard::callback_guard(http2_handler& h)
|
||||
: handler(h)
|
||||
{
|
||||
handler.enter_callback();
|
||||
}
|
||||
|
||||
callback_guard::~callback_guard()
|
||||
{
|
||||
handler.leave_callback();
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
265
src/asio_http2_handler.h
Normal file
265
src/asio_http2_handler.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef HTTP2_HANDLER_H
|
||||
#define HTTP2_HANDLER_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
|
||||
class channel_impl {
|
||||
public:
|
||||
channel_impl();
|
||||
void post(void_cb cb);
|
||||
void strand(boost::asio::io_service::strand *strand);
|
||||
private:
|
||||
boost::asio::io_service::strand *strand_;
|
||||
};
|
||||
|
||||
namespace server {
|
||||
|
||||
class http2_handler;
|
||||
class http2_stream;
|
||||
|
||||
class request_impl {
|
||||
public:
|
||||
request_impl();
|
||||
|
||||
const std::vector<header>& headers() const;
|
||||
const std::string& method() const;
|
||||
const std::string& scheme() const;
|
||||
const std::string& authority() const;
|
||||
const std::string& host() const;
|
||||
const std::string& path() const;
|
||||
|
||||
bool push(std::string method, std::string path,
|
||||
std::vector<header> headers = {});
|
||||
|
||||
bool pushed() const;
|
||||
bool closed() const;
|
||||
|
||||
void on_data(data_cb cb);
|
||||
void on_end(void_cb cb);
|
||||
|
||||
bool run_task(thread_cb start);
|
||||
|
||||
void set_header(std::vector<header> headers);
|
||||
void add_header(std::string name, std::string value);
|
||||
void method(std::string method);
|
||||
void scheme(std::string scheme);
|
||||
void authority(std::string authority);
|
||||
void host(std::string host);
|
||||
void path(std::string path);
|
||||
void pushed(bool f);
|
||||
void handler(std::weak_ptr<http2_handler> h);
|
||||
void stream(std::weak_ptr<http2_stream> s);
|
||||
void call_on_data(const uint8_t *data, std::size_t len);
|
||||
void call_on_end();
|
||||
private:
|
||||
std::vector<header> headers_;
|
||||
std::string method_;
|
||||
std::string scheme_;
|
||||
std::string authority_;
|
||||
std::string host_;
|
||||
std::string path_;
|
||||
data_cb on_data_cb_;
|
||||
void_cb on_end_cb_;
|
||||
std::weak_ptr<http2_handler> handler_;
|
||||
std::weak_ptr<http2_stream> stream_;
|
||||
bool pushed_;
|
||||
};
|
||||
|
||||
class response_impl {
|
||||
public:
|
||||
response_impl();
|
||||
void write_head(unsigned int status_code, std::vector<header> headers = {});
|
||||
void end(std::string data = "");
|
||||
void end(read_cb cb);
|
||||
void resume();
|
||||
bool closed() const;
|
||||
|
||||
unsigned int status_code() const;
|
||||
const std::vector<header>& headers() const;
|
||||
bool started() const;
|
||||
void handler(std::weak_ptr<http2_handler> h);
|
||||
void stream(std::weak_ptr<http2_stream> s);
|
||||
read_cb::result_type call_read(uint8_t *data, std::size_t len);
|
||||
private:
|
||||
std::vector<header> headers_;
|
||||
read_cb read_cb_;
|
||||
std::weak_ptr<http2_handler> handler_;
|
||||
std::weak_ptr<http2_stream> stream_;
|
||||
unsigned int status_code_;
|
||||
bool started_;
|
||||
};
|
||||
|
||||
class http2_stream {
|
||||
public:
|
||||
http2_stream(int32_t stream_id);
|
||||
|
||||
int32_t get_stream_id() const;
|
||||
const std::shared_ptr<request>& get_request();
|
||||
const std::shared_ptr<response>& get_response();
|
||||
private:
|
||||
std::shared_ptr<request> request_;
|
||||
std::shared_ptr<response> response_;
|
||||
int32_t stream_id_;
|
||||
};
|
||||
|
||||
struct callback_guard {
|
||||
callback_guard(http2_handler& h);
|
||||
~callback_guard();
|
||||
http2_handler& handler;
|
||||
};
|
||||
|
||||
typedef std::function<void(void)> connection_write;
|
||||
|
||||
class http2_handler : public std::enable_shared_from_this<http2_handler> {
|
||||
public:
|
||||
http2_handler(boost::asio::io_service& io_service,
|
||||
boost::asio::io_service& task_io_service,
|
||||
connection_write writefun,
|
||||
request_cb cb);
|
||||
|
||||
~http2_handler();
|
||||
|
||||
int start();
|
||||
|
||||
std::shared_ptr<http2_stream> create_stream(int32_t stream_id);
|
||||
void close_stream(int32_t stream_id);
|
||||
std::shared_ptr<http2_stream> find_stream(int32_t stream_id);
|
||||
|
||||
void call_on_request(http2_stream& stream);
|
||||
|
||||
bool should_stop() const;
|
||||
|
||||
int start_response(http2_stream& stream);
|
||||
|
||||
void stream_error(int32_t stream_id, uint32_t error_code);
|
||||
|
||||
void initiate_write();
|
||||
|
||||
void enter_callback();
|
||||
void leave_callback();
|
||||
bool inside_callback() const;
|
||||
|
||||
void resume(http2_stream& stream);
|
||||
|
||||
int push_promise(http2_stream& stream, std::string method,
|
||||
std::string path,
|
||||
std::vector<header> headers);
|
||||
|
||||
bool run_task(thread_cb start);
|
||||
|
||||
boost::asio::io_service& io_service();
|
||||
|
||||
template<size_t N>
|
||||
int on_read(const boost::array<uint8_t, N>& buffer, std::size_t len)
|
||||
{
|
||||
callback_guard cg(*this);
|
||||
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, buffer.data(), len);
|
||||
|
||||
if(rv < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
int on_write(boost::array<uint8_t, N>& buffer, std::size_t& len)
|
||||
{
|
||||
callback_guard cg(*this);
|
||||
|
||||
len = 0;
|
||||
|
||||
if(buf_) {
|
||||
std::copy(buf_, buf_ + buflen_, std::begin(buffer));
|
||||
|
||||
len += buflen_;
|
||||
|
||||
buf_ = nullptr;
|
||||
buflen_ = 0;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
const uint8_t *data;
|
||||
auto nread = nghttp2_session_mem_send(session_, &data);
|
||||
if(nread < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(nread == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(len + nread > buffer.size()) {
|
||||
buf_ = data;
|
||||
buflen_ = nread;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
std::copy(data, data + nread, std::begin(buffer) + len);
|
||||
|
||||
len += nread;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<int32_t, std::shared_ptr<http2_stream>> streams_;
|
||||
connection_write writefun_;
|
||||
request_cb request_cb_;
|
||||
boost::asio::io_service& io_service_;
|
||||
boost::asio::io_service& task_io_service_;
|
||||
std::shared_ptr<boost::asio::io_service::strand> strand_;
|
||||
nghttp2_session *session_;
|
||||
const uint8_t *buf_;
|
||||
std::size_t buflen_;
|
||||
bool inside_callback_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp
|
||||
|
||||
#endif // HTTP2_HANDLER_H
|
||||
214
src/asio_http2_impl.cc
Normal file
214
src/asio_http2_impl.cc
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_http2_impl.h"
|
||||
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#include "asio_server.h"
|
||||
#include "util.h"
|
||||
#include "ssl.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
http2::http2()
|
||||
: impl_(util::make_unique<http2_impl>())
|
||||
{}
|
||||
|
||||
http2::~http2()
|
||||
{}
|
||||
|
||||
void http2::listen(const std::string& address, uint16_t port, request_cb cb)
|
||||
{
|
||||
impl_->listen(address, port, std::move(cb));
|
||||
}
|
||||
|
||||
void http2::num_threads(size_t num_threads)
|
||||
{
|
||||
impl_->num_threads(num_threads);
|
||||
}
|
||||
|
||||
void http2::tls(std::string private_key_file,
|
||||
std::string certificate_file)
|
||||
{
|
||||
impl_->tls(std::move(private_key_file), std::move(certificate_file));
|
||||
}
|
||||
|
||||
void http2::num_concurrent_tasks(size_t num_concurrent_tasks)
|
||||
{
|
||||
impl_->num_concurrent_tasks(num_concurrent_tasks);
|
||||
}
|
||||
|
||||
http2_impl::http2_impl()
|
||||
: num_threads_(1),
|
||||
num_concurrent_tasks_(1)
|
||||
{}
|
||||
|
||||
namespace {
|
||||
std::array<unsigned char, NGHTTP2_PROTO_VERSION_ID_LEN + 1>&
|
||||
get_alpn_token()
|
||||
{
|
||||
static std::array<unsigned char, NGHTTP2_PROTO_VERSION_ID_LEN + 1> token;
|
||||
|
||||
token[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
|
||||
std::copy(NGHTTP2_PROTO_VERSION_ID,
|
||||
NGHTTP2_PROTO_VERSION_ID + NGHTTP2_PROTO_VERSION_ID_LEN,
|
||||
std::begin(token) + 1);
|
||||
return token;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void http2_impl::listen(const std::string& address, uint16_t port,
|
||||
request_cb cb)
|
||||
{
|
||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx;
|
||||
|
||||
if(!private_key_file_.empty() && !certificate_file_.empty()) {
|
||||
ssl_ctx = util::make_unique<boost::asio::ssl::context>
|
||||
(boost::asio::ssl::context::sslv23);
|
||||
|
||||
ssl_ctx->use_private_key_file(private_key_file_,
|
||||
boost::asio::ssl::context::pem);
|
||||
ssl_ctx->use_certificate_chain_file(certificate_file_);
|
||||
|
||||
auto ctx = ssl_ctx->native_handle();
|
||||
|
||||
SSL_CTX_set_options(ctx,
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
||||
SSL_OP_SINGLE_ECDH_USE |
|
||||
SSL_OP_NO_TICKET |
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
|
||||
SSL_CTX_set_cipher_list(ctx, ssl::DEFAULT_CIPHER_LIST);
|
||||
|
||||
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
if(ecdh) {
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
}
|
||||
|
||||
SSL_CTX_set_next_protos_advertised_cb
|
||||
(ctx,
|
||||
[](SSL *s, const unsigned char **data, unsigned int *len, void *arg) {
|
||||
auto& token = get_alpn_token();
|
||||
|
||||
*data = token.data();
|
||||
*len = token.size();
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}, nullptr);
|
||||
}
|
||||
|
||||
server(address, port, num_threads_, num_concurrent_tasks_,
|
||||
std::move(cb), std::move(ssl_ctx)).run();
|
||||
}
|
||||
|
||||
void http2_impl::num_threads(size_t num_threads)
|
||||
{
|
||||
num_threads_ = num_threads;
|
||||
}
|
||||
|
||||
void http2_impl::tls(std::string private_key_file,
|
||||
std::string certificate_file)
|
||||
{
|
||||
private_key_file_ = std::move(private_key_file);
|
||||
certificate_file_ = std::move(certificate_file);
|
||||
}
|
||||
|
||||
void http2_impl::num_concurrent_tasks(size_t num_concurrent_tasks)
|
||||
{
|
||||
num_concurrent_tasks_ = num_concurrent_tasks;
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
|
||||
template<typename T, typename F>
|
||||
std::shared_ptr<util::Defer<T, F>> defer_shared(T&& t, F f)
|
||||
{
|
||||
return std::make_shared<util::Defer<T, F>>(std::forward<T>(t),
|
||||
std::forward<F>(f));
|
||||
}
|
||||
|
||||
read_cb file_reader(const std::string& path)
|
||||
{
|
||||
auto fd = open(path.c_str(), O_RDONLY);
|
||||
if(fd == -1) {
|
||||
return read_cb();
|
||||
}
|
||||
|
||||
return file_reader_from_fd(fd);
|
||||
}
|
||||
|
||||
read_cb file_reader_from_fd(int fd)
|
||||
{
|
||||
auto d = defer_shared(static_cast<int>(fd), close);
|
||||
|
||||
return [fd, d](uint8_t *buf, size_t len) -> read_cb::result_type
|
||||
{
|
||||
int rv;
|
||||
while((rv = read(fd, buf, len)) == -1 && errno == EINTR);
|
||||
|
||||
if(rv == -1) {
|
||||
return std::make_pair(-1, false);
|
||||
}
|
||||
|
||||
if(rv == 0) {
|
||||
return std::make_pair(rv, true);
|
||||
}
|
||||
|
||||
return std::make_pair(rv, false);
|
||||
};
|
||||
}
|
||||
|
||||
bool check_path(const std::string& path)
|
||||
{
|
||||
return util::check_path(path);
|
||||
}
|
||||
|
||||
std::string percent_decode(const std::string& s)
|
||||
{
|
||||
return util::percentDecode(std::begin(s), std::end(s));
|
||||
}
|
||||
|
||||
std::string http_date(int64_t t)
|
||||
{
|
||||
return util::http_date(t);
|
||||
}
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
62
src/asio_http2_impl.h
Normal file
62
src/asio_http2_impl.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_HTTP2_IMPL_H
|
||||
#define ASIO_HTTP2_IMPL_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
class server;
|
||||
|
||||
class http2_impl {
|
||||
public:
|
||||
http2_impl();
|
||||
void listen(const std::string& address, uint16_t port,
|
||||
request_cb cb);
|
||||
void num_threads(size_t num_threads);
|
||||
void tls(std::string private_key_file, std::string certificate_file);
|
||||
void num_concurrent_tasks(size_t num_concurrent_tasks);
|
||||
private:
|
||||
std::string private_key_file_;
|
||||
std::string certificate_file_;
|
||||
std::unique_ptr<server> server_;
|
||||
std::size_t num_threads_;
|
||||
std::size_t num_concurrent_tasks_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_HTTP2_IMPL_H
|
||||
131
src/asio_io_service_pool.cc
Normal file
131
src/asio_io_service_pool.cc
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// io_service_pool.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include "asio_server.h"
|
||||
#include <stdexcept>
|
||||
#include <future>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
io_service_pool::io_service_pool(std::size_t pool_size,
|
||||
std::size_t thread_pool_size)
|
||||
: next_io_service_(0),
|
||||
thread_pool_size_(thread_pool_size)
|
||||
{
|
||||
if (pool_size == 0) {
|
||||
throw std::runtime_error("io_service_pool size is 0");
|
||||
}
|
||||
|
||||
// Give all the io_services work to do so that their run() functions will not
|
||||
// exit until they are explicitly stopped.
|
||||
for (std::size_t i = 0; i < pool_size; ++i) {
|
||||
auto io_service = std::make_shared<boost::asio::io_service>();
|
||||
auto work = std::make_shared<boost::asio::io_service::work>(*io_service);
|
||||
io_services_.push_back(io_service);
|
||||
work_.push_back(work);
|
||||
}
|
||||
|
||||
auto work = std::make_shared<boost::asio::io_service::work>
|
||||
(task_io_service_);
|
||||
work_.push_back(work);
|
||||
}
|
||||
|
||||
void io_service_pool::run()
|
||||
{
|
||||
for(std::size_t i = 0; i < thread_pool_size_; ++i) {
|
||||
thread_pool_.create_thread
|
||||
([this]()
|
||||
{
|
||||
task_io_service_.run();
|
||||
});
|
||||
}
|
||||
|
||||
// Create a pool of threads to run all of the io_services.
|
||||
auto futs = std::vector<std::future<std::size_t>>();
|
||||
|
||||
for (std::size_t i = 0; i < io_services_.size(); ++i) {
|
||||
futs.push_back
|
||||
(std::async(std::launch::async,
|
||||
(size_t(boost::asio::io_service::*)(void))
|
||||
&boost::asio::io_service::run,
|
||||
io_services_[i]));
|
||||
}
|
||||
|
||||
// Wait for all threads in the pool to exit.
|
||||
for (auto& fut : futs) {
|
||||
fut.get();
|
||||
}
|
||||
|
||||
thread_pool_.join_all();
|
||||
}
|
||||
|
||||
void io_service_pool::stop()
|
||||
{
|
||||
// Explicitly stop all io_services.
|
||||
for (auto& iosv : io_services_) {
|
||||
iosv->stop();
|
||||
}
|
||||
|
||||
task_io_service_.stop();
|
||||
}
|
||||
|
||||
boost::asio::io_service& io_service_pool::get_io_service()
|
||||
{
|
||||
// Use a round-robin scheme to choose the next io_service to use.
|
||||
auto& io_service = *io_services_[next_io_service_];
|
||||
++next_io_service_;
|
||||
if (next_io_service_ == io_services_.size()) {
|
||||
next_io_service_ = 0;
|
||||
}
|
||||
return io_service;
|
||||
}
|
||||
|
||||
boost::asio::io_service& io_service_pool::get_task_io_service()
|
||||
{
|
||||
return task_io_service_;
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
101
src/asio_io_service_pool.h
Normal file
101
src/asio_io_service_pool.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// io_service_pool.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef HTTP_SERVER2_IO_SERVICE_POOL_HPP
|
||||
#define HTTP_SERVER2_IO_SERVICE_POOL_HPP
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
/// A pool of io_service objects.
|
||||
class io_service_pool
|
||||
: private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/// Construct the io_service pool.
|
||||
explicit io_service_pool(std::size_t pool_size,
|
||||
std::size_t thread_pool_size);
|
||||
|
||||
/// Run all io_service objects in the pool.
|
||||
void run();
|
||||
|
||||
/// Stop all io_service objects in the pool.
|
||||
void stop();
|
||||
|
||||
/// Get an io_service to use.
|
||||
boost::asio::io_service& get_io_service();
|
||||
|
||||
boost::asio::io_service& get_task_io_service();
|
||||
|
||||
private:
|
||||
typedef std::shared_ptr<boost::asio::io_service> io_service_ptr;
|
||||
typedef std::shared_ptr<boost::asio::io_service::work> work_ptr;
|
||||
|
||||
/// The pool of io_services.
|
||||
std::vector<io_service_ptr> io_services_;
|
||||
|
||||
boost::asio::io_service task_io_service_;
|
||||
boost::thread_group thread_pool_;
|
||||
|
||||
/// The work that keeps the io_services running.
|
||||
std::vector<work_ptr> work_;
|
||||
|
||||
/// The next io_service to use for a connection.
|
||||
std::size_t next_io_service_;
|
||||
|
||||
std::size_t thread_pool_size_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // HTTP_SERVER2_IO_SERVICE_POOL_HPP
|
||||
165
src/asio_server.cc
Normal file
165
src/asio_server.cc
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// server.cpp
|
||||
// ~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include "asio_server.h"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
server::server(const std::string& address, uint16_t port,
|
||||
std::size_t io_service_pool_size,
|
||||
std::size_t thread_pool_size,
|
||||
request_cb cb,
|
||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx)
|
||||
: io_service_pool_(io_service_pool_size, thread_pool_size),
|
||||
signals_(io_service_pool_.get_io_service()),
|
||||
tick_timer_(io_service_pool_.get_io_service(),
|
||||
boost::posix_time::seconds(1)),
|
||||
acceptor_(io_service_pool_.get_io_service()),
|
||||
ssl_ctx_(std::move(ssl_ctx)),
|
||||
request_cb_(std::move(cb))
|
||||
{
|
||||
// Register to handle the signals that indicate when the server should exit.
|
||||
// It is safe to register for the same signal multiple times in a program,
|
||||
// provided all registration for the specified signal is made through Asio.
|
||||
signals_.add(SIGINT);
|
||||
signals_.add(SIGTERM);
|
||||
#if defined(SIGQUIT)
|
||||
signals_.add(SIGQUIT);
|
||||
#endif // defined(SIGQUIT)
|
||||
signals_.async_wait([this](const boost::system::error_code& error,
|
||||
int signal_number)
|
||||
{
|
||||
io_service_pool_.stop();
|
||||
});
|
||||
|
||||
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
||||
boost::asio::ip::tcp::resolver resolver(acceptor_.get_io_service());
|
||||
boost::asio::ip::tcp::resolver::query query(address, std::to_string(port));
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
acceptor_.open(endpoint.protocol());
|
||||
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
acceptor_.bind(endpoint);
|
||||
acceptor_.listen();
|
||||
|
||||
start_accept();
|
||||
|
||||
start_timer();
|
||||
}
|
||||
|
||||
void server::run()
|
||||
{
|
||||
io_service_pool_.run();
|
||||
}
|
||||
|
||||
std::shared_ptr<std::string> cached_date;
|
||||
|
||||
namespace {
|
||||
void update_date()
|
||||
{
|
||||
cached_date = std::make_shared<std::string>(util::http_date(time(nullptr)));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void server::start_timer()
|
||||
{
|
||||
update_date();
|
||||
|
||||
tick_timer_.async_wait
|
||||
([this](const boost::system::error_code& e)
|
||||
{
|
||||
tick_timer_.expires_at(tick_timer_.expires_at() +
|
||||
boost::posix_time::seconds(1));
|
||||
start_timer();
|
||||
});
|
||||
}
|
||||
|
||||
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
|
||||
|
||||
void server::start_accept()
|
||||
{
|
||||
if(ssl_ctx_) {
|
||||
auto new_connection =
|
||||
std::make_shared<connection<ssl_socket>>
|
||||
(request_cb_, io_service_pool_.get_task_io_service(),
|
||||
io_service_pool_.get_io_service(), *ssl_ctx_);
|
||||
|
||||
acceptor_.async_accept
|
||||
(new_connection->socket().lowest_layer(),
|
||||
[this, new_connection](const boost::system::error_code& e)
|
||||
{
|
||||
if(!e) {
|
||||
new_connection->socket().lowest_layer().set_option
|
||||
(boost::asio::ip::tcp::no_delay(true));
|
||||
new_connection->socket().async_handshake
|
||||
(boost::asio::ssl::stream_base::server,
|
||||
[new_connection](const boost::system::error_code& e)
|
||||
{
|
||||
if(!e) {
|
||||
new_connection->start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
start_accept();
|
||||
});
|
||||
} else {
|
||||
auto new_connection =
|
||||
std::make_shared<connection<boost::asio::ip::tcp::socket>>
|
||||
(request_cb_, io_service_pool_.get_task_io_service(),
|
||||
io_service_pool_.get_io_service());
|
||||
|
||||
acceptor_.async_accept
|
||||
(new_connection->socket(),
|
||||
[this, new_connection](const boost::system::error_code& e)
|
||||
{
|
||||
if (!e) {
|
||||
new_connection->socket().set_option
|
||||
(boost::asio::ip::tcp::no_delay(true));
|
||||
new_connection->start();
|
||||
}
|
||||
|
||||
start_accept();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
104
src/asio_server.h
Normal file
104
src/asio_server.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// server.hpp
|
||||
// ~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef HTTP_SERVER2_SERVER_HPP
|
||||
#define HTTP_SERVER2_SERVER_HPP
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
#include "asio_connection.h"
|
||||
#include "asio_io_service_pool.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
/// The top-level class of the HTTP server.
|
||||
class server
|
||||
: private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/// Construct the server to listen on the specified TCP address and port, and
|
||||
/// serve up files from the given directory.
|
||||
explicit server(const std::string& address, uint16_t port,
|
||||
std::size_t io_service_pool_size,
|
||||
std::size_t thread_pool_size,
|
||||
request_cb cb,
|
||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx);
|
||||
|
||||
/// Run the server's io_service loop.
|
||||
void run();
|
||||
|
||||
private:
|
||||
/// Initiate an asynchronous accept operation.
|
||||
void start_accept();
|
||||
|
||||
void start_timer();
|
||||
|
||||
/// The pool of io_service objects used to perform asynchronous operations.
|
||||
io_service_pool io_service_pool_;
|
||||
|
||||
/// The signal_set is used to register for process termination notifications.
|
||||
boost::asio::signal_set signals_;
|
||||
|
||||
boost::asio::deadline_timer tick_timer_;
|
||||
|
||||
/// Acceptor used to listen for incoming connections.
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
|
||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx_;
|
||||
|
||||
request_cb request_cb_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // HTTP_SERVER2_SERVER_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user