mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-07 18:48:54 +08:00
Compare commits
243 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a46a2c0a4 | ||
|
|
fbff101165 | ||
|
|
526d2c727d | ||
|
|
6c232da679 | ||
|
|
1241c951d6 | ||
|
|
73e79130d1 | ||
|
|
1a1902350b | ||
|
|
eec65826cf | ||
|
|
fc17c0a618 | ||
|
|
2620992003 | ||
|
|
5a2069b55c | ||
|
|
14adcb2d81 | ||
|
|
13660edef2 | ||
|
|
98034286ac | ||
|
|
2a37a28d72 | ||
|
|
7bb154f768 | ||
|
|
eb96aa261f | ||
|
|
232d359cbb | ||
|
|
2d5d9d5d04 | ||
|
|
7ecca39025 | ||
|
|
bc0190c19f | ||
|
|
9a162b81f0 | ||
|
|
a67a8fabff | ||
|
|
989d381aab | ||
|
|
1d65d82cb5 | ||
|
|
4be4d875f3 | ||
|
|
1ab707713f | ||
|
|
cc46d363c5 | ||
|
|
fa082cbdd0 | ||
|
|
016d40ea0f | ||
|
|
fe6d065bb4 | ||
|
|
b4e8bea4b5 | ||
|
|
555d5abac9 | ||
|
|
3137dc4a70 | ||
|
|
4bba4bf66c | ||
|
|
7b3a33a313 | ||
|
|
ee52290de7 | ||
|
|
8f0899a190 | ||
|
|
f6cfd082c7 | ||
|
|
9d81be4b35 | ||
|
|
a62778d6b0 | ||
|
|
ea612a2dce | ||
|
|
026521b097 | ||
|
|
9dc5259593 | ||
|
|
ea8a566d98 | ||
|
|
8c6f9e899f | ||
|
|
552f675466 | ||
|
|
f9a50333d2 | ||
|
|
f05a4830c5 | ||
|
|
9e1b068a4b | ||
|
|
54bff91762 | ||
|
|
63630690a8 | ||
|
|
dbc613e0d0 | ||
|
|
ee354ee6c8 | ||
|
|
df707df21b | ||
|
|
2436acbd23 | ||
|
|
b41835f19b | ||
|
|
42b2430fe1 | ||
|
|
c8f67788e0 | ||
|
|
bbdff112a3 | ||
|
|
02468b1ca1 | ||
|
|
c41f413978 | ||
|
|
e38dd37667 | ||
|
|
f2cf2b625c | ||
|
|
eb05777d88 | ||
|
|
6b0b8ea7d5 | ||
|
|
c925c32233 | ||
|
|
514558afc0 | ||
|
|
b9f602b9a2 | ||
|
|
1a99bcc860 | ||
|
|
6b8aa36c98 | ||
|
|
86ddda5c0e | ||
|
|
58b7f4a096 | ||
|
|
4069aab4f7 | ||
|
|
5595ba643e | ||
|
|
77c556901c | ||
|
|
4928959213 | ||
|
|
a200bb1084 | ||
|
|
92a1ca5917 | ||
|
|
97648d257f | ||
|
|
787d40129b | ||
|
|
91ad7e150e | ||
|
|
28bde2cef0 | ||
|
|
a9b54a1bfa | ||
|
|
80f0e99f00 | ||
|
|
102ea7c0bb | ||
|
|
85671a69bf | ||
|
|
a3fa257473 | ||
|
|
c4e994c97d | ||
|
|
0b41e20d54 | ||
|
|
cfabce6e70 | ||
|
|
b948c5457d | ||
|
|
3bdf78e8af | ||
|
|
436595df98 | ||
|
|
d3561a63b1 | ||
|
|
1a12a9b397 | ||
|
|
57644e0256 | ||
|
|
7323d4c639 | ||
|
|
e23225689f | ||
|
|
e6ad2eb14f | ||
|
|
d4a22edeb3 | ||
|
|
8f4e2d941f | ||
|
|
1a8da6caec | ||
|
|
dc335b9025 | ||
|
|
93afbc7d2f | ||
|
|
82e2c5bd22 | ||
|
|
53bcafb39f | ||
|
|
59f8397659 | ||
|
|
061732adf0 | ||
|
|
5c2ca28706 | ||
|
|
a8ea86cfe5 | ||
|
|
7451a73def | ||
|
|
889e705f35 | ||
|
|
14d4979c54 | ||
|
|
095bc178f3 | ||
|
|
308738025c | ||
|
|
97366bf55c | ||
|
|
87cadca3d8 | ||
|
|
9803f92e9c | ||
|
|
cbfa021095 | ||
|
|
03746884a4 | ||
|
|
6ed710adbd | ||
|
|
44b4cda200 | ||
|
|
69a4f3bf42 | ||
|
|
5334cb5acc | ||
|
|
6ca24264e4 | ||
|
|
37a631278f | ||
|
|
5c42687759 | ||
|
|
b636e9744f | ||
|
|
b873930802 | ||
|
|
bc53c81616 | ||
|
|
09c485e712 | ||
|
|
d247470da2 | ||
|
|
4aca2f0b59 | ||
|
|
9d711f65f7 | ||
|
|
0eab08a7cf | ||
|
|
b9c4757d21 | ||
|
|
1fcd881395 | ||
|
|
cd0564ddfa | ||
|
|
dd435b51ab | ||
|
|
ff60cc6b71 | ||
|
|
80743ddc7b | ||
|
|
36a8f24559 | ||
|
|
b25e19e876 | ||
|
|
e9660c3558 | ||
|
|
8c3b379b66 | ||
|
|
b2bb6f1db1 | ||
|
|
d56ecd7414 | ||
|
|
ef4e39be55 | ||
|
|
d42f31ca78 | ||
|
|
7522d50d1a | ||
|
|
cc03a12b75 | ||
|
|
9eff511c5e | ||
|
|
a96ac6f0a0 | ||
|
|
213a63d97d | ||
|
|
8d4548b9c1 | ||
|
|
44f2e6ae1d | ||
|
|
0cd7d268f3 | ||
|
|
f3a9041851 | ||
|
|
776a8c64f6 | ||
|
|
524a1f9498 | ||
|
|
28cfae162a | ||
|
|
b0123448a4 | ||
|
|
2d15dca096 | ||
|
|
5f05135d1b | ||
|
|
3b6b4ff066 | ||
|
|
0c8ec7bfa6 | ||
|
|
2c05b8d6f0 | ||
|
|
45c4187d8f | ||
|
|
87029e05af | ||
|
|
363914c3f7 | ||
|
|
1316065c14 | ||
|
|
2b6a181bef | ||
|
|
bf68df9ef4 | ||
|
|
e7f6089b0e | ||
|
|
a1500b0ee3 | ||
|
|
14001052f8 | ||
|
|
95ab54c79d | ||
|
|
5e84f767f0 | ||
|
|
c47855085b | ||
|
|
1442b1bd0a | ||
|
|
763293a050 | ||
|
|
cc94632b29 | ||
|
|
5df770b9c1 | ||
|
|
4bc9afe20a | ||
|
|
522faeb24f | ||
|
|
362ff09183 | ||
|
|
ccea4d42b5 | ||
|
|
ebbe065716 | ||
|
|
3a97f21383 | ||
|
|
12ced1cddc | ||
|
|
3576f20e5a | ||
|
|
7ae6e6b4c5 | ||
|
|
a2486daee1 | ||
|
|
8bf440b89c | ||
|
|
e9cdb9c896 | ||
|
|
c4804ee50b | ||
|
|
95cb284e27 | ||
|
|
c4ccc376df | ||
|
|
6133110386 | ||
|
|
6f58434d89 | ||
|
|
3fd5d0af79 | ||
|
|
1a6855ea7d | ||
|
|
0312521ac9 | ||
|
|
67b0e0c2d6 | ||
|
|
966e3a1308 | ||
|
|
fd8f8e2708 | ||
|
|
d7fdcbb3d6 | ||
|
|
de2c2ad65c | ||
|
|
862a0ee66b | ||
|
|
c2510a01a5 | ||
|
|
dc85623060 | ||
|
|
8afbb6ca26 | ||
|
|
ed79637737 | ||
|
|
faa2c4467a | ||
|
|
c87fae463e | ||
|
|
29b4b11e78 | ||
|
|
3b24be3bcd | ||
|
|
ece8289aaf | ||
|
|
4042ff0fc4 | ||
|
|
d3d6c5e314 | ||
|
|
125e32eb56 | ||
|
|
94bf8dcd4e | ||
|
|
89b8039466 | ||
|
|
72843b33d0 | ||
|
|
03e699e013 | ||
|
|
fcf99fa8fc | ||
|
|
661fb2eb0e | ||
|
|
42496d638b | ||
|
|
c0a6a0a6d1 | ||
|
|
b7bda783c5 | ||
|
|
6893608ae2 | ||
|
|
ef913bc929 | ||
|
|
a5ed70bcfe | ||
|
|
9bf2ca6916 | ||
|
|
57729d0a23 | ||
|
|
e86b81ec10 | ||
|
|
076eefbed6 | ||
|
|
58a735dc68 | ||
|
|
948d4d43d5 | ||
|
|
ef581e94bb | ||
|
|
ad84af2b2b | ||
|
|
0e65e1254d |
50
.gitignore
vendored
50
.gitignore
vendored
@@ -1,14 +1,18 @@
|
|||||||
|
# emacs backup file
|
||||||
*~
|
*~
|
||||||
*.o
|
|
||||||
*.lo
|
# autotools
|
||||||
*.la
|
*.la
|
||||||
depcomp
|
*.lo
|
||||||
*.m4
|
*.m4
|
||||||
|
*.o
|
||||||
|
.deps/
|
||||||
|
.libs/
|
||||||
|
INSTALL
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
libtool
|
|
||||||
missing
|
|
||||||
autom4te.cache/
|
autom4te.cache/
|
||||||
|
compile
|
||||||
config.guess
|
config.guess
|
||||||
config.h
|
config.h
|
||||||
config.h.in
|
config.h.in
|
||||||
@@ -16,36 +20,14 @@ config.log
|
|||||||
config.status
|
config.status
|
||||||
config.sub
|
config.sub
|
||||||
configure
|
configure
|
||||||
|
depcomp
|
||||||
install-sh
|
install-sh
|
||||||
.deps/
|
libtool
|
||||||
.libs
|
|
||||||
lib/includes/nghttp2/nghttp2ver.h
|
|
||||||
lib/libnghttp2.pc
|
|
||||||
src/libnghttp2_asio.pc
|
|
||||||
ltmain.sh
|
ltmain.sh
|
||||||
|
missing
|
||||||
stamp-h1
|
stamp-h1
|
||||||
.deps/
|
|
||||||
INSTALL
|
|
||||||
.DS_STORE
|
|
||||||
compile
|
|
||||||
test-driver
|
test-driver
|
||||||
.dirstamp
|
|
||||||
doc/index.rst
|
# test logs generated by `make check`
|
||||||
doc/nghttp2.h.rst
|
*.log
|
||||||
doc/nghttp2ver.h.rst
|
*.trs
|
||||||
doc/package_README.rst
|
|
||||||
doc/tutorial-client.rst
|
|
||||||
doc/tutorial-server.rst
|
|
||||||
doc/nghttpx-howto.rst
|
|
||||||
doc/h2load-howto.rst
|
|
||||||
doc/tutorial-hpack.rst
|
|
||||||
doc/python-apiref.rst
|
|
||||||
doc/building-android-binary.rst
|
|
||||||
doc/asio_http2.h.rst
|
|
||||||
doc/asio_http2_server.h.rst
|
|
||||||
doc/asio_http2_client.h.rst
|
|
||||||
doc/libnghttp2_asio.rst
|
|
||||||
doc/contribute.rst
|
|
||||||
python/setup.py
|
|
||||||
python/dist
|
|
||||||
python/MANIFEST
|
|
||||||
|
|||||||
46
.travis.yml
46
.travis.yml
@@ -1,31 +1,31 @@
|
|||||||
language: cpp
|
language: cpp
|
||||||
compiler:
|
compiler:
|
||||||
- clang
|
- clang
|
||||||
#Disable gcc build for the moment...
|
- gcc
|
||||||
# - gcc
|
sudo: false
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- g++-4.9
|
||||||
|
- libstdc++-4.9-dev
|
||||||
|
- autoconf
|
||||||
|
- automake
|
||||||
|
- autotools-dev
|
||||||
|
- libtool
|
||||||
|
- pkg-config
|
||||||
|
- zlib1g-dev
|
||||||
|
- libcunit1-dev
|
||||||
|
- libssl-dev
|
||||||
|
- libxml2-dev
|
||||||
|
- libev-dev
|
||||||
|
- libevent-dev
|
||||||
|
- libjansson-dev
|
||||||
|
- libjemalloc-dev
|
||||||
before_install:
|
before_install:
|
||||||
- $CC --version
|
- $CC --version
|
||||||
- sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
|
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
|
||||||
- sudo apt-get update -qq
|
|
||||||
#Install and use gcc-4.8 (don't build with gcc-4.6)
|
|
||||||
#libstdc++-4.8 is needed by Clang to build too
|
|
||||||
- sudo apt-get -qq install g++-4.8 libstdc++-4.8-dev
|
|
||||||
- >
|
|
||||||
sudo apt-get install --no-install-recommends -qq
|
|
||||||
autoconf
|
|
||||||
automake
|
|
||||||
autotools-dev
|
|
||||||
libtool
|
|
||||||
pkg-config
|
|
||||||
zlib1g-dev
|
|
||||||
libcunit1-dev
|
|
||||||
libssl-dev
|
|
||||||
libxml2-dev
|
|
||||||
libev-dev
|
|
||||||
libevent-dev
|
|
||||||
libjansson-dev
|
|
||||||
libjemalloc-dev
|
|
||||||
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
|
|
||||||
- $CC --version
|
- $CC --version
|
||||||
before_script:
|
before_script:
|
||||||
- autoreconf -i
|
- autoreconf -i
|
||||||
|
|||||||
18
CONTRIBUTION
Normal file
18
CONTRIBUTION
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[The text below was composed based on 1.2. License section of
|
||||||
|
curl/libcurl project.]
|
||||||
|
|
||||||
|
When contributing with code, you agree to put your changes and new
|
||||||
|
code under the same license nghttp2 is already using unless stated and
|
||||||
|
agreed otherwise.
|
||||||
|
|
||||||
|
When changing existing source code, you do not alter the copyright of
|
||||||
|
the original file(s). The copyright will still be owned by the
|
||||||
|
original creator(s) or those who have been assigned copyright by the
|
||||||
|
original author(s).
|
||||||
|
|
||||||
|
By submitting a patch to the nghttp2 project, you are assumed to have
|
||||||
|
the right to the code and to be allowed by your employer or whatever
|
||||||
|
to hand over that patch/code to us. We will credit you for your
|
||||||
|
changes as far as possible, to give credit but also to keep a trace
|
||||||
|
back to who made what changes. Please always provide us with your
|
||||||
|
full real name when contributing!
|
||||||
19
COPYING
19
COPYING
@@ -20,22 +20,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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!
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# vim: ft=dockerfile:
|
||||||
# Dockerfile to build nghttp2 android binary
|
# Dockerfile to build nghttp2 android binary
|
||||||
#
|
#
|
||||||
# $ sudo docker build -t nghttp2-android - < Dockerfile.android
|
# $ sudo docker build -t nghttp2-android - < Dockerfile.android
|
||||||
@@ -9,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
|
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
|
||||||
|
|
||||||
FROM ubuntu
|
FROM ubuntu:trusty
|
||||||
|
|
||||||
MAINTAINER Tatsuhiro Tsujikawa
|
MAINTAINER Tatsuhiro Tsujikawa
|
||||||
|
|
||||||
@@ -29,9 +30,10 @@ RUN apt-get install -y make binutils autoconf automake autotools-dev libtool \
|
|||||||
genisoimage libc6-i386 lib32stdc++6
|
genisoimage libc6-i386 lib32stdc++6
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin
|
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
|
chmod a+x android-ndk-r10c-linux-x86_64.bin && \
|
||||||
RUN ./android-ndk-r10c-linux-x86_64.bin
|
./android-ndk-r10c-linux-x86_64.bin && \
|
||||||
|
rm android-ndk-r10c-linux-x86_64.bin
|
||||||
|
|
||||||
WORKDIR /root/build/android-ndk-r10c
|
WORKDIR /root/build/android-ndk-r10c
|
||||||
RUN /bin/bash build/tools/make-standalone-toolchain.sh \
|
RUN /bin/bash build/tools/make-standalone-toolchain.sh \
|
||||||
@@ -57,20 +59,24 @@ RUN autoreconf -i && \
|
|||||||
make install
|
make install
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.1j.tar.gz
|
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.2a.tar.gz && \
|
||||||
RUN tar xf openssl-1.0.1j.tar.gz
|
tar xf openssl-1.0.2a.tar.gz && \
|
||||||
WORKDIR /root/build/openssl-1.0.1j
|
rm openssl-1.0.2a.tar.gz
|
||||||
|
|
||||||
|
WORKDIR /root/build/openssl-1.0.2a
|
||||||
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
|
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
|
||||||
./Configure --prefix=$PREFIX android && \
|
./Configure --prefix=$PREFIX android && \
|
||||||
make && make install_sw
|
make && make install_sw
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O http://dist.schmorp.de/libev/libev-4.19.tar.gz
|
RUN curl -L -O http://dist.schmorp.de/libev/libev-4.19.tar.gz && \
|
||||||
RUN curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch
|
curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch && \
|
||||||
RUN tar xf libev-4.19.tar.gz
|
tar xf libev-4.19.tar.gz && \
|
||||||
|
rm libev-4.19.tar.gz
|
||||||
|
|
||||||
WORKDIR /root/build/libev-4.19
|
WORKDIR /root/build/libev-4.19
|
||||||
RUN patch -p1 < ../libev-4.19-android.patch
|
RUN patch -p1 < ../libev-4.19-android.patch && \
|
||||||
RUN ./configure \
|
./configure \
|
||||||
--host=arm-linux-androideabi \
|
--host=arm-linux-androideabi \
|
||||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||||
--prefix=$PREFIX \
|
--prefix=$PREFIX \
|
||||||
@@ -95,9 +101,9 @@ RUN autoreconf -i && \
|
|||||||
--disable-threads \
|
--disable-threads \
|
||||||
LIBSPDYLAY_CFLAGS=-I$PREFIX/usr/local/include \
|
LIBSPDYLAY_CFLAGS=-I$PREFIX/usr/local/include \
|
||||||
LIBSPDYLAY_LIBS="-L$PREFIX/usr/local/lib -lspdylay" \
|
LIBSPDYLAY_LIBS="-L$PREFIX/usr/local/lib -lspdylay" \
|
||||||
CPPFLAGS="-I$PREFIX/include" \
|
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||||
CXXFLAGS="-fno-strict-aliasing" \
|
CXXFLAGS="-fno-strict-aliasing" \
|
||||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||||
LDFLAGS="-L$PREFIX/lib" && \
|
LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
|
||||||
make && \
|
make && \
|
||||||
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp
|
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp
|
||||||
|
|||||||
280
README.rst
280
README.rst
@@ -1,30 +1,30 @@
|
|||||||
nghttp2 - HTTP/2 C Library
|
nghttp2 - HTTP/2 C Library
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
This is an implementation of Hypertext Transfer Protocol version 2
|
This is an implementation of the Hypertext Transfer Protocol version 2
|
||||||
in C.
|
in C.
|
||||||
|
|
||||||
The framing layer of HTTP/2 is implemented as a form of reusable C
|
The framing layer of HTTP/2 is implemented as a reusable C
|
||||||
library. On top of that, we have implemented HTTP/2 client, server
|
library. On top of that, we have implemented an HTTP/2 client, server
|
||||||
and proxy. We have also developed load test and benchmarking tool for
|
and proxy. We have also developed load test and benchmarking tools for
|
||||||
HTTP/2 and SPDY.
|
HTTP/2 and SPDY.
|
||||||
|
|
||||||
HPACK encoder and decoder are available as public API.
|
An HPACK encoder and decoder are available as a public API.
|
||||||
|
|
||||||
The experimental high level C++ library is also available.
|
An experimental high level C++ library is also available.
|
||||||
|
|
||||||
We have Python binding of this libary, but we have not covered
|
We have Python bindings of this libary, but we do not have full
|
||||||
everything yet.
|
code coverage yet.
|
||||||
|
|
||||||
Development Status
|
Development Status
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
We started to implement h2-14
|
We started to implement h2-14
|
||||||
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), the header
|
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), and header
|
||||||
compression
|
compression
|
||||||
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09).
|
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09).
|
||||||
|
|
||||||
The nghttp2 code base was forked from spdylay project.
|
The nghttp2 code base was forked from the spdylay project.
|
||||||
|
|
||||||
=========================== =======
|
=========================== =======
|
||||||
HTTP/2 Features Support
|
HTTP/2 Features Support
|
||||||
@@ -37,7 +37,7 @@ Large header (CONTINUATION) Yes
|
|||||||
Public Test Server
|
Public Test Server
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
The following endpoints are available to try out nghttp2
|
The following endpoints are available to try out our nghttp2
|
||||||
implementation.
|
implementation.
|
||||||
|
|
||||||
* https://nghttp2.org/ (TLS + ALPN/NPN)
|
* https://nghttp2.org/ (TLS + ALPN/NPN)
|
||||||
@@ -67,16 +67,16 @@ To build the documentation, you need to install:
|
|||||||
* sphinx (http://sphinx-doc.org/)
|
* sphinx (http://sphinx-doc.org/)
|
||||||
|
|
||||||
To build and run the application programs (``nghttp``, ``nghttpd`` and
|
To build and run the application programs (``nghttp``, ``nghttpd`` and
|
||||||
``nghttpx``) in ``src`` directory, the following packages are
|
``nghttpx``) in the ``src`` directory, the following packages are
|
||||||
required:
|
required:
|
||||||
|
|
||||||
* OpenSSL >= 1.0.1
|
* OpenSSL >= 1.0.1
|
||||||
* libev >= 4.15
|
* libev >= 4.15
|
||||||
* zlib >= 1.2.3
|
* zlib >= 1.2.3
|
||||||
|
|
||||||
ALPN support requires unreleased version OpenSSL >= 1.0.2.
|
ALPN support requires OpenSSL >= 1.0.2 (released 22 January 2015).
|
||||||
|
|
||||||
To enable SPDY protocol in the application program ``nghttpx`` and
|
To enable the SPDY protocol in the application program ``nghttpx`` and
|
||||||
``h2load``, the following package is required:
|
``h2load``, the following package is required:
|
||||||
|
|
||||||
* spdylay >= 1.3.0
|
* spdylay >= 1.3.0
|
||||||
@@ -90,7 +90,7 @@ The HPACK tools require the following package:
|
|||||||
|
|
||||||
* jansson >= 2.5
|
* jansson >= 2.5
|
||||||
|
|
||||||
To build sources under examples directory, libevent is required:
|
To build sources under the examples directory, libevent is required:
|
||||||
|
|
||||||
* libevent-openssl >= 2.0.8
|
* libevent-openssl >= 2.0.8
|
||||||
|
|
||||||
@@ -109,16 +109,17 @@ The Python bindings require the following packages:
|
|||||||
* cython >= 0.19
|
* cython >= 0.19
|
||||||
* python >= 2.7
|
* python >= 2.7
|
||||||
|
|
||||||
If you are using Ubuntu 14.04 LTS, you need the following packages
|
If you are using Ubuntu 14.04 LTS (trusty), run the following to install the needed packages::
|
||||||
installed::
|
|
||||||
|
|
||||||
apt-get install make binutils autoconf automake autotools-dev libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev libjemalloc-dev cython python3.4-dev
|
sudo apt-get install make binutils autoconf automake autotools-dev libtool pkg-config \
|
||||||
|
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \
|
||||||
|
libjemalloc-dev cython python3.4-dev
|
||||||
|
|
||||||
spdylay is not packaged in Ubuntu, so you need to build it yourself:
|
spdylay is not packaged in Ubuntu, so you need to build it yourself:
|
||||||
http://tatsuhiro-t.github.io/spdylay/
|
http://tatsuhiro-t.github.io/spdylay/
|
||||||
|
|
||||||
Build from git
|
Building from git
|
||||||
--------------
|
-----------------
|
||||||
|
|
||||||
Building from git is easy, but please be sure that at least autoconf 2.68 is
|
Building from git is easy, but please be sure that at least autoconf 2.68 is
|
||||||
used::
|
used::
|
||||||
@@ -129,23 +130,50 @@ used::
|
|||||||
$ ./configure
|
$ ./configure
|
||||||
$ make
|
$ make
|
||||||
|
|
||||||
To compile source code, gcc >= 4.8.3 or clang >= 3.4 is required.
|
To compile the source code, gcc >= 4.8.3 or clang >= 3.4 is required.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Mac OS X users may need ``--disable-threads`` configure option to
|
Mac OS X users may need the ``--disable-threads`` configure option to
|
||||||
disable multi threading in nghttpd, nghttpx and h2load to prevent
|
disable multi-threading in nghttpd, nghttpx and h2load to prevent
|
||||||
them from crashing. Patch is welcome to make multi threading work
|
them from crashing. A patch is welcome to make multi threading work
|
||||||
on Mac OS X platform.
|
on Mac OS X platform.
|
||||||
|
|
||||||
Building documentation
|
Notes for building on Windows (Mingw/Cygwin)
|
||||||
----------------------
|
--------------------------------------------
|
||||||
|
|
||||||
|
Under Mingw environment, you can only compile the library, it's
|
||||||
|
``libnghttp2-X.dll`` and ``libnghttp2.a``.
|
||||||
|
|
||||||
|
If you want to compile the applications(``h2load``, ``nghttp``,
|
||||||
|
``nghttpx``, ``nghttpd``), you need to use the Cygwin environment.
|
||||||
|
|
||||||
|
Under Cygwin environment, to compile the applications you need to
|
||||||
|
compile and install the libev first.
|
||||||
|
|
||||||
|
Secondly, you need to undefine the macro ``__STRICT_ANSI__``, if you
|
||||||
|
not, the functions ``fdopen``, ``fileno`` and ``strptime`` will not
|
||||||
|
available.
|
||||||
|
|
||||||
|
the sample command like this::
|
||||||
|
|
||||||
|
$ export CFLAGS="-U__STRICT_ANSI__ -I$libev_PREFIX/include -L$libev_PREFIX/lib"
|
||||||
|
$ export CXXFLAGS=$CFLAGS
|
||||||
|
$ ./configure
|
||||||
|
$ make
|
||||||
|
|
||||||
|
If you want to compile the applications under ``examples/``, you need
|
||||||
|
to remove or rename the ``event.h`` from libev's installation, because
|
||||||
|
it conflicts with libevent's installation.
|
||||||
|
|
||||||
|
Building the documentation
|
||||||
|
--------------------------
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Documentation is still incomplete.
|
Documentation is still incomplete.
|
||||||
|
|
||||||
To build documentation, run::
|
To build the documentation, run::
|
||||||
|
|
||||||
$ make html
|
$ make html
|
||||||
|
|
||||||
@@ -159,13 +187,13 @@ https://nghttp2.org/documentation/
|
|||||||
Unit tests
|
Unit tests
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Unit tests are done by simply running `make check`.
|
Unit tests are done by simply running ``make check``.
|
||||||
|
|
||||||
Integration tests
|
Integration tests
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
We have the integration tests for nghttpx proxy server. The tests are
|
We have the integration tests for the nghttpx proxy server. The tests are
|
||||||
written in `Go programming language <http://golang.org/>`_ and uses
|
written in the `Go programming language <http://golang.org/>`_ and uses
|
||||||
its testing framework. We depend on the following libraries:
|
its testing framework. We depend on the following libraries:
|
||||||
|
|
||||||
* https://github.com/bradfitz/http2
|
* https://github.com/bradfitz/http2
|
||||||
@@ -182,12 +210,12 @@ To run the tests, run the following command under
|
|||||||
|
|
||||||
$ make it
|
$ make it
|
||||||
|
|
||||||
Inside the tests, we use port 3009 to run test subject server.
|
Inside the tests, we use port 3009 to run the test subject server.
|
||||||
|
|
||||||
Client, Server and Proxy programs
|
Client, Server and Proxy programs
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
The src directory contains HTTP/2 client, server and proxy programs.
|
The ``src`` directory contains the HTTP/2 client, server and proxy programs.
|
||||||
|
|
||||||
nghttp - client
|
nghttp - client
|
||||||
+++++++++++++++
|
+++++++++++++++
|
||||||
@@ -334,7 +362,7 @@ The HTTP Upgrade is performed like this::
|
|||||||
[ 0.038] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
[ 0.038] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
||||||
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
|
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
|
||||||
|
|
||||||
With ``-s`` option, ``nghttp`` prints out some timing information for
|
Using the ``-s`` option, ``nghttp`` prints out some timing information for
|
||||||
requests, sorted by completion time::
|
requests, sorted by completion time::
|
||||||
|
|
||||||
$ nghttp -nas https://nghttp2.org/
|
$ nghttp -nas https://nghttp2.org/
|
||||||
@@ -360,8 +388,8 @@ requests, sorted by completion time::
|
|||||||
+76.14ms +11.17ms 64.97ms 200 171K /images/posts/with-pri-blog.png
|
+76.14ms +11.17ms 64.97ms 200 171K /images/posts/with-pri-blog.png
|
||||||
+88.52ms +11.17ms 77.36ms 200 174K /images/posts/without-pri-blog.png
|
+88.52ms +11.17ms 77.36ms 200 174K /images/posts/without-pri-blog.png
|
||||||
|
|
||||||
With ``-r`` option, ``nghttp`` writes more detailed timing data to
|
Using the ``-r`` option, ``nghttp`` writes more detailed timing data to
|
||||||
given file in HAR format.
|
the given file in HAR format.
|
||||||
|
|
||||||
nghttpd - server
|
nghttpd - server
|
||||||
++++++++++++++++
|
++++++++++++++++
|
||||||
@@ -371,13 +399,13 @@ nghttpd - server
|
|||||||
By default, it uses SSL/TLS connection. Use ``--no-tls`` option to
|
By default, it uses SSL/TLS connection. Use ``--no-tls`` option to
|
||||||
disable it.
|
disable it.
|
||||||
|
|
||||||
``nghttpd`` only accepts the HTTP/2 connection via NPN/ALPN or direct
|
``nghttpd`` only accepts HTTP/2 connections via NPN/ALPN or direct
|
||||||
HTTP/2 connection. No HTTP Upgrade is supported.
|
HTTP/2 connections. No HTTP Upgrade is supported.
|
||||||
|
|
||||||
``-p`` option allows users to configure server push.
|
The ``-p`` option allows users to configure server push.
|
||||||
|
|
||||||
Just like ``nghttp``, it has verbose output mode for framing
|
Just like ``nghttp``, it has a verbose output mode for framing
|
||||||
information. Here is sample output from ``nghttpd`` server::
|
information. Here is sample output from ``nghttpd``::
|
||||||
|
|
||||||
$ nghttpd --no-tls -v 8080
|
$ nghttpd --no-tls -v 8080
|
||||||
IPv4: listen on port 8080
|
IPv4: listen on port 8080
|
||||||
@@ -431,8 +459,15 @@ nghttpx - proxy
|
|||||||
+++++++++++++++
|
+++++++++++++++
|
||||||
|
|
||||||
``nghttpx`` is a multi-threaded reverse proxy for ``h2-14``, SPDY and
|
``nghttpx`` is a multi-threaded reverse proxy for ``h2-14``, SPDY and
|
||||||
HTTP/1.1 and powers nghttp2.org site and supports HTTP/2 server push.
|
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server push.
|
||||||
It has several operation modes:
|
|
||||||
|
``nghttpx`` implements `important performance-oriented features
|
||||||
|
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
|
||||||
|
session IDs, session tickets (with automatic key rotation), OCSP
|
||||||
|
stapling, dynamic record sizing, ALPN/NPN, forward secrecy and SPDY &
|
||||||
|
HTTP/2.
|
||||||
|
|
||||||
|
``nghttpx`` has several operational modes:
|
||||||
|
|
||||||
================== ============================ ============== =============
|
================== ============================ ============== =============
|
||||||
Mode option Frontend Backend Note
|
Mode option Frontend Backend Note
|
||||||
@@ -446,19 +481,19 @@ default mode HTTP/2, SPDY, HTTP/1.1 (TLS) HTTP/1.1 Reverse proxy
|
|||||||
|
|
||||||
The interesting mode at the moment is the default mode. It works like
|
The interesting mode at the moment is the default mode. It works like
|
||||||
a reverse proxy and listens for ``h2-14``, SPDY and HTTP/1.1 and can
|
a reverse proxy and listens for ``h2-14``, SPDY and HTTP/1.1 and can
|
||||||
be deployed SSL/TLS terminator for existing web server.
|
be deployed as a SSL/TLS terminator for existing web server.
|
||||||
|
|
||||||
The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
|
The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
|
||||||
SSL/TLS in the frontend connection by default. To disable SSL/TLS,
|
SSL/TLS in the frontend connection by default. To disable SSL/TLS,
|
||||||
use ``--frontend-no-tls`` option. If that option is used, SPDY is
|
use the ``--frontend-no-tls`` option. If that option is used, SPDY is
|
||||||
disabled in the frontend and incoming HTTP/1.1 connection can be
|
disabled in the frontend and incoming HTTP/1.1 connections can be
|
||||||
upgraded to HTTP/2 through HTTP Upgrade.
|
upgraded to HTTP/2 through HTTP Upgrade.
|
||||||
|
|
||||||
The ``--http2-bridge``, ``--client`` and ``--client-proxy`` modes use
|
The ``--http2-bridge``, ``--client`` and ``--client-proxy`` modes use
|
||||||
SSL/TLS in the backend connection by deafult. To disable SSL/TLS, use
|
SSL/TLS in the backend connection by deafult. To disable SSL/TLS, use
|
||||||
``--backend-no-tls`` option.
|
the ``--backend-no-tls`` option.
|
||||||
|
|
||||||
``nghttpx`` supports configuration file. See ``--conf`` option and
|
``nghttpx`` supports a configuration file. See the ``--conf`` option and
|
||||||
sample configuration file ``nghttpx.conf.sample``.
|
sample configuration file ``nghttpx.conf.sample``.
|
||||||
|
|
||||||
In the default mode, (without any of ``--http2-proxy``,
|
In the default mode, (without any of ``--http2-proxy``,
|
||||||
@@ -468,18 +503,18 @@ In the default mode, (without any of ``--http2-proxy``,
|
|||||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Web Server
|
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Web Server
|
||||||
[reverse proxy]
|
[reverse proxy]
|
||||||
|
|
||||||
With ``--http2-proxy`` option, it works as so called secure proxy (aka
|
With the ``--http2-proxy`` option, it works as a so called secure proxy (aka
|
||||||
SPDY proxy)::
|
SPDY proxy)::
|
||||||
|
|
||||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
|
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
|
||||||
[secure proxy] (e.g., Squid, ATS)
|
[secure proxy] (e.g., Squid, ATS)
|
||||||
|
|
||||||
The ``Client`` in the above needs to be configured to use
|
The ``Client`` in the above example needs to be configured to use
|
||||||
``nghttpx`` as secure proxy.
|
``nghttpx`` as secure proxy.
|
||||||
|
|
||||||
At the time of this writing, Chrome is the only browser which supports
|
At the time of this writing, Chrome is the only browser which supports
|
||||||
secure proxy. The one way to configure Chrome to use secure proxy is
|
secure proxy. One way to configure Chrome to use a secure proxy is
|
||||||
create proxy.pac script like this:
|
to create a proxy.pac script like this:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
@@ -488,7 +523,7 @@ create proxy.pac script like this:
|
|||||||
}
|
}
|
||||||
|
|
||||||
``SERVERADDR`` and ``PORT`` is the hostname/address and port of the
|
``SERVERADDR`` and ``PORT`` is the hostname/address and port of the
|
||||||
machine nghttpx is running. Please note that Chrome requires valid
|
machine nghttpx is running on. Please note that Chrome requires a valid
|
||||||
certificate for secure proxy.
|
certificate for secure proxy.
|
||||||
|
|
||||||
Then run Chrome with the following arguments::
|
Then run Chrome with the following arguments::
|
||||||
@@ -496,24 +531,24 @@ Then run Chrome with the following arguments::
|
|||||||
$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
|
$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
|
||||||
|
|
||||||
With ``--http2-bridge``, it accepts HTTP/2, SPDY and HTTP/1.1
|
With ``--http2-bridge``, it accepts HTTP/2, SPDY and HTTP/1.1
|
||||||
connections and communicates with backend in HTTP/2::
|
connections and communicates with the backend in HTTP/2::
|
||||||
|
|
||||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> Web or HTTP/2 Proxy etc
|
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> Web or HTTP/2 Proxy etc
|
||||||
(e.g., nghttpx -s)
|
(e.g., nghttpx -s)
|
||||||
|
|
||||||
With ``--client-proxy`` option, it works as forward proxy and expects
|
With ``--client-proxy``, it works as a forward proxy and expects
|
||||||
that the backend is HTTP/2 proxy::
|
that the backend is an HTTP/2 proxy::
|
||||||
|
|
||||||
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> HTTP/2 Proxy
|
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> HTTP/2 Proxy
|
||||||
[forward proxy] (e.g., nghttpx -s)
|
[forward proxy] (e.g., nghttpx -s)
|
||||||
|
|
||||||
The ``Client`` needs to be configured to use nghttpx as forward
|
The ``Client`` needs to be configured to use nghttpx as a forward
|
||||||
proxy. The frontend HTTP/1.1 connection can be upgraded to HTTP/2
|
proxy. The frontend HTTP/1.1 connection can be upgraded to HTTP/2
|
||||||
through HTTP Upgrade. With the above configuration, one can use
|
through HTTP Upgrade. With the above configuration, one can use
|
||||||
HTTP/1.1 client to access and test their HTTP/2 servers.
|
HTTP/1.1 client to access and test their HTTP/2 servers.
|
||||||
|
|
||||||
With ``--client`` option, it works as reverse proxy and expects that
|
With ``--client``, it works as a reverse proxy and expects that
|
||||||
the backend is HTTP/2 Web server::
|
the backend is an HTTP/2 Web server::
|
||||||
|
|
||||||
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> Web Server
|
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> Web Server
|
||||||
[reverse proxy]
|
[reverse proxy]
|
||||||
@@ -522,11 +557,11 @@ The frontend HTTP/1.1 connection can be upgraded to HTTP/2
|
|||||||
through HTTP Upgrade.
|
through HTTP Upgrade.
|
||||||
|
|
||||||
For the operation modes which talk to the backend in HTTP/2 over
|
For the operation modes which talk to the backend in HTTP/2 over
|
||||||
SSL/TLS, the backend connections can be tunneled through HTTP proxy.
|
SSL/TLS, the backend connections can be tunneled through an HTTP proxy.
|
||||||
The proxy is specified using ``--backend-http-proxy-uri`` option. The
|
The proxy is specified using ``--backend-http-proxy-uri``. The
|
||||||
following figure illustrates the example of ``--http2-bridge`` and
|
following figure illustrates the example of the ``--http2-bridge`` and
|
||||||
``--backend-http-proxy-uri`` options to talk to the outside HTTP/2
|
``--backend-http-proxy-uri`` options to talk to the outside HTTP/2
|
||||||
proxy through HTTP proxy::
|
proxy through an HTTP proxy::
|
||||||
|
|
||||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
|
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
|
||||||
|
|
||||||
@@ -537,7 +572,7 @@ Benchmarking tool
|
|||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The ``h2load`` program is a benchmarking tool for HTTP/2 and SPDY.
|
The ``h2load`` program is a benchmarking tool for HTTP/2 and SPDY.
|
||||||
The SPDY support is enabled if the program was built with spdylay
|
The SPDY support is enabled if the program was built with the spdylay
|
||||||
library. The UI of ``h2load`` is heavily inspired by ``weighttp``
|
library. The UI of ``h2load`` is heavily inspired by ``weighttp``
|
||||||
(https://github.com/lighttpd/weighttp). The typical usage is as
|
(https://github.com/lighttpd/weighttp). The typical usage is as
|
||||||
follows::
|
follows::
|
||||||
@@ -565,38 +600,38 @@ follows::
|
|||||||
min max mean sd +/- sd
|
min max mean sd +/- sd
|
||||||
time for request: 283.86ms 1.46s 659.70ms 150.87ms 84.68%
|
time for request: 283.86ms 1.46s 659.70ms 150.87ms 84.68%
|
||||||
|
|
||||||
The above example issued total 100000 requests, using 100 concurrent
|
The above example issued total 100,000 requests, using 100 concurrent
|
||||||
clients (in other words, 100 HTTP/2 sessions), and maximum 100 streams
|
clients (in other words, 100 HTTP/2 sessions), and a maximum of 100 streams
|
||||||
per client. With ``-t`` option, ``h2load`` will use multiple native
|
per client. With the ``-t`` option, ``h2load`` will use multiple native
|
||||||
threads to avoid saturating single core on client side.
|
threads to avoid saturating a single core on client side.
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
**Don't use this tool against publicly available servers.** That is
|
**Don't use this tool against publicly available servers.** That is
|
||||||
considered a DOS attack. Please only use against your private
|
considered a DOS attack. Please only use it against your private
|
||||||
servers.
|
servers.
|
||||||
|
|
||||||
HPACK tools
|
HPACK tools
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
The ``src`` directory contains HPACK tools. The ``deflatehd`` is a
|
The ``src`` directory contains the HPACK tools. The ``deflatehd`` program is a
|
||||||
command-line header compression tool. The ``inflatehd`` is
|
command-line header compression tool. The ``inflatehd`` program is a
|
||||||
command-line header decompression tool. Both tools read input from
|
command-line header decompression tool. Both tools read input from
|
||||||
stdin and write output to stdout. The errors are written to stderr.
|
stdin and write output to stdout. Errors are written to stderr.
|
||||||
They take JSON as input and output. We use (mostly) same JSON data
|
They take JSON as input and output. We (mostly) use the same JSON data
|
||||||
format described at https://github.com/http2jp/hpack-test-case
|
format described at https://github.com/http2jp/hpack-test-case.
|
||||||
|
|
||||||
deflatehd - header compressor
|
deflatehd - header compressor
|
||||||
+++++++++++++++++++++++++++++
|
+++++++++++++++++++++++++++++
|
||||||
|
|
||||||
The ``deflatehd`` reads JSON data or HTTP/1-style header fields from
|
The ``deflatehd`` program reads JSON data or HTTP/1-style header fields from
|
||||||
stdin and outputs compressed header block in JSON.
|
stdin and outputs compressed header block in JSON.
|
||||||
|
|
||||||
For the JSON input, the root JSON object must include ``cases`` key.
|
For the JSON input, the root JSON object must include a ``cases`` key.
|
||||||
Its value has to include the sequence of input header set. They share
|
Its value has to include the sequence of input header set. They share
|
||||||
the same compression context and are processed in the order they
|
the same compression context and are processed in the order they
|
||||||
appear. Each item in the sequence is a JSON object and it must
|
appear. Each item in the sequence is a JSON object and it must
|
||||||
include ``headers`` key. Its value is an array of a JSON object,
|
include a ``headers`` key. Its value is an array of JSON objects,
|
||||||
which includes exactly one name/value pair.
|
which includes exactly one name/value pair.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@@ -622,8 +657,8 @@ Example:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
With ``-t`` option, the program can accept more familiar HTTP/1 style
|
With the ``-t`` option, the program can accept more familiar HTTP/1 style
|
||||||
header field block. Each header set is delimited by empty line:
|
header field blocks. Each header set is delimited by an empty line:
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
@@ -634,29 +669,29 @@ Example::
|
|||||||
:method: POST
|
:method: POST
|
||||||
user-agent: nghttp2
|
user-agent: nghttp2
|
||||||
|
|
||||||
The output is JSON object. It should include ``cases`` key and its
|
The output is in JSON object. It should include a ``cases`` key and its
|
||||||
value is an array of JSON object, which has at least following keys:
|
value is an array of JSON objects, which has at least the following keys:
|
||||||
|
|
||||||
seq
|
seq
|
||||||
The index of header set in the input.
|
The index of header set in the input.
|
||||||
|
|
||||||
input_length
|
input_length
|
||||||
The sum of length of name/value pair in the input.
|
The sum of the length of the name/value pairs in the input.
|
||||||
|
|
||||||
output_length
|
output_length
|
||||||
The length of compressed header block.
|
The length of the compressed header block.
|
||||||
|
|
||||||
percentage_of_original_size
|
percentage_of_original_size
|
||||||
``input_length`` / ``output_length`` * 100
|
``input_length`` / ``output_length`` * 100
|
||||||
|
|
||||||
wire
|
wire
|
||||||
The compressed header block in hex string.
|
The compressed header block as a hex string.
|
||||||
|
|
||||||
headers
|
headers
|
||||||
The input header set.
|
The input header set.
|
||||||
|
|
||||||
header_table_size
|
header_table_size
|
||||||
The header table size adjusted before deflating header set.
|
The header table size adjusted before deflating the header set.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
@@ -723,7 +758,7 @@ Examples:
|
|||||||
The output can be used as the input for ``inflatehd`` and
|
The output can be used as the input for ``inflatehd`` and
|
||||||
``deflatehd``.
|
``deflatehd``.
|
||||||
|
|
||||||
With ``-d`` option, the extra ``header_table`` key is added and its
|
With the ``-d`` option, the extra ``header_table`` key is added and its
|
||||||
associated value includes the state of dynamic header table after the
|
associated value includes the state of dynamic header table after the
|
||||||
corresponding header set was processed. The value includes at least
|
corresponding header set was processed. The value includes at least
|
||||||
the following keys:
|
the following keys:
|
||||||
@@ -747,8 +782,8 @@ deflate_size
|
|||||||
``max_deflate_size``.
|
``max_deflate_size``.
|
||||||
|
|
||||||
max_deflate_size
|
max_deflate_size
|
||||||
The maximum header table size encoder uses. This can be smaller
|
The maximum header table size the encoder uses. This can be smaller
|
||||||
than ``max_size``. In this case, encoder only uses up to first
|
than ``max_size``. In this case, the encoder only uses up to first
|
||||||
``max_deflate_size`` buffer. Since the header table size is still
|
``max_deflate_size`` buffer. Since the header table size is still
|
||||||
``max_size``, the encoder has to keep track of entries ouside the
|
``max_size``, the encoder has to keep track of entries ouside the
|
||||||
``max_deflate_size`` but inside the ``max_size`` and make sure
|
``max_deflate_size`` but inside the ``max_size`` and make sure
|
||||||
@@ -911,14 +946,14 @@ Example:
|
|||||||
inflatehd - header decompressor
|
inflatehd - header decompressor
|
||||||
+++++++++++++++++++++++++++++++
|
+++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
The ``inflatehd`` reads JSON data from stdin and outputs decompressed
|
The ``inflatehd`` program reads JSON data from stdin and outputs decompressed
|
||||||
name/value pairs in JSON.
|
name/value pairs in JSON.
|
||||||
|
|
||||||
The root JSON object must include ``cases`` key. Its value has to
|
The root JSON object must include the ``cases`` key. Its value has to
|
||||||
include the sequence of compressed header block. They share the same
|
include the sequence of compressed header blocks. They share the same
|
||||||
compression context and are processed in the order they appear. Each
|
compression context and are processed in the order they appear. Each
|
||||||
item in the sequence is a JSON object and it must have at least
|
item in the sequence is a JSON object and it must have at least a
|
||||||
``wire`` key. Its value is a compressed header block in hex string.
|
``wire`` key. Its value is a compressed header block as a hex string.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -932,17 +967,17 @@ Example:
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
The output is JSON object. It should include ``cases`` key and its
|
The output is a JSON object. It should include a ``cases`` key and its
|
||||||
value is an array of JSON object, which has at least following keys:
|
value is an array of JSON objects, which has at least following keys:
|
||||||
|
|
||||||
seq
|
seq
|
||||||
The index of header set in the input.
|
The index of the header set in the input.
|
||||||
|
|
||||||
headers
|
headers
|
||||||
The JSON array includes decompressed name/value pairs.
|
A JSON array that includes decompressed name/value pairs.
|
||||||
|
|
||||||
wire
|
wire
|
||||||
The compressed header block in hex string.
|
The compressed header block as a hex string.
|
||||||
|
|
||||||
header_table_size
|
header_table_size
|
||||||
The header table size adjusted before inflating compressed header
|
The header table size adjusted before inflating compressed header
|
||||||
@@ -1006,8 +1041,8 @@ Example:
|
|||||||
The output can be used as the input for ``deflatehd`` and
|
The output can be used as the input for ``deflatehd`` and
|
||||||
``inflatehd``.
|
``inflatehd``.
|
||||||
|
|
||||||
With ``-d`` option, the extra ``header_table`` key is added and its
|
With the ``-d`` option, the extra ``header_table`` key is added and its
|
||||||
associated value includes the state of dynamic header table after the
|
associated value includes the state of the dynamic header table after the
|
||||||
corresponding header set was processed. The format is the same as
|
corresponding header set was processed. The format is the same as
|
||||||
``deflatehd``.
|
``deflatehd``.
|
||||||
|
|
||||||
@@ -1016,10 +1051,10 @@ libnghttp2_asio: High level HTTP/2 C++ library
|
|||||||
|
|
||||||
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
|
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
|
||||||
high level abstraction API to build HTTP/2 applications. It depends
|
high level abstraction API to build HTTP/2 applications. It depends
|
||||||
on Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
|
on the Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
|
||||||
provides client and server API.
|
provides both client and server APIs.
|
||||||
|
|
||||||
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
|
libnghttp2_asio is not built by default. Use the ``--enable-asio-lib``
|
||||||
configure flag to build libnghttp2_asio. The required Boost libraries
|
configure flag to build libnghttp2_asio. The required Boost libraries
|
||||||
are:
|
are:
|
||||||
|
|
||||||
@@ -1027,9 +1062,9 @@ are:
|
|||||||
* Boost::System
|
* Boost::System
|
||||||
* Boost::Thread
|
* Boost::Thread
|
||||||
|
|
||||||
Server API is designed to build HTTP/2 server very easily to utilize
|
The server API is designed to build an HTTP/2 server very easily to utilize
|
||||||
C++11 anonymous function and closure. The bare minimum example of
|
C++11 anonymous functions and closures. The bare minimum example of
|
||||||
HTTP/2 server looks like this:
|
an HTTP/2 server looks like this:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
@@ -1052,7 +1087,7 @@ HTTP/2 server looks like this:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Here is the sample code for client API use:
|
Here is sample code to use the client API:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
@@ -1109,19 +1144,19 @@ For more details, see the documentation of libnghttp2_asio.
|
|||||||
Python bindings
|
Python bindings
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
This ``python`` directory contains nghttp2 Python bindings. The
|
The ``python`` directory contains nghttp2 Python bindings. The
|
||||||
bindings currently provide HPACK compressor and decompressor classes
|
bindings currently provide HPACK compressor and decompressor classes
|
||||||
and HTTP/2 server.
|
and an HTTP/2 server.
|
||||||
|
|
||||||
The extension module is called ``nghttp2``.
|
The extension module is called ``nghttp2``.
|
||||||
|
|
||||||
``make`` will build the bindings and target Python version is
|
``make`` will build the bindings and target Python version is
|
||||||
determined by configure script. If the detected Python version is not
|
determined by the ``configure`` script. If the detected Python version is not
|
||||||
what you expect, specify a path to Python executable in ``PYTHON``
|
what you expect, specify a path to Python executable in a ``PYTHON``
|
||||||
variable as an argument to configure script (e.g., ``./configure
|
variable as an argument to configure script (e.g., ``./configure
|
||||||
PYTHON=/usr/bin/python3.4``).
|
PYTHON=/usr/bin/python3.4``).
|
||||||
|
|
||||||
The following example code illustrates basic usage of HPACK compressor
|
The following example code illustrates basic usage of the HPACK compressor
|
||||||
and decompressor in Python:
|
and decompressor in Python:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -1148,21 +1183,21 @@ By default, it does nothing. It must be subclassed to handle each
|
|||||||
event callback method.
|
event callback method.
|
||||||
|
|
||||||
The first callback method invoked is ``on_headers()``. It is called
|
The first callback method invoked is ``on_headers()``. It is called
|
||||||
when HEADERS frame, which includes request header fields, has arrived.
|
when HEADERS frame, which includes the request header fields, has arrived.
|
||||||
|
|
||||||
If request has request body, ``on_data(data)`` is invoked for each
|
If the request has a request body, ``on_data(data)`` is invoked for each
|
||||||
chunk of received data.
|
chunk of received data.
|
||||||
|
|
||||||
When whole request is received, ``on_request_done()`` is invoked.
|
Once the entire request is received, ``on_request_done()`` is invoked.
|
||||||
|
|
||||||
When stream is closed, ``on_close(error_code)`` is called.
|
When the stream is closed, ``on_close(error_code)`` is called.
|
||||||
|
|
||||||
The application can send response using ``send_response()`` method.
|
The application can send a response using ``send_response()`` method.
|
||||||
It can be used in ``on_headers()``, ``on_data()`` or
|
It can be used in ``on_headers()``, ``on_data()`` or
|
||||||
``on_request_done()``.
|
``on_request_done()``.
|
||||||
|
|
||||||
The application can push resource using ``push()`` method. It must be
|
The application can push resources using the ``push()`` method. It must be
|
||||||
used before ``send_response()`` call.
|
used before the ``send_response()`` call.
|
||||||
|
|
||||||
The following instance variables are available:
|
The following instance variables are available:
|
||||||
|
|
||||||
@@ -1232,14 +1267,15 @@ When contributing with code, you agree to put your changes and new
|
|||||||
code under the same license nghttp2 is already using unless stated and
|
code under the same license nghttp2 is already using unless stated and
|
||||||
agreed otherwise.
|
agreed otherwise.
|
||||||
|
|
||||||
When changing existing source code, you do not alter the copyright of
|
When changing existing source code, do not alter the copyright of
|
||||||
the original file(s). The copyright will still be owned by the
|
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 creator(s) or those who have been assigned copyright by the
|
||||||
original author(s).
|
original author(s).
|
||||||
|
|
||||||
By submitting a patch to the nghttp2 project, you are assumed to have
|
By submitting a patch to the nghttp2 project, you (or your employer, as
|
||||||
the right to the code and to be allowed by your employer or whatever
|
the case may be) agree to assign the copyright of your submission to us.
|
||||||
to hand over that patch/code to us. We will credit you for your
|
.. the above really needs to be reworded to pass legal muster.
|
||||||
|
We will credit you for your
|
||||||
changes as far as possible, to give credit but also to keep a trace
|
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
|
back to who made what changes. Please always provide us with your
|
||||||
full real name when contributing!
|
full real name when contributing!
|
||||||
|
|||||||
@@ -42,6 +42,6 @@ PATH=$TOOLCHAIN/bin:$PATH
|
|||||||
--enable-werror \
|
--enable-werror \
|
||||||
CC=clang \
|
CC=clang \
|
||||||
CXX=clang++ \
|
CXX=clang++ \
|
||||||
CPPFLAGS="-I$PREFIX/include" \
|
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||||
LDFLAGS="-L$PREFIX/lib"
|
LDFLAGS="-fPIE -pie -L$PREFIX/lib"
|
||||||
|
|||||||
22
configure.ac
22
configure.ac
@@ -25,14 +25,14 @@ dnl Do not change user variables!
|
|||||||
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
||||||
|
|
||||||
AC_PREREQ(2.61)
|
AC_PREREQ(2.61)
|
||||||
AC_INIT([nghttp2], [0.7.6], [t-tujikawa@users.sourceforge.net])
|
AC_INIT([nghttp2], [0.7.14], [t-tujikawa@users.sourceforge.net])
|
||||||
LT_PREREQ([2.2.6])
|
LT_PREREQ([2.2.6])
|
||||||
LT_INIT()
|
LT_INIT()
|
||||||
dnl See versioning rule:
|
dnl See versioning rule:
|
||||||
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||||
AC_SUBST(LT_CURRENT, 12)
|
AC_SUBST(LT_CURRENT, 13)
|
||||||
AC_SUBST(LT_REVISION, 0)
|
AC_SUBST(LT_REVISION, 3)
|
||||||
AC_SUBST(LT_AGE, 7)
|
AC_SUBST(LT_AGE, 8)
|
||||||
|
|
||||||
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
|
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"`
|
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
|
||||||
@@ -508,13 +508,6 @@ AC_CHECK_HEADERS([ \
|
|||||||
unistd.h \
|
unistd.h \
|
||||||
])
|
])
|
||||||
|
|
||||||
case "${host}" in
|
|
||||||
*mingw*)
|
|
||||||
# For ntohl, ntohs in Windows
|
|
||||||
AC_CHECK_HEADERS([winsock2.h])
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_TYPE_SIZE_T
|
AC_TYPE_SIZE_T
|
||||||
AC_TYPE_SSIZE_T
|
AC_TYPE_SSIZE_T
|
||||||
@@ -564,13 +557,6 @@ AM_CONDITIONAL([ENABLE_TINY_NGHTTPD],
|
|||||||
[ test "x${have_epoll}" = "xyes" &&
|
[ test "x${have_epoll}" = "xyes" &&
|
||||||
test "x${have_timerfd_create}" = "xyes"])
|
test "x${have_timerfd_create}" = "xyes"])
|
||||||
|
|
||||||
dnl Windows library for winsock2
|
|
||||||
case "${host}" in
|
|
||||||
*mingw*)
|
|
||||||
LIBS="$LIBS -lws2_32"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
ac_save_CFLAGS=$CFLAGS
|
ac_save_CFLAGS=$CFLAGS
|
||||||
CFLAGS=
|
CFLAGS=
|
||||||
|
|
||||||
|
|||||||
2
contrib/.gitignore
vendored
2
contrib/.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
nghttpx-init
|
nghttpx-init
|
||||||
|
nghttpx.service
|
||||||
|
nghttpx-upstart.conf
|
||||||
|
|||||||
@@ -21,19 +21,24 @@
|
|||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
EXTRA_DIST = nghttpx-init.in nghttpx-logrotate
|
configfiles = nghttpx-init nghttpx.service nghttpx-upstart.conf
|
||||||
|
|
||||||
|
EXTRA_DIST = $(configfiles:%=%.in) nghttpx-logrotate
|
||||||
|
|
||||||
edit = sed -e 's|@bindir[@]|$(bindir)|g'
|
edit = sed -e 's|@bindir[@]|$(bindir)|g'
|
||||||
|
|
||||||
nghttpx-init: Makefile
|
nghttpx-init: %: $(srcdir)/%.in
|
||||||
rm -f $@ $@.tmp
|
rm -f $@ $@.tmp
|
||||||
$(edit) $(srcdir)/$@.in > $@.tmp
|
$(edit) $< > $@.tmp
|
||||||
chmod +x $@.tmp
|
chmod +x $@.tmp
|
||||||
mv $@.tmp $@
|
mv $@.tmp $@
|
||||||
|
|
||||||
nghttpx-init: $(srcdir)/nghttpx-init.in
|
nghttpx.service nghttpx-upstart.conf: %: $(srcdir)/%.in
|
||||||
|
$(edit) $< > $@
|
||||||
|
|
||||||
all-local: nghttpx-init
|
$(configfiles): Makefile
|
||||||
|
|
||||||
|
all-local: $(configfiles)
|
||||||
|
|
||||||
clean-local:
|
clean-local:
|
||||||
-rm -f nghttpx-init nghttpx-init.tmp
|
-rm -f nghttpx-init.tmp $(configfiles)
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
/var/log/nghttpx/*.log {
|
/var/log/nghttpx/*.log {
|
||||||
weekly
|
weekly
|
||||||
missingok
|
|
||||||
rotate 52
|
rotate 52
|
||||||
|
missingok
|
||||||
compress
|
compress
|
||||||
delaycompress
|
delaycompress
|
||||||
notifempty
|
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
|
postrotate
|
||||||
[ -s /run/nghttpx.pid ] && kill -USR1 `cat /run/nghttpx.pid`
|
killall -USR1 nghttpx 2> /dev/null || true
|
||||||
endscript
|
endscript
|
||||||
}
|
}
|
||||||
|
|||||||
8
contrib/nghttpx-upstart.conf.in
Normal file
8
contrib/nghttpx-upstart.conf.in
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# vim: ft=upstart:
|
||||||
|
|
||||||
|
description "HTTP/2 reverse proxy"
|
||||||
|
|
||||||
|
start on runlevel [2]
|
||||||
|
stop on runlevel [016]
|
||||||
|
|
||||||
|
exec @bindir@/nghttpx
|
||||||
10
contrib/nghttpx.service.in
Normal file
10
contrib/nghttpx.service.in
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=HTTP/2 experimental proxy
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=@bindir@/nghttpx --errorlog-syslog
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
23
doc/.gitignore
vendored
23
doc/.gitignore
vendored
@@ -1,3 +1,24 @@
|
|||||||
|
# generated files
|
||||||
apiref.rst
|
apiref.rst
|
||||||
|
asio_http2.h.rst
|
||||||
|
asio_http2_client.h.rst
|
||||||
|
asio_http2_server.h.rst
|
||||||
|
building-android-binary.rst
|
||||||
conf.py
|
conf.py
|
||||||
manual
|
contribute.rst
|
||||||
|
enums.rst
|
||||||
|
h2load-howto.rst
|
||||||
|
index.rst
|
||||||
|
libnghttp2_asio.rst
|
||||||
|
macros.rst
|
||||||
|
manual/
|
||||||
|
nghttp2.h.rst
|
||||||
|
nghttp2_*.rst
|
||||||
|
nghttp2ver.h.rst
|
||||||
|
nghttpx-howto.rst
|
||||||
|
package_README.rst
|
||||||
|
python-apiref.rst
|
||||||
|
tutorial-client.rst
|
||||||
|
tutorial-hpack.rst
|
||||||
|
tutorial-server.rst
|
||||||
|
types.rst
|
||||||
|
|||||||
127
doc/Makefile.am
127
doc/Makefile.am
@@ -23,10 +23,112 @@
|
|||||||
|
|
||||||
man_MANS = nghttp.1 nghttpd.1 nghttpx.1 h2load.1
|
man_MANS = nghttp.1 nghttpd.1 nghttpx.1 h2load.1
|
||||||
|
|
||||||
|
APIDOCS= \
|
||||||
|
apiref.rst \
|
||||||
|
macros.rst \
|
||||||
|
enums.rst \
|
||||||
|
types.rst \
|
||||||
|
nghttp2_check_header_name.rst \
|
||||||
|
nghttp2_check_header_value.rst \
|
||||||
|
nghttp2_hd_deflate_bound.rst \
|
||||||
|
nghttp2_hd_deflate_change_table_size.rst \
|
||||||
|
nghttp2_hd_deflate_del.rst \
|
||||||
|
nghttp2_hd_deflate_hd.rst \
|
||||||
|
nghttp2_hd_deflate_new.rst \
|
||||||
|
nghttp2_hd_deflate_new2.rst \
|
||||||
|
nghttp2_hd_inflate_change_table_size.rst \
|
||||||
|
nghttp2_hd_inflate_del.rst \
|
||||||
|
nghttp2_hd_inflate_end_headers.rst \
|
||||||
|
nghttp2_hd_inflate_hd.rst \
|
||||||
|
nghttp2_hd_inflate_new.rst \
|
||||||
|
nghttp2_hd_inflate_new2.rst \
|
||||||
|
nghttp2_is_fatal.rst \
|
||||||
|
nghttp2_nv_compare_name.rst \
|
||||||
|
nghttp2_option_del.rst \
|
||||||
|
nghttp2_option_new.rst \
|
||||||
|
nghttp2_option_set_no_auto_window_update.rst \
|
||||||
|
nghttp2_option_set_no_http_messaging.rst \
|
||||||
|
nghttp2_option_set_peer_max_concurrent_streams.rst \
|
||||||
|
nghttp2_option_set_recv_client_preface.rst \
|
||||||
|
nghttp2_pack_settings_payload.rst \
|
||||||
|
nghttp2_priority_spec_check_default.rst \
|
||||||
|
nghttp2_priority_spec_default_init.rst \
|
||||||
|
nghttp2_priority_spec_init.rst \
|
||||||
|
nghttp2_select_next_protocol.rst \
|
||||||
|
nghttp2_session_callbacks_del.rst \
|
||||||
|
nghttp2_session_callbacks_new.rst \
|
||||||
|
nghttp2_session_callbacks_set_before_frame_send_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_data_source_read_length_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_on_begin_frame_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_on_begin_headers_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_on_frame_not_send_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_on_frame_recv_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_on_frame_send_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_on_header_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_on_stream_close_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_recv_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_select_padding_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_send_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_send_data_callback.rst \
|
||||||
|
nghttp2_session_client_new.rst \
|
||||||
|
nghttp2_session_client_new2.rst \
|
||||||
|
nghttp2_session_client_new3.rst \
|
||||||
|
nghttp2_session_consume.rst \
|
||||||
|
nghttp2_session_consume_connection.rst \
|
||||||
|
nghttp2_session_consume_stream.rst \
|
||||||
|
nghttp2_session_del.rst \
|
||||||
|
nghttp2_session_get_effective_local_window_size.rst \
|
||||||
|
nghttp2_session_get_effective_recv_data_length.rst \
|
||||||
|
nghttp2_session_get_last_proc_stream_id.rst \
|
||||||
|
nghttp2_session_get_next_stream_id.rst \
|
||||||
|
nghttp2_session_get_outbound_queue_size.rst \
|
||||||
|
nghttp2_session_get_remote_settings.rst \
|
||||||
|
nghttp2_session_get_remote_window_size.rst \
|
||||||
|
nghttp2_session_get_stream_effective_local_window_size.rst \
|
||||||
|
nghttp2_session_get_stream_effective_recv_data_length.rst \
|
||||||
|
nghttp2_session_get_stream_local_close.rst \
|
||||||
|
nghttp2_session_get_stream_remote_close.rst \
|
||||||
|
nghttp2_session_get_stream_remote_window_size.rst \
|
||||||
|
nghttp2_session_get_stream_user_data.rst \
|
||||||
|
nghttp2_session_mem_recv.rst \
|
||||||
|
nghttp2_session_mem_send.rst \
|
||||||
|
nghttp2_session_recv.rst \
|
||||||
|
nghttp2_session_resume_data.rst \
|
||||||
|
nghttp2_session_send.rst \
|
||||||
|
nghttp2_session_server_new.rst \
|
||||||
|
nghttp2_session_server_new2.rst \
|
||||||
|
nghttp2_session_server_new3.rst \
|
||||||
|
nghttp2_session_set_next_stream_id.rst \
|
||||||
|
nghttp2_session_set_stream_user_data.rst \
|
||||||
|
nghttp2_session_terminate_session.rst \
|
||||||
|
nghttp2_session_terminate_session2.rst \
|
||||||
|
nghttp2_session_upgrade.rst \
|
||||||
|
nghttp2_session_want_read.rst \
|
||||||
|
nghttp2_session_want_write.rst \
|
||||||
|
nghttp2_strerror.rst \
|
||||||
|
nghttp2_submit_altsvc.rst \
|
||||||
|
nghttp2_submit_data.rst \
|
||||||
|
nghttp2_submit_goaway.rst \
|
||||||
|
nghttp2_submit_headers.rst \
|
||||||
|
nghttp2_submit_ping.rst \
|
||||||
|
nghttp2_submit_priority.rst \
|
||||||
|
nghttp2_submit_push_promise.rst \
|
||||||
|
nghttp2_submit_request.rst \
|
||||||
|
nghttp2_submit_response.rst \
|
||||||
|
nghttp2_submit_rst_stream.rst \
|
||||||
|
nghttp2_submit_settings.rst \
|
||||||
|
nghttp2_submit_shutdown_notice.rst \
|
||||||
|
nghttp2_submit_trailer.rst \
|
||||||
|
nghttp2_submit_window_update.rst \
|
||||||
|
nghttp2_version.rst
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
mkapiref.py \
|
mkapiref.py \
|
||||||
README.rst \
|
README.rst \
|
||||||
apiref-header.rst \
|
programmers-guide.rst \
|
||||||
|
$(APIDOCS) \
|
||||||
nghttp.1.rst \
|
nghttp.1.rst \
|
||||||
nghttpd.1.rst \
|
nghttpd.1.rst \
|
||||||
nghttpx.1.rst \
|
nghttpx.1.rst \
|
||||||
@@ -99,13 +201,30 @@ help:
|
|||||||
@echo " linkcheck to check all external links for integrity"
|
@echo " linkcheck to check all external links for integrity"
|
||||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||||
|
|
||||||
apiref.rst: $(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
|
apiref.rst macros.rst enums.rst types.rst: \
|
||||||
|
$(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
|
||||||
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
|
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
|
||||||
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
|
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
|
||||||
--header $(top_srcdir)/doc/apiref-header.rst $^ > $@
|
$@ macros.rst enums.rst types.rst . $^
|
||||||
|
|
||||||
|
# Inspired by
|
||||||
|
# http://www.gnu.org/savannah-checkouts/gnu/automake/manual/html_node/Multiple-Outputs.html
|
||||||
|
apidoc.stamp: $(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
|
||||||
|
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
|
||||||
|
@rm -f apidoc.tmp
|
||||||
|
@touch apidoc.tmp
|
||||||
|
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
|
||||||
|
$@ macros.rst enums.rst types.rst . $^
|
||||||
|
@mv -f apidoc.tmp $@
|
||||||
|
$(APIDOC): apidoc.stamp
|
||||||
|
## Recover from the removal of $@
|
||||||
|
@if test -f $@; then :; else \
|
||||||
|
rm -f apidoc.stamp; \
|
||||||
|
$(MAKE) $(AM_MAKEFLAGS) apidoc.stamp; \
|
||||||
|
fi
|
||||||
|
|
||||||
clean-local:
|
clean-local:
|
||||||
-rm apiref.rst
|
-rm $(APIDOCS)
|
||||||
-rm -rf $(BUILDDIR)/*
|
-rm -rf $(BUILDDIR)/*
|
||||||
|
|
||||||
html-local: apiref.rst
|
html-local: apiref.rst
|
||||||
|
|||||||
2
doc/_themes/sphinx_rtd_theme/__init__.py
vendored
2
doc/_themes/sphinx_rtd_theme/__init__.py
vendored
@@ -5,7 +5,7 @@ From https://github.com/ryan-roemer/sphinx-bootstrap-theme.
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
VERSION = (0, 1, 5)
|
VERSION = (0, 1, 8)
|
||||||
|
|
||||||
__version__ = ".".join(str(v) for v in VERSION)
|
__version__ = ".".join(str(v) for v in VERSION)
|
||||||
__version_full__ = __version__
|
__version_full__ = __version__
|
||||||
|
|||||||
@@ -6,13 +6,17 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
<li>{{ title }}</li>
|
<li>{{ title }}</li>
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
{% if pagename != "search" %}
|
||||||
{% if display_github %}
|
{% if display_github %}
|
||||||
<a href="https://github.com/{{ github_user }}/{{ github_repo }}/blob/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-github"> Edit on GitHub</a>
|
<a href="https://{{ github_host|default("github.com") }}/{{ github_user }}/{{ github_repo }}/blob/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-github"> Edit on GitHub</a>
|
||||||
{% elif display_bitbucket %}
|
{% elif display_bitbucket %}
|
||||||
<a href="https://bitbucket.org/{{ bitbucket_user }}/{{ bitbucket_repo }}/src/{{ bitbucket_version}}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-bitbucket"> Edit on Bitbucket</a>
|
<a href="https://bitbucket.org/{{ bitbucket_user }}/{{ bitbucket_repo }}/src/{{ bitbucket_version}}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-bitbucket"> Edit on Bitbucket</a>
|
||||||
|
{% elif show_source and source_url_prefix %}
|
||||||
|
<a href="{{ source_url_prefix }}{{ pagename }}{{ source_suffix }}">View page source</a>
|
||||||
{% elif show_source and has_source and sourcename %}
|
{% elif show_source and has_source and sourcename %}
|
||||||
<a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow"> View page source</a>
|
<a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow"> View page source</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|||||||
7
doc/_themes/sphinx_rtd_theme/footer.html
vendored
7
doc/_themes/sphinx_rtd_theme/footer.html
vendored
@@ -2,10 +2,10 @@
|
|||||||
{% if next or prev %}
|
{% if next or prev %}
|
||||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||||
{% if next %}
|
{% if next %}
|
||||||
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}">Next <span class="fa fa-arrow-circle-right"></span></a>
|
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if prev %}
|
{% if prev %}
|
||||||
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}"><span class="fa fa-arrow-circle-left"></span> Previous</a>
|
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -28,6 +28,9 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{%- if show_sphinx %}
|
||||||
{% trans %}Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}.
|
{% trans %}Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}.
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
27
doc/_themes/sphinx_rtd_theme/layout.html
vendored
27
doc/_themes/sphinx_rtd_theme/layout.html
vendored
@@ -12,6 +12,7 @@
|
|||||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
{{ metatags }}
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
{% block htmltitle %}
|
{% block htmltitle %}
|
||||||
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# CSS #}
|
{# CSS #}
|
||||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic|Roboto+Slab:400,700|Inconsolata:400,700&subset=latin,cyrillic' rel='stylesheet' type='text/css'>
|
|
||||||
|
|
||||||
{# OPENSEARCH #}
|
{# OPENSEARCH #}
|
||||||
{% if not embedded %}
|
{% if not embedded %}
|
||||||
@@ -42,6 +42,10 @@
|
|||||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for cssfile in extra_css_files %}
|
||||||
|
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{%- block linktags %}
|
{%- block linktags %}
|
||||||
{%- if hasdoc('about') %}
|
{%- if hasdoc('about') %}
|
||||||
<link rel="author" title="{{ _('About these documents') }}"
|
<link rel="author" title="{{ _('About these documents') }}"
|
||||||
@@ -71,7 +75,7 @@
|
|||||||
{%- block extrahead %} {% endblock %}
|
{%- block extrahead %} {% endblock %}
|
||||||
|
|
||||||
{# Keep modernizr in head - http://modernizr.com/docs/#installing #}
|
{# Keep modernizr in head - http://modernizr.com/docs/#installing #}
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js"></script>
|
<script src="_static/js/modernizr.min.js"></script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -83,14 +87,27 @@
|
|||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-nav-search">
|
<div class="wy-side-nav-search">
|
||||||
{% block sidebartitle %}
|
{% block sidebartitle %}
|
||||||
<a href="{{ pathto(master_doc) }}" class="fa fa-home"> {{ project }}</a>
|
|
||||||
{% endblock %}
|
{% if logo and theme_logo_only %}
|
||||||
|
<a href="{{ pathto(master_doc) }}">
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ pathto(master_doc) }}" class="icon icon-home"> {{ project }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if logo %}
|
||||||
|
{# Not strictly valid HTML, but it's the only way to display/scale it properly, without weird scripting or heaps of work #}
|
||||||
|
<img src="{{ pathto('_static/' + logo, 1) }}" class="logo" />
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
|
||||||
{% include "searchbox.html" %}
|
{% include "searchbox.html" %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
{% block menu %}
|
{% block menu %}
|
||||||
{% set toctree = toctree(maxdepth=2, collapse=False, includehidden=True) %}
|
{% set toctree = toctree(maxdepth=4, collapse=False, includehidden=True) %}
|
||||||
{% if toctree %}
|
{% if toctree %}
|
||||||
{{ toctree }}
|
{{ toctree }}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
7
doc/_themes/sphinx_rtd_theme/static/css/badge_only.css.map
vendored
Normal file
7
doc/_themes/sphinx_rtd_theme/static/css/badge_only.css.map
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"mappings": "CAyDA,SAAY,EACV,qBAAsB,EAAE,UAAW,EAqDrC,QAAS,EARP,IAAK,EAAE,AAAC,EACR,+BAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,cAAO,EACL,IAAK,EAAE,GAAI,EC1Gb,SAkBC,EAjBC,UAAW,ECFJ,UAAW,EDGlB,UAAW,EAHqC,KAAM,EAItD,SAAU,EAJsD,KAAM,EAapE,EAAG,EAAE,qCAAwB,EAC7B,EAAG,EAAE,0PAAyE,ECZpF,SAAU,EACR,MAAO,EAAE,WAAY,EACrB,UAAW,EAAE,UAAW,EACxB,SAAU,EAAE,KAAM,EAClB,UAAW,EAAE,KAAM,EACnB,UAAW,EAAE,AAAC,EACd,cAAe,EAAE,MAAO,EAG1B,IAAK,EACH,MAAO,EAAE,WAAY,EACrB,cAAe,EAAE,MAAO,EAIxB,KAAG,EACD,MAAO,EAAE,WAAY,EACvB,sCAAiB,EAGf,IAAK,EAAE,MAAY,EAEvB,KAAM,EACJ,cAAe,EAAE,GAAI,EACrB,UAAW,EAAE,EAAG,EAChB,UAAW,EAAE,KAAM,EAEjB,YAAG,EACD,IAAK,EAAE,IAAI,EACb,oDAAiB,EAGf,aAAc,EAAE,OAAQ,EAG9B,cAAe,EACb,MAAO,EAAE,EAAO,EAElB,gBAAiB,EACf,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,sBAAuB,EACrB,MAAO,EAAE,EAAO,EAElB,kBAAmB,EACjB,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,sBAAuB,EACrB,MAAO,EAAE,EAAO,EAElB,qBAAsB,EACpB,MAAO,EAAE,EAAO,EAElB,uBAAwB,EACtB,MAAO,EAAE,EAAO,ECnElB,YAAa,EACX,OAAQ,EAAE,IAAK,EACf,KAAM,EAAE,AAAC,EACT,GAAI,EAAE,AAAC,EACP,IAAK,EC6E+B,IAAK,ED5EzC,IAAK,ECE+B,MAAyB,EDD7D,SAAU,EAAE,MAAkC,EAC9C,SAAU,EAAE,iBAAiC,EAC7C,UAAW,EEAyB,sDAAM,EFC1C,MAAO,EC+E6B,EAAG,ED9EvC,cAAC,EACC,IAAK,ECqE6B,MAAW,EDpE7C,cAAe,EAAE,GAAI,EACvB,6BAAgB,EACd,MAAO,EAAE,GAAI,EACf,iCAAoB,EAClB,MAAO,EAAE,GAAqB,EAC9B,eAAgB,EAAE,MAAkC,EACpD,MAAO,EAAE,IAAK,EACd,SAAU,EAAE,IAAK,EACjB,QAAS,EAAE,EAAG,EACd,KAAM,EAAE,MAAO,EACf,IAAK,ECiD6B,MAAM,EJgC1C,IAAK,EAAE,AAAC,EACR,iFAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,uCAAO,EACL,IAAK,EAAE,GAAI,EGrFX,qCAAG,EACD,IAAK,EClB2B,MAAyB,EDmB3D,0CAAQ,EACN,IAAK,EAAE,GAAI,EACb,4CAAU,EACR,IAAK,EAAE,GAAI,EACb,iDAAiB,EACf,eAAgB,ECQgB,MAAI,EDPpC,IAAK,EC0B2B,GAAM,EDzBxC,wDAAwB,EACtB,eAAgB,ECXgB,MAAO,EDYvC,IAAK,ECzB2B,GAAI,ED0BxC,yCAA8B,EAC5B,MAAO,EAAE,IAAK,EAChB,gCAAmB,EACjB,QAAS,EAAE,EAAG,EACd,MAAO,EAAE,GAAqB,EAC9B,IAAK,ECE6B,GAAwB,EDD1D,MAAO,EAAE,GAAI,EACb,mCAAE,EACA,MAAO,EAAE,IAAK,EACd,KAAM,EAAE,EAAG,EACX,KAAM,EAAE,AAAC,EACT,KAAM,EAAE,KAAM,EACd,MAAO,EAAE,AAAC,EACV,SAAU,EAAE,gBAA6C,EAC3D,mCAAE,EACA,MAAO,EAAE,WAAY,EACrB,KAAM,EAAE,AAAC,EACT,qCAAC,EACC,MAAO,EAAE,WAAY,EACrB,MAAO,EAAE,EAAqB,EAC9B,IAAK,ECjDyB,MAAyB,EDkD7D,sBAAW,EACT,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI,EACZ,IAAK,EAAE,GAAI,EACX,GAAI,EAAE,GAAI,EACV,KAAM,EAAE,GAAI,EACZ,QAAS,ECkByB,IAAK,EDjBvC,iCAAU,EACR,IAAK,EAAE,GAAI,EACb,+BAAQ,EACN,IAAK,EAAE,GAAI,EACb,oDAA+B,EAC7B,SAAU,EAAE,IAAK,EACjB,6DAAQ,EACN,IAAK,EAAE,GAAI,EACb,+DAAU,EACR,IAAK,EAAE,GAAI,EACf,2CAAoB,EAClB,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI,EACZ,UAAW,EAAE,GAAI,EACjB,MAAO,EAAE,IAAuB,EAChC,MAAO,EAAE,IAAK,EACd,SAAU,EAAE,KAAM,EGhDpB,mCAAsB,EHmDxB,YAAa,EACX,IAAK,EAAE,EAAG,EACV,MAAO,EAAE,GAAI,EACb,kBAAO,EACL,MAAO,EAAE,IAAK,EAClB,EAAG,EACD,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI",
|
||||||
|
"sources": ["../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/bourbon/dist/css3/_font-face.scss","../../../sass/_theme_badge_fa.sass","../../../sass/_theme_badge.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss"],
|
||||||
|
"names": [],
|
||||||
|
"file": "badge_only.css"
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
7
doc/_themes/sphinx_rtd_theme/static/css/theme.css.map
vendored
Normal file
7
doc/_themes/sphinx_rtd_theme/static/css/theme.css.map
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Bold.ttf
vendored
Normal file
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Bold.ttf
vendored
Normal file
Binary file not shown.
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/Inconsolata.ttf
vendored
Normal file
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/Inconsolata.ttf
vendored
Normal file
Binary file not shown.
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/Lato-Bold.ttf
vendored
Normal file
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/Lato-Bold.ttf
vendored
Normal file
Binary file not shown.
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/Lato-Regular.ttf
vendored
Normal file
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/Lato-Regular.ttf
vendored
Normal file
Binary file not shown.
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Bold.ttf
vendored
Normal file
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Bold.ttf
vendored
Normal file
Binary file not shown.
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Regular.ttf
vendored
Normal file
BIN
doc/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Regular.ttf
vendored
Normal file
Binary file not shown.
4
doc/_themes/sphinx_rtd_theme/static/js/modernizr.min.js
vendored
Normal file
4
doc/_themes/sphinx_rtd_theme/static/js/modernizr.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
90
doc/_themes/sphinx_rtd_theme/static/js/theme.js
vendored
90
doc/_themes/sphinx_rtd_theme/static/js/theme.js
vendored
@@ -1,44 +1,110 @@
|
|||||||
|
function toggleCurrent (elem) {
|
||||||
|
var parent_li = elem.closest('li');
|
||||||
|
parent_li.siblings('li.current').removeClass('current');
|
||||||
|
parent_li.siblings().find('li.current').removeClass('current');
|
||||||
|
parent_li.find('> ul li.current').removeClass('current');
|
||||||
|
parent_li.toggleClass('current');
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// Shift nav in mobile when clicking the menu.
|
// Shift nav in mobile when clicking the menu.
|
||||||
$(document).on('click', "[data-toggle='wy-nav-top']", function() {
|
$(document).on('click', "[data-toggle='wy-nav-top']", function() {
|
||||||
$("[data-toggle='wy-nav-shift']").toggleClass("shift");
|
$("[data-toggle='wy-nav-shift']").toggleClass("shift");
|
||||||
$("[data-toggle='rst-versions']").toggleClass("shift");
|
$("[data-toggle='rst-versions']").toggleClass("shift");
|
||||||
});
|
});
|
||||||
// Close menu when you click a link.
|
// Nav menu link click operations
|
||||||
$(document).on('click', ".wy-menu-vertical .current ul li a", function() {
|
$(document).on('click', ".wy-menu-vertical .current ul li a", function() {
|
||||||
|
var target = $(this);
|
||||||
|
// Close menu when you click a link.
|
||||||
$("[data-toggle='wy-nav-shift']").removeClass("shift");
|
$("[data-toggle='wy-nav-shift']").removeClass("shift");
|
||||||
$("[data-toggle='rst-versions']").toggleClass("shift");
|
$("[data-toggle='rst-versions']").toggleClass("shift");
|
||||||
|
// Handle dynamic display of l3 and l4 nav lists
|
||||||
|
toggleCurrent(target);
|
||||||
|
if (typeof(window.SphinxRtdTheme) != 'undefined') {
|
||||||
|
window.SphinxRtdTheme.StickyNav.hashChange();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
$(document).on('click', "[data-toggle='rst-current-version']", function() {
|
$(document).on('click', "[data-toggle='rst-current-version']", function() {
|
||||||
$("[data-toggle='rst-versions']").toggleClass("shift-up");
|
$("[data-toggle='rst-versions']").toggleClass("shift-up");
|
||||||
});
|
});
|
||||||
// Make tables responsive
|
// Make tables responsive
|
||||||
$("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>");
|
$("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>");
|
||||||
|
|
||||||
|
// Add expand links to all parents of nested ul
|
||||||
|
$('.wy-menu-vertical ul').siblings('a').each(function () {
|
||||||
|
var link = $(this);
|
||||||
|
expand = $('<span class="toctree-expand"></span>');
|
||||||
|
expand.on('click', function (ev) {
|
||||||
|
toggleCurrent(link);
|
||||||
|
ev.stopPropagation();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
link.prepend(expand);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sphinx theme state
|
||||||
window.SphinxRtdTheme = (function (jquery) {
|
window.SphinxRtdTheme = (function (jquery) {
|
||||||
var stickyNav = (function () {
|
var stickyNav = (function () {
|
||||||
var navBar,
|
var navBar,
|
||||||
win,
|
win,
|
||||||
stickyNavCssClass = 'stickynav',
|
winScroll = false,
|
||||||
applyStickNav = function () {
|
linkScroll = false,
|
||||||
if (navBar.height() <= win.height()) {
|
winPosition = 0,
|
||||||
navBar.addClass(stickyNavCssClass);
|
|
||||||
} else {
|
|
||||||
navBar.removeClass(stickyNavCssClass);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
enable = function () {
|
enable = function () {
|
||||||
applyStickNav();
|
init();
|
||||||
win.on('resize', applyStickNav);
|
reset();
|
||||||
|
win.on('hashchange', reset);
|
||||||
|
|
||||||
|
// Set scrolling
|
||||||
|
win.on('scroll', function () {
|
||||||
|
if (!linkScroll) {
|
||||||
|
winScroll = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setInterval(function () {
|
||||||
|
if (winScroll) {
|
||||||
|
winScroll = false;
|
||||||
|
var newWinPosition = win.scrollTop(),
|
||||||
|
navPosition = navBar.scrollTop(),
|
||||||
|
newNavPosition = navPosition + (newWinPosition - winPosition);
|
||||||
|
navBar.scrollTop(newNavPosition);
|
||||||
|
winPosition = newWinPosition;
|
||||||
|
}
|
||||||
|
}, 25);
|
||||||
},
|
},
|
||||||
init = function () {
|
init = function () {
|
||||||
navBar = jquery('nav.wy-nav-side:first');
|
navBar = jquery('nav.wy-nav-side:first');
|
||||||
win = jquery(window);
|
win = jquery(window);
|
||||||
|
},
|
||||||
|
reset = function () {
|
||||||
|
// Get anchor from URL and open up nested nav
|
||||||
|
var anchor = encodeURI(window.location.hash);
|
||||||
|
if (anchor) {
|
||||||
|
try {
|
||||||
|
var link = $('.wy-menu-vertical')
|
||||||
|
.find('[href="' + anchor + '"]');
|
||||||
|
$('.wy-menu-vertical li.toctree-l1 li.current')
|
||||||
|
.removeClass('current');
|
||||||
|
link.closest('li.toctree-l2').addClass('current');
|
||||||
|
link.closest('li.toctree-l3').addClass('current');
|
||||||
|
link.closest('li.toctree-l4').addClass('current');
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log("Error expanding nav for anchor", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hashChange = function () {
|
||||||
|
linkScroll = true;
|
||||||
|
win.one('hashchange', function () {
|
||||||
|
linkScroll = false;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
jquery(init);
|
jquery(init);
|
||||||
return {
|
return {
|
||||||
enable : enable
|
enable: enable,
|
||||||
|
hashChange: hashChange
|
||||||
};
|
};
|
||||||
}());
|
}());
|
||||||
return {
|
return {
|
||||||
|
|||||||
1
doc/_themes/sphinx_rtd_theme/theme.conf
vendored
1
doc/_themes/sphinx_rtd_theme/theme.conf
vendored
@@ -6,3 +6,4 @@ stylesheet = css/theme.css
|
|||||||
typekit_id = hiw1hhg
|
typekit_id = hiw1hhg
|
||||||
analytics_id =
|
analytics_id =
|
||||||
sticky_navigation = False
|
sticky_navigation = False
|
||||||
|
logo_only =
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _h2load()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--threads --connection-window-bits --input-file --help --requests --verbose --version --window-bits --clients --no-tls-proto --header --max-concurrent-streams ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--threads --connection-window-bits --input-file --help --requests --data --verbose --version --window-bits --clients --no-tls-proto --header --max-concurrent-streams ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _nghttp()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--verbose --no-dep --get-assets --har --header-table-size --multiply --padding --dep-idle --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --weight --help --key --null-out --window-bits --stat --header ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --padding --hexdump --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --trailer --weight --help --key --null-out --window-bits --stat --header ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _nghttpd()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--error-gzip --push --header-table-size --htdocs --padding --verbose --version --help --daemon --verify-client --workers --no-tls --color --early-response --dh-param-file ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--error-gzip --push --header-table-size --trailer --htdocs --address --padding --verbose --version --help --hexdump --dh-param-file --daemon --verify-client --workers --no-tls --color --early-response --max-concurrent-streams ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _nghttpx()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--frontend-http2-connection-window-bits --worker-read-rate --frontend-no-tls --frontend-http2-dump-request-header --daemon --write-rate --altsvc --frontend-http2-dump-response-header --backend-http1-connections-per-frontend --tls-ticket-key-file --ciphers --verify-client-cacert --backend-keep-alive-timeout --strip-incoming-x-forwarded-for --errorlog-file --private-key-passwd-file --version --backlog --backend-http-proxy-uri --add-response-header --backend-write-timeout --backend-request-buffer --add-x-forwarded-for --write-burst --backend-http2-connection-window-bits --insecure --rlimit-nofile --backend-http2-window-bits --tls-proto-list --no-location-rewrite --padding --accesslog-syslog --conf --http2-max-concurrent-streams --client-proxy --worker-frontend-connections --cacert --frontend-read-timeout --worker-write-burst --npn-list --syslog-facility --backend-http1-connections-per-host --no-server-push --client --http2-bridge --no-via --user --stream-write-timeout --backend-response-buffer --http2-no-cookie-crumbling --backend-read-timeout --stream-read-timeout --workers --worker-read-burst --tls-ctx-per-worker --dh-param-file --errorlog-syslog --frontend --accesslog-file --http2-proxy --read-burst --accesslog-format --frontend-http2-window-bits --backend-no-tls --client-private-key-file --pid-file --client-cert-file --no-host-rewrite --log-level --worker-write-rate --help --backend-tls-sni-field --subcert --frontend-frame-debug --frontend-write-timeout --verify-client --read-rate --frontend-http2-read-timeout --backend-ipv4 --listener-disable-timeout --backend-ipv6 --backend ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--worker-read-rate --frontend-no-tls --frontend-http2-dump-response-header --backend-http1-connections-per-frontend --tls-ticket-key-file --verify-client-cacert --backend-request-buffer --backend-http2-connection-window-bits --conf --worker-write-burst --npn-list --fetch-ocsp-response-file --stream-read-timeout --accesslog-syslog --frontend-http2-read-timeout --listener-disable-timeout --frontend-http2-connection-window-bits --ciphers --strip-incoming-x-forwarded-for --daemon --backend-keep-alive-timeout --backend-http-proxy-uri --backend-http1-connections-per-host --rlimit-nofile --no-via --ocsp-update-interval --backend-write-timeout --client --http2-no-cookie-crumbling --worker-read-burst --client-proxy --http2-bridge --accesslog-format --errorlog-syslog --errorlog-file --http2-max-concurrent-streams --frontend-write-timeout --read-burst --backend-ipv4 --backend-ipv6 --backend --insecure --log-level --tls-proto-list --backend-http2-connections-per-worker --dh-param-file --worker-frontend-connections --header-field-buffer --no-server-push --no-location-rewrite --no-ocsp --backend-response-buffer --workers --frontend-http2-window-bits --no-host-rewrite --worker-write-rate --backend-tls-sni-field --subcert --help --frontend-frame-debug --pid-file --frontend-http2-dump-request-header --private-key-passwd-file --write-rate --altsvc --user --add-x-forwarded-for --syslog-facility --frontend-read-timeout --backlog --write-burst --backend-http2-window-bits --padding --stream-write-timeout --cacert --version --verify-client --backend-read-timeout --frontend --accesslog-file --http2-proxy --max-header-fields --backend-no-tls --client-private-key-file --client-cert-file --add-response-header --read-rate ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
64
doc/h2load.1
64
doc/h2load.1
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "H2LOAD" "1" "February 27, 2015" "0.7.5" "nghttp2"
|
.TH "H2LOAD" "1" "May 08, 2015" "0.7.14" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
h2load \- HTTP/2 benchmarking tool
|
h2load \- HTTP/2 benchmarking tool
|
||||||
.
|
.
|
||||||
@@ -93,6 +93,8 @@ Default: \fBauto\fP
|
|||||||
.B \-w, \-\-window\-bits=<N>
|
.B \-w, \-\-window\-bits=<N>
|
||||||
Sets the stream level initial window size to (2**<N>)\-1.
|
Sets the stream level initial window size to (2**<N>)\-1.
|
||||||
For SPDY, 2**<N> is used instead.
|
For SPDY, 2**<N> is used instead.
|
||||||
|
.sp
|
||||||
|
Default: \fB30\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -101,6 +103,8 @@ Sets the connection level initial window size to
|
|||||||
(2**<N>)\-1. For SPDY, if <N> is strictly less than 16,
|
(2**<N>)\-1. For SPDY, if <N> is strictly less than 16,
|
||||||
this option is ignored. Otherwise 2**<N> is used for
|
this option is ignored. Otherwise 2**<N> is used for
|
||||||
SPDY.
|
SPDY.
|
||||||
|
.sp
|
||||||
|
Default: \fB30\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -118,6 +122,12 @@ Default: \fBh2c\-14\fP
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-d, \-\-data=<FILE>
|
||||||
|
Post FILE to server. The request method is changed to
|
||||||
|
POST.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-v, \-\-verbose
|
.B \-v, \-\-verbose
|
||||||
Output debug information.
|
Output debug information.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -195,13 +205,63 @@ The maximum time taken for request and response.
|
|||||||
The mean time taken for request and response.
|
The mean time taken for request and response.
|
||||||
.TP
|
.TP
|
||||||
.B sd
|
.B sd
|
||||||
The standard deviation of the time for request and response.
|
The standard deviation of the time taken for request and response.
|
||||||
.TP
|
.TP
|
||||||
.B +/\- sd
|
.B +/\- sd
|
||||||
The fraction of the number of requests within standard deviation
|
The fraction of the number of requests within standard deviation
|
||||||
range (mean +/\- sd) against total number of successful requests.
|
range (mean +/\- sd) against total number of successful requests.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
.TP
|
||||||
|
.B time for connect
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B min
|
||||||
|
The minimum time taken to connect to a server.
|
||||||
|
.TP
|
||||||
|
.B max
|
||||||
|
The maximum time taken to connect to a server.
|
||||||
|
.TP
|
||||||
|
.B mean
|
||||||
|
The mean time taken to connect to a server.
|
||||||
|
.TP
|
||||||
|
.B sd
|
||||||
|
The standard deviation of the time taken to connect to a server.
|
||||||
|
.TP
|
||||||
|
.B +/\- sd
|
||||||
|
The fraction of the number of connections within standard
|
||||||
|
deviation range (mean +/\- sd) against total number of successful
|
||||||
|
connections.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
.TP
|
||||||
|
.B time for 1st byte (of (decrypted in case of TLS) application data)
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B min
|
||||||
|
The minimum time taken to get 1st byte from a server.
|
||||||
|
.TP
|
||||||
|
.B max
|
||||||
|
The maximum time taken to get 1st byte from a server.
|
||||||
|
.TP
|
||||||
|
.B mean
|
||||||
|
The mean time taken to get 1st byte from a server.
|
||||||
|
.TP
|
||||||
|
.B sd
|
||||||
|
The standard deviation of the time taken to get 1st byte from a
|
||||||
|
server.
|
||||||
|
.TP
|
||||||
|
.B +/\- sd
|
||||||
|
The fraction of the number of connections within standard
|
||||||
|
deviation range (mean +/\- sd) against total number of successful
|
||||||
|
connections.
|
||||||
|
.UNINDENT
|
||||||
|
.UNINDENT
|
||||||
|
.SH FLOW CONTROL
|
||||||
|
.sp
|
||||||
|
h2load sets large flow control window by default, and effectively
|
||||||
|
disables flow control to avoid under utilization of server
|
||||||
|
performance. To set smaller flow control window, use \fI\%\-w\fP and
|
||||||
|
\fI\%\-W\fP options. For example, use \fB\-w16 \-W16\fP to set default
|
||||||
|
window size described in HTTP/2 and SPDY protocol specification.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.sp
|
.sp
|
||||||
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fInghttpx(1)\fP
|
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fInghttpx(1)\fP
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
.. program:: h2load
|
||||||
|
|
||||||
h2load(1)
|
h2load(1)
|
||||||
=========
|
=========
|
||||||
|
|
||||||
@@ -65,6 +67,8 @@ OPTIONS
|
|||||||
Sets the stream level initial window size to (2\*\*<N>)-1.
|
Sets the stream level initial window size to (2\*\*<N>)-1.
|
||||||
For SPDY, 2**<N> is used instead.
|
For SPDY, 2**<N> is used instead.
|
||||||
|
|
||||||
|
Default: ``30``
|
||||||
|
|
||||||
.. option:: -W, --connection-window-bits=<N>
|
.. option:: -W, --connection-window-bits=<N>
|
||||||
|
|
||||||
Sets the connection level initial window size to
|
Sets the connection level initial window size to
|
||||||
@@ -72,6 +76,8 @@ OPTIONS
|
|||||||
this option is ignored. Otherwise 2\*\*<N> is used for
|
this option is ignored. Otherwise 2\*\*<N> is used for
|
||||||
SPDY.
|
SPDY.
|
||||||
|
|
||||||
|
Default: ``30``
|
||||||
|
|
||||||
.. option:: -H, --header=<HEADER>
|
.. option:: -H, --header=<HEADER>
|
||||||
|
|
||||||
Add/Override a header to the requests.
|
Add/Override a header to the requests.
|
||||||
@@ -84,6 +90,11 @@ OPTIONS
|
|||||||
|
|
||||||
Default: ``h2c-14``
|
Default: ``h2c-14``
|
||||||
|
|
||||||
|
.. option:: -d, --data=<FILE>
|
||||||
|
|
||||||
|
Post FILE to server. The request method is changed to
|
||||||
|
POST.
|
||||||
|
|
||||||
.. option:: -v, --verbose
|
.. option:: -v, --verbose
|
||||||
|
|
||||||
Output debug information.
|
Output debug information.
|
||||||
@@ -142,11 +153,49 @@ time for request
|
|||||||
mean
|
mean
|
||||||
The mean time taken for request and response.
|
The mean time taken for request and response.
|
||||||
sd
|
sd
|
||||||
The standard deviation of the time for request and response.
|
The standard deviation of the time taken for request and response.
|
||||||
+/- sd
|
+/- sd
|
||||||
The fraction of the number of requests within standard deviation
|
The fraction of the number of requests within standard deviation
|
||||||
range (mean +/- sd) against total number of successful requests.
|
range (mean +/- sd) against total number of successful requests.
|
||||||
|
|
||||||
|
time for connect
|
||||||
|
min
|
||||||
|
The minimum time taken to connect to a server.
|
||||||
|
max
|
||||||
|
The maximum time taken to connect to a server.
|
||||||
|
mean
|
||||||
|
The mean time taken to connect to a server.
|
||||||
|
sd
|
||||||
|
The standard deviation of the time taken to connect to a server.
|
||||||
|
+/- sd
|
||||||
|
The fraction of the number of connections within standard
|
||||||
|
deviation range (mean +/- sd) against total number of successful
|
||||||
|
connections.
|
||||||
|
|
||||||
|
time for 1st byte (of (decrypted in case of TLS) application data)
|
||||||
|
min
|
||||||
|
The minimum time taken to get 1st byte from a server.
|
||||||
|
max
|
||||||
|
The maximum time taken to get 1st byte from a server.
|
||||||
|
mean
|
||||||
|
The mean time taken to get 1st byte from a server.
|
||||||
|
sd
|
||||||
|
The standard deviation of the time taken to get 1st byte from a
|
||||||
|
server.
|
||||||
|
+/- sd
|
||||||
|
The fraction of the number of connections within standard
|
||||||
|
deviation range (mean +/- sd) against total number of successful
|
||||||
|
connections.
|
||||||
|
|
||||||
|
FLOW CONTROL
|
||||||
|
------------
|
||||||
|
|
||||||
|
h2load sets large flow control window by default, and effectively
|
||||||
|
disables flow control to avoid under utilization of server
|
||||||
|
performance. To set smaller flow control window, use :option:`-w` and
|
||||||
|
:option:`-W` options. For example, use ``-w16 -W16`` to set default
|
||||||
|
window size described in HTTP/2 and SPDY protocol specification.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
@@ -44,11 +44,49 @@ time for request
|
|||||||
mean
|
mean
|
||||||
The mean time taken for request and response.
|
The mean time taken for request and response.
|
||||||
sd
|
sd
|
||||||
The standard deviation of the time for request and response.
|
The standard deviation of the time taken for request and response.
|
||||||
+/- sd
|
+/- sd
|
||||||
The fraction of the number of requests within standard deviation
|
The fraction of the number of requests within standard deviation
|
||||||
range (mean +/- sd) against total number of successful requests.
|
range (mean +/- sd) against total number of successful requests.
|
||||||
|
|
||||||
|
time for connect
|
||||||
|
min
|
||||||
|
The minimum time taken to connect to a server.
|
||||||
|
max
|
||||||
|
The maximum time taken to connect to a server.
|
||||||
|
mean
|
||||||
|
The mean time taken to connect to a server.
|
||||||
|
sd
|
||||||
|
The standard deviation of the time taken to connect to a server.
|
||||||
|
+/- sd
|
||||||
|
The fraction of the number of connections within standard
|
||||||
|
deviation range (mean +/- sd) against total number of successful
|
||||||
|
connections.
|
||||||
|
|
||||||
|
time for 1st byte (of (decrypted in case of TLS) application data)
|
||||||
|
min
|
||||||
|
The minimum time taken to get 1st byte from a server.
|
||||||
|
max
|
||||||
|
The maximum time taken to get 1st byte from a server.
|
||||||
|
mean
|
||||||
|
The mean time taken to get 1st byte from a server.
|
||||||
|
sd
|
||||||
|
The standard deviation of the time taken to get 1st byte from a
|
||||||
|
server.
|
||||||
|
+/- sd
|
||||||
|
The fraction of the number of connections within standard
|
||||||
|
deviation range (mean +/- sd) against total number of successful
|
||||||
|
connections.
|
||||||
|
|
||||||
|
FLOW CONTROL
|
||||||
|
------------
|
||||||
|
|
||||||
|
h2load sets large flow control window by default, and effectively
|
||||||
|
disables flow control to avoid under utilization of server
|
||||||
|
performance. To set smaller flow control window, use :option:`-w` and
|
||||||
|
:option:`-W` options. For example, use ``-w16 -W16`` to set default
|
||||||
|
window size described in HTTP/2 and SPDY protocol specification.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
124
doc/mkapiref.py
124
doc/mkapiref.py
@@ -24,19 +24,21 @@
|
|||||||
|
|
||||||
# Generates API reference from C source code.
|
# Generates API reference from C source code.
|
||||||
from __future__ import print_function # At least python 2.6 is required
|
from __future__ import print_function # At least python 2.6 is required
|
||||||
import re, sys, argparse
|
import re, sys, argparse, os.path
|
||||||
|
|
||||||
class FunctionDoc:
|
class FunctionDoc:
|
||||||
def __init__(self, name, content, domain):
|
def __init__(self, name, content, domain):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.content = content
|
self.content = content
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
|
if self.domain == 'function':
|
||||||
|
self.funcname = re.search(r'(nghttp2_[^ )]+)\(', self.name).group(1)
|
||||||
|
|
||||||
def write(self, out):
|
def write(self, out):
|
||||||
print('''.. {}:: {}'''.format(self.domain, self.name))
|
out.write('.. {}:: {}\n'.format(self.domain, self.name))
|
||||||
print('')
|
out.write('\n')
|
||||||
for line in self.content:
|
for line in self.content:
|
||||||
print(' {}'.format(line))
|
out.write(' {}\n'.format(line))
|
||||||
|
|
||||||
class StructDoc:
|
class StructDoc:
|
||||||
def __init__(self, name, content, members, member_domain):
|
def __init__(self, name, content, members, member_domain):
|
||||||
@@ -47,17 +49,17 @@ class StructDoc:
|
|||||||
|
|
||||||
def write(self, out):
|
def write(self, out):
|
||||||
if self.name:
|
if self.name:
|
||||||
print('''.. type:: {}'''.format(self.name))
|
out.write('.. type:: {}\n'.format(self.name))
|
||||||
print('')
|
out.write('\n')
|
||||||
for line in self.content:
|
for line in self.content:
|
||||||
print(' {}'.format(line))
|
out.write(' {}\n'.format(line))
|
||||||
print('')
|
out.write('\n')
|
||||||
for name, content in self.members:
|
for name, content in self.members:
|
||||||
print(''' .. {}:: {}'''.format(self.member_domain, name))
|
out.write(' .. {}:: {}\n'.format(self.member_domain, name))
|
||||||
print('')
|
out.write('\n')
|
||||||
for line in content:
|
for line in content:
|
||||||
print(''' {}'''.format(line))
|
out.write(' {}\n'.format(line))
|
||||||
print('')
|
out.write('\n')
|
||||||
|
|
||||||
class MacroDoc:
|
class MacroDoc:
|
||||||
def __init__(self, name, content):
|
def __init__(self, name, content):
|
||||||
@@ -65,10 +67,10 @@ class MacroDoc:
|
|||||||
self.content = content
|
self.content = content
|
||||||
|
|
||||||
def write(self, out):
|
def write(self, out):
|
||||||
print('''.. macro:: {}'''.format(self.name))
|
out.write('''.. macro:: {}\n'''.format(self.name))
|
||||||
print('')
|
out.write('\n')
|
||||||
for line in self.content:
|
for line in self.content:
|
||||||
print(' {}'.format(line))
|
out.write(' {}\n'.format(line))
|
||||||
|
|
||||||
def make_api_ref(infiles):
|
def make_api_ref(infiles):
|
||||||
macros = []
|
macros = []
|
||||||
@@ -93,19 +95,65 @@ def make_api_ref(infiles):
|
|||||||
enums.append(process_enum(infile))
|
enums.append(process_enum(infile))
|
||||||
elif doctype == '@macro':
|
elif doctype == '@macro':
|
||||||
macros.append(process_macro(infile))
|
macros.append(process_macro(infile))
|
||||||
|
return macros, enums, types, functions
|
||||||
|
|
||||||
alldocs = [('Macros', macros),
|
alldocs = [('Macros', macros),
|
||||||
('Enums', enums),
|
('Enums', enums),
|
||||||
('Types (structs, unions and typedefs)', types),
|
('Types (structs, unions and typedefs)', types),
|
||||||
('Functions', functions)]
|
('Functions', functions)]
|
||||||
for title, docs in alldocs:
|
|
||||||
if not docs:
|
def output(
|
||||||
continue
|
indexfile, macrosfile, enumsfile, typesfile, funcsdir,
|
||||||
print(title)
|
macros, enums, types, functions):
|
||||||
print('-'*len(title))
|
indexfile.write('''
|
||||||
for doc in docs:
|
API Reference
|
||||||
doc.write(sys.stdout)
|
=============
|
||||||
print('')
|
|
||||||
print('')
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
macros
|
||||||
|
enums
|
||||||
|
types
|
||||||
|
''')
|
||||||
|
|
||||||
|
for doc in functions:
|
||||||
|
indexfile.write(' {}\n'.format(doc.funcname))
|
||||||
|
|
||||||
|
macrosfile.write('''
|
||||||
|
Macros
|
||||||
|
======
|
||||||
|
''')
|
||||||
|
for doc in macros:
|
||||||
|
doc.write(macrosfile)
|
||||||
|
|
||||||
|
enumsfile.write('''
|
||||||
|
Enums
|
||||||
|
=====
|
||||||
|
''')
|
||||||
|
for doc in enums:
|
||||||
|
doc.write(enumsfile)
|
||||||
|
|
||||||
|
typesfile.write('''
|
||||||
|
Types (structs, unions and typedefs)
|
||||||
|
====================================
|
||||||
|
''')
|
||||||
|
for doc in types:
|
||||||
|
doc.write(typesfile)
|
||||||
|
|
||||||
|
for doc in functions:
|
||||||
|
with open(os.path.join(funcsdir, doc.funcname + '.rst'), 'w') as f:
|
||||||
|
f.write('''
|
||||||
|
{funcname}
|
||||||
|
{secul}
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
--------
|
||||||
|
|
||||||
|
*#include <nghttp2/nghttp2.h>*
|
||||||
|
|
||||||
|
'''.format(funcname=doc.funcname, secul='='*len(doc.funcname)))
|
||||||
|
doc.write(f)
|
||||||
|
|
||||||
def process_macro(infile):
|
def process_macro(infile):
|
||||||
content = read_content(infile)
|
content = read_content(infile)
|
||||||
@@ -199,12 +247,30 @@ def transform_content(content):
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser(description="Generate API reference")
|
parser = argparse.ArgumentParser(description="Generate API reference")
|
||||||
parser.add_argument('--header', type=argparse.FileType('r'),
|
parser.add_argument('index', type=argparse.FileType('w'),
|
||||||
help='header inserted at the top of the page')
|
help='index output file')
|
||||||
|
parser.add_argument('macros', type=argparse.FileType('w'),
|
||||||
|
help='macros section output file. The filename should be macros.rst')
|
||||||
|
parser.add_argument('enums', type=argparse.FileType('w'),
|
||||||
|
help='enums section output file. The filename should be enums.rst')
|
||||||
|
parser.add_argument('types', type=argparse.FileType('w'),
|
||||||
|
help='types section output file. The filename should be types.rst')
|
||||||
|
parser.add_argument('funcsdir',
|
||||||
|
help='functions doc output dir')
|
||||||
parser.add_argument('files', nargs='+', type=argparse.FileType('r'),
|
parser.add_argument('files', nargs='+', type=argparse.FileType('r'),
|
||||||
help='source file')
|
help='source file')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.header:
|
macros = []
|
||||||
print(args.header.read())
|
enums = []
|
||||||
|
types = []
|
||||||
|
funcs = []
|
||||||
for infile in args.files:
|
for infile in args.files:
|
||||||
make_api_ref(args.files)
|
m, e, t, f = make_api_ref(args.files)
|
||||||
|
macros.extend(m)
|
||||||
|
enums.extend(e)
|
||||||
|
types.extend(t)
|
||||||
|
funcs.extend(f)
|
||||||
|
funcs.sort(key=lambda x: x.funcname)
|
||||||
|
output(
|
||||||
|
args.index, args.macros, args.enums, args.types, args.funcsdir,
|
||||||
|
macros, enums, types, funcs)
|
||||||
|
|||||||
90
doc/nghttp.1
90
doc/nghttp.1
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTP" "1" "February 27, 2015" "0.7.5" "nghttp2"
|
.TH "NGHTTP" "1" "May 08, 2015" "0.7.14" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttp \- HTTP/2 experimental client
|
nghttp \- HTTP/2 experimental client
|
||||||
.
|
.
|
||||||
@@ -64,8 +64,9 @@ yet.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-t, \-\-timeout=<SEC>
|
.B \-t, \-\-timeout=<DURATION>
|
||||||
Timeout each request after <SEC> seconds.
|
Timeout each request after <DURATION>. Set 0 to disable
|
||||||
|
timeout.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -101,6 +102,14 @@ Add a header to the requests. Example: \fI\%\-H\fP\(aq:method: PUT\(aq
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-trailer=<HEADER>
|
||||||
|
Add a trailer header to the requests. <HEADER> must not
|
||||||
|
include pseudo header field (header field name starting
|
||||||
|
with \(aq:\(aq). To send trailer, one must use \fI\%\-d\fP option to
|
||||||
|
send request body. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-cert=<CERT>
|
.B \-\-cert=<CERT>
|
||||||
Use the specified client certificate file. The file
|
Use the specified client certificate file. The file
|
||||||
must be in PEM format.
|
must be in PEM format.
|
||||||
@@ -127,7 +136,7 @@ requested twice. This option disables it too.
|
|||||||
.TP
|
.TP
|
||||||
.B \-u, \-\-upgrade
|
.B \-u, \-\-upgrade
|
||||||
Perform HTTP Upgrade for HTTP/2. This option is ignored
|
Perform HTTP Upgrade for HTTP/2. This option is ignored
|
||||||
if the request URI has https scheme. If \fI\-d\fP is used, the
|
if the request URI has https scheme. If \fI\%\-d\fP is used, the
|
||||||
HTTP upgrade request is performed with OPTIONS method.
|
HTTP upgrade request is performed with OPTIONS method.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
@@ -184,8 +193,15 @@ Don\(aqt send dependency based priority hint to server.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-dep\-idle
|
.B \-\-hexdump
|
||||||
Use idle streams as anchor nodes to express priority.
|
Display the incoming traffic in hexadecimal (Canonical
|
||||||
|
hex+ASCII display). If SSL/TLS is used, decrypted data
|
||||||
|
are used.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-no\-push
|
||||||
|
Disable server push.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -200,6 +216,68 @@ Display this help and exit.
|
|||||||
.sp
|
.sp
|
||||||
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||||
10 * 1024). Units are K, M and G (powers of 1024).
|
10 * 1024). Units are K, M and G (powers of 1024).
|
||||||
|
.sp
|
||||||
|
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
||||||
|
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
|
||||||
|
(hours, minutes, seconds and milliseconds, respectively). If a unit
|
||||||
|
is omitted, a second is used as unit.
|
||||||
|
.SH DEPENDENCY BASED PRIORITY
|
||||||
|
.sp
|
||||||
|
nghttp sends priority hints to server by default unless
|
||||||
|
\fI\%\-\-no\-dep\fP is used. nghttp mimics the way Firefox employs to
|
||||||
|
manages dependency using idle streams. We follows the behaviour of
|
||||||
|
Firefox Nightly as of April, 2015, and nghttp\(aqs behaviour is very
|
||||||
|
static and could be different from Firefox in detail. But reproducing
|
||||||
|
the same behaviour of Firefox is not our goal. The goal is provide
|
||||||
|
the easy way to test out the dependency priority in server
|
||||||
|
implementation.
|
||||||
|
.sp
|
||||||
|
When connection is established, nghttp sends 5 PRIORITY frames to idle
|
||||||
|
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
|
||||||
|
tree:
|
||||||
|
.INDENT 0.0
|
||||||
|
.INDENT 3.5
|
||||||
|
.sp
|
||||||
|
.nf
|
||||||
|
.ft C
|
||||||
|
+\-\-\-\-\-+
|
||||||
|
|id=0 |
|
||||||
|
+\-\-\-\-\-+
|
||||||
|
^ ^ ^
|
||||||
|
w=201 / | \e w=1
|
||||||
|
/ | \e
|
||||||
|
/ w=101| \e
|
||||||
|
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
|
||||||
|
|id=3 | |id=5 | |id=7 |
|
||||||
|
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
|
||||||
|
^ ^
|
||||||
|
w=1 | w=1 |
|
||||||
|
| |
|
||||||
|
+\-\-\-\-\-+ +\-\-\-\-\-+
|
||||||
|
|id=11| |id=9 |
|
||||||
|
+\-\-\-\-\-+ +\-\-\-\-\-+
|
||||||
|
.ft P
|
||||||
|
.fi
|
||||||
|
.UNINDENT
|
||||||
|
.UNINDENT
|
||||||
|
.sp
|
||||||
|
In the above figure, \fBid\fP means stream ID, and \fBw\fP means weight.
|
||||||
|
The stream 0 is non\-existence stream, and forms the root of the tree.
|
||||||
|
The stream 7 and 9 are not used for now.
|
||||||
|
.sp
|
||||||
|
The URIs given in the command\-line depend on stream 11 with the weight
|
||||||
|
given in \fI\%\-p\fP option, which defaults to 16.
|
||||||
|
.sp
|
||||||
|
If \fI\%\-a\fP option is used, nghttp parses the resource pointed by
|
||||||
|
URI given in command\-line as html, and extracts resource links from
|
||||||
|
it. When requesting those resources, nghttp uses dependency according
|
||||||
|
to its resource type.
|
||||||
|
.sp
|
||||||
|
For CSS, and Javascript files inside "head" element, they depend on
|
||||||
|
stream 3 with the weight 2. The Javascript files outside "head"
|
||||||
|
element depend on stream 5 with the weight 2. The mages depend on
|
||||||
|
stream 11 with the weight 12. The other resources (e.g., icon) depend
|
||||||
|
on stream 11 with the weight 2.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.sp
|
.sp
|
||||||
\fInghttpd(1)\fP, \fInghttpx(1)\fP, \fIh2load(1)\fP
|
\fInghttpd(1)\fP, \fInghttpx(1)\fP, \fIh2load(1)\fP
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
.. program:: nghttp
|
||||||
|
|
||||||
nghttp(1)
|
nghttp(1)
|
||||||
=========
|
=========
|
||||||
|
|
||||||
@@ -36,9 +38,10 @@ OPTIONS
|
|||||||
'index.html' is used as a filename. Not implemented
|
'index.html' is used as a filename. Not implemented
|
||||||
yet.
|
yet.
|
||||||
|
|
||||||
.. option:: -t, --timeout=<SEC>
|
.. option:: -t, --timeout=<DURATION>
|
||||||
|
|
||||||
Timeout each request after <SEC> seconds.
|
Timeout each request after <DURATION>. Set 0 to disable
|
||||||
|
timeout.
|
||||||
|
|
||||||
.. option:: -w, --window-bits=<N>
|
.. option:: -w, --window-bits=<N>
|
||||||
|
|
||||||
@@ -67,6 +70,13 @@ OPTIONS
|
|||||||
|
|
||||||
Add a header to the requests. Example: :option:`-H`\':method: PUT'
|
Add a header to the requests. Example: :option:`-H`\':method: PUT'
|
||||||
|
|
||||||
|
.. option:: --trailer=<HEADER>
|
||||||
|
|
||||||
|
Add a trailer header to the requests. <HEADER> must not
|
||||||
|
include pseudo header field (header field name starting
|
||||||
|
with ':'). To send trailer, one must use :option:`-d` option to
|
||||||
|
send request body. Example: :option:`--trailer` 'foo: bar'.
|
||||||
|
|
||||||
.. option:: --cert=<CERT>
|
.. option:: --cert=<CERT>
|
||||||
|
|
||||||
Use the specified client certificate file. The file
|
Use the specified client certificate file. The file
|
||||||
@@ -136,9 +146,15 @@ OPTIONS
|
|||||||
|
|
||||||
Don't send dependency based priority hint to server.
|
Don't send dependency based priority hint to server.
|
||||||
|
|
||||||
.. option:: --dep-idle
|
.. option:: --hexdump
|
||||||
|
|
||||||
Use idle streams as anchor nodes to express priority.
|
Display the incoming traffic in hexadecimal (Canonical
|
||||||
|
hex+ASCII display). If SSL/TLS is used, decrypted data
|
||||||
|
are used.
|
||||||
|
|
||||||
|
.. option:: --no-push
|
||||||
|
|
||||||
|
Disable server push.
|
||||||
|
|
||||||
.. option:: --version
|
.. option:: --version
|
||||||
|
|
||||||
@@ -149,9 +165,66 @@ OPTIONS
|
|||||||
Display this help and exit.
|
Display this help and exit.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||||
10 * 1024). Units are K, M and G (powers of 1024).
|
10 * 1024). Units are K, M and G (powers of 1024).
|
||||||
|
|
||||||
|
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
||||||
|
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
|
||||||
|
(hours, minutes, seconds and milliseconds, respectively). If a unit
|
||||||
|
is omitted, a second is used as unit.
|
||||||
|
|
||||||
|
DEPENDENCY BASED PRIORITY
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
nghttp sends priority hints to server by default unless
|
||||||
|
:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
|
||||||
|
manages dependency using idle streams. We follows the behaviour of
|
||||||
|
Firefox Nightly as of April, 2015, and nghttp's behaviour is very
|
||||||
|
static and could be different from Firefox in detail. But reproducing
|
||||||
|
the same behaviour of Firefox is not our goal. The goal is provide
|
||||||
|
the easy way to test out the dependency priority in server
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
When connection is established, nghttp sends 5 PRIORITY frames to idle
|
||||||
|
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
|
||||||
|
tree::
|
||||||
|
|
||||||
|
+-----+
|
||||||
|
|id=0 |
|
||||||
|
+-----+
|
||||||
|
^ ^ ^
|
||||||
|
w=201 / | \ w=1
|
||||||
|
/ | \
|
||||||
|
/ w=101| \
|
||||||
|
+-----+ +-----+ +-----+
|
||||||
|
|id=3 | |id=5 | |id=7 |
|
||||||
|
+-----+ +-----+ +-----+
|
||||||
|
^ ^
|
||||||
|
w=1 | w=1 |
|
||||||
|
| |
|
||||||
|
+-----+ +-----+
|
||||||
|
|id=11| |id=9 |
|
||||||
|
+-----+ +-----+
|
||||||
|
|
||||||
|
In the above figure, ``id`` means stream ID, and ``w`` means weight.
|
||||||
|
The stream 0 is non-existence stream, and forms the root of the tree.
|
||||||
|
The stream 7 and 9 are not used for now.
|
||||||
|
|
||||||
|
The URIs given in the command-line depend on stream 11 with the weight
|
||||||
|
given in :option:`-p` option, which defaults to 16.
|
||||||
|
|
||||||
|
If :option:`-a` option is used, nghttp parses the resource pointed by
|
||||||
|
URI given in command-line as html, and extracts resource links from
|
||||||
|
it. When requesting those resources, nghttp uses dependency according
|
||||||
|
to its resource type.
|
||||||
|
|
||||||
|
For CSS, and Javascript files inside "head" element, they depend on
|
||||||
|
stream 3 with the weight 2. The Javascript files outside "head"
|
||||||
|
element depend on stream 5 with the weight 2. The mages depend on
|
||||||
|
stream 11 with the weight 12. The other resources (e.g., icon) depend
|
||||||
|
on stream 11 with the weight 2.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,54 @@
|
|||||||
|
DEPENDENCY BASED PRIORITY
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
nghttp sends priority hints to server by default unless
|
||||||
|
:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
|
||||||
|
manages dependency using idle streams. We follows the behaviour of
|
||||||
|
Firefox Nightly as of April, 2015, and nghttp's behaviour is very
|
||||||
|
static and could be different from Firefox in detail. But reproducing
|
||||||
|
the same behaviour of Firefox is not our goal. The goal is provide
|
||||||
|
the easy way to test out the dependency priority in server
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
When connection is established, nghttp sends 5 PRIORITY frames to idle
|
||||||
|
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
|
||||||
|
tree::
|
||||||
|
|
||||||
|
+-----+
|
||||||
|
|id=0 |
|
||||||
|
+-----+
|
||||||
|
^ ^ ^
|
||||||
|
w=201 / | \ w=1
|
||||||
|
/ | \
|
||||||
|
/ w=101| \
|
||||||
|
+-----+ +-----+ +-----+
|
||||||
|
|id=3 | |id=5 | |id=7 |
|
||||||
|
+-----+ +-----+ +-----+
|
||||||
|
^ ^
|
||||||
|
w=1 | w=1 |
|
||||||
|
| |
|
||||||
|
+-----+ +-----+
|
||||||
|
|id=11| |id=9 |
|
||||||
|
+-----+ +-----+
|
||||||
|
|
||||||
|
In the above figure, ``id`` means stream ID, and ``w`` means weight.
|
||||||
|
The stream 0 is non-existence stream, and forms the root of the tree.
|
||||||
|
The stream 7 and 9 are not used for now.
|
||||||
|
|
||||||
|
The URIs given in the command-line depend on stream 11 with the weight
|
||||||
|
given in :option:`-p` option, which defaults to 16.
|
||||||
|
|
||||||
|
If :option:`-a` option is used, nghttp parses the resource pointed by
|
||||||
|
URI given in command-line as html, and extracts resource links from
|
||||||
|
it. When requesting those resources, nghttp uses dependency according
|
||||||
|
to its resource type.
|
||||||
|
|
||||||
|
For CSS, and Javascript files inside "head" element, they depend on
|
||||||
|
stream 3 with the weight 2. The Javascript files outside "head"
|
||||||
|
element depend on stream 5 with the weight 2. The mages depend on
|
||||||
|
stream 11 with the weight 12. The other resources (e.g., icon) depend
|
||||||
|
on stream 11 with the weight 2.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTPD" "1" "February 27, 2015" "0.7.5" "nghttp2"
|
.TH "NGHTTPD" "1" "May 08, 2015" "0.7.14" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpd \- HTTP/2 experimental server
|
nghttpd \- HTTP/2 experimental server
|
||||||
.
|
.
|
||||||
@@ -63,7 +63,7 @@ address determined by getaddrinfo is used.
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-D, \-\-daemon
|
.B \-D, \-\-daemon
|
||||||
Run in a background. If \fI\-D\fP is used, the current working
|
Run in a background. If \fI\%\-D\fP is used, the current working
|
||||||
directory is changed to \(aq\fI/\fP\(aq. Therefore if this option
|
directory is changed to \(aq\fI/\fP\(aq. Therefore if this option
|
||||||
is used, \fI\%\-d\fP option must be specified.
|
is used, \fI\%\-d\fP option must be specified.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -109,7 +109,7 @@ Push resources <PUSH_PATH>s when <PATH> is requested.
|
|||||||
This option can be used repeatedly to specify multiple
|
This option can be used repeatedly to specify multiple
|
||||||
push configurations. <PATH> and <PUSH_PATH>s are
|
push configurations. <PATH> and <PUSH_PATH>s are
|
||||||
relative to document root. See \fI\%\-\-htdocs\fP option.
|
relative to document root. See \fI\%\-\-htdocs\fP option.
|
||||||
Example: \fI\-p\fP/=/foo.png \fI\-p\fP/doc=/bar.css
|
Example: \fI\%\-p\fP/=/foo.png \fI\%\-p\fP/doc=/bar.css
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -119,6 +119,14 @@ Specify 0 to disable padding.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-m, \-\-max\-concurrent\-streams=<N>
|
||||||
|
Set the maximum number of the concurrent streams in one
|
||||||
|
HTTP/2 session.
|
||||||
|
.sp
|
||||||
|
Default: \fB100\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-n, \-\-workers=<N>
|
.B \-n, \-\-workers=<N>
|
||||||
Set the number of worker threads.
|
Set the number of worker threads.
|
||||||
.sp
|
.sp
|
||||||
@@ -144,6 +152,21 @@ rather than complete request is received.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-trailer=<HEADER>
|
||||||
|
Add a trailer header to a response. <HEADER> must not
|
||||||
|
include pseudo header field (header field name starting
|
||||||
|
with \(aq:\(aq). The trailer is sent only if a response has
|
||||||
|
body part. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-hexdump
|
||||||
|
Display the incoming traffic in hexadecimal (Canonical
|
||||||
|
hex+ASCII display). If SSL/TLS is used, decrypted data
|
||||||
|
are used.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-version
|
.B \-\-version
|
||||||
Display version information and exit.
|
Display version information and exit.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
.. program:: nghttpd
|
||||||
|
|
||||||
nghttpd(1)
|
nghttpd(1)
|
||||||
==========
|
==========
|
||||||
|
|
||||||
@@ -83,6 +85,13 @@ OPTIONS
|
|||||||
Add at most <N> bytes to a frame payload as padding.
|
Add at most <N> bytes to a frame payload as padding.
|
||||||
Specify 0 to disable padding.
|
Specify 0 to disable padding.
|
||||||
|
|
||||||
|
.. option:: -m, --max-concurrent-streams=<N>
|
||||||
|
|
||||||
|
Set the maximum number of the concurrent streams in one
|
||||||
|
HTTP/2 session.
|
||||||
|
|
||||||
|
Default: ``100``
|
||||||
|
|
||||||
.. option:: -n, --workers=<N>
|
.. option:: -n, --workers=<N>
|
||||||
|
|
||||||
Set the number of worker threads.
|
Set the number of worker threads.
|
||||||
@@ -104,6 +113,19 @@ OPTIONS
|
|||||||
Start sending response when request HEADERS is received,
|
Start sending response when request HEADERS is received,
|
||||||
rather than complete request is received.
|
rather than complete request is received.
|
||||||
|
|
||||||
|
.. option:: --trailer=<HEADER>
|
||||||
|
|
||||||
|
Add a trailer header to a response. <HEADER> must not
|
||||||
|
include pseudo header field (header field name starting
|
||||||
|
with ':'). The trailer is sent only if a response has
|
||||||
|
body part. Example: :option:`--trailer` 'foo: bar'.
|
||||||
|
|
||||||
|
.. option:: --hexdump
|
||||||
|
|
||||||
|
Display the incoming traffic in hexadecimal (Canonical
|
||||||
|
hex+ASCII display). If SSL/TLS is used, decrypted data
|
||||||
|
are used.
|
||||||
|
|
||||||
.. option:: --version
|
.. option:: --version
|
||||||
|
|
||||||
Display version information and exit.
|
Display version information and exit.
|
||||||
@@ -113,6 +135,7 @@ OPTIONS
|
|||||||
Display this help and exit.
|
Display this help and exit.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||||
10 * 1024). Units are K, M and G (powers of 1024).
|
10 * 1024). Units are K, M and G (powers of 1024).
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTPX" "1" "February 27, 2015" "0.7.5" "nghttp2"
|
.TH "NGHTTPX" "1" "May 08, 2015" "0.7.14" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpx \- HTTP/2 experimental proxy
|
nghttpx \- HTTP/2 experimental proxy
|
||||||
.
|
.
|
||||||
@@ -46,7 +46,8 @@ Set path to server\(aqs private key. Required unless \fI\%\-p\fP,
|
|||||||
.TP
|
.TP
|
||||||
.B <CERT>
|
.B <CERT>
|
||||||
Set path to server\(aqs certificate. Required unless \fI\%\-p\fP,
|
Set path to server\(aqs certificate. Required unless \fI\%\-p\fP,
|
||||||
\fI\%\-\-client\fP or \fI\%\-\-frontend\-no\-tls\fP are given.
|
\fI\%\-\-client\fP or \fI\%\-\-frontend\-no\-tls\fP are given. To make OCSP
|
||||||
|
stapling work, this must be absolute path.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.sp
|
.sp
|
||||||
@@ -55,13 +56,10 @@ The options are categorized into several groups.
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-b, \-\-backend=<HOST,PORT>
|
.B \-b, \-\-backend=<HOST,PORT>
|
||||||
Set backend host and port. For HTTP/1 backend, multiple
|
Set backend host and port. The multiple backend
|
||||||
backend addresses are accepted by repeating this option.
|
addresses are accepted by repeating this option. UNIX
|
||||||
HTTP/2 backend does not support multiple backend
|
domain socket can be specified by prefixing path name
|
||||||
addresses and the first occurrence of this option is
|
with "unix:" (e.g., unix:/var/run/backend.sock)
|
||||||
used. UNIX domain socket can be specified by prefixing
|
|
||||||
path name with "unix:" (e.g.,
|
|
||||||
unix:/var/run/backend.sock)
|
|
||||||
.sp
|
.sp
|
||||||
Default: \fB127.0.0.1,80\fP
|
Default: \fB127.0.0.1,80\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -196,6 +194,13 @@ Default: \fB0\fP
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-backend\-http2\-connections\-per\-worker=<N>
|
||||||
|
Set maximum number of HTTP/2 connections per worker.
|
||||||
|
The default value is 0, which means the number of
|
||||||
|
backend addresses specified by \fI\%\-b\fP option.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-backend\-http1\-connections\-per\-host=<N>
|
.B \-\-backend\-http1\-connections\-per\-host=<N>
|
||||||
Set maximum number of backend concurrent HTTP/1
|
Set maximum number of backend concurrent HTTP/1
|
||||||
connections per host. This option is meaningful when \fI\%\-s\fP
|
connections per host. This option is meaningful when \fI\%\-s\fP
|
||||||
@@ -245,14 +250,14 @@ Default: \fB16K\fP
|
|||||||
Specify read timeout for HTTP/2 and SPDY frontend
|
Specify read timeout for HTTP/2 and SPDY frontend
|
||||||
connection.
|
connection.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB180s\fP
|
Default: \fB3m\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-frontend\-read\-timeout=<DURATION>
|
.B \-\-frontend\-read\-timeout=<DURATION>
|
||||||
Specify read timeout for HTTP/1.1 frontend connection.
|
Specify read timeout for HTTP/1.1 frontend connection.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB180s\fP
|
Default: \fB3m\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -282,7 +287,7 @@ Default: \fB0\fP
|
|||||||
.B \-\-backend\-read\-timeout=<DURATION>
|
.B \-\-backend\-read\-timeout=<DURATION>
|
||||||
Specify read timeout for backend connection.
|
Specify read timeout for backend connection.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB180s\fP
|
Default: \fB3m\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -344,7 +349,8 @@ password protected it\(aqll be requested interactively.
|
|||||||
Specify additional certificate and private key file.
|
Specify additional certificate and private key file.
|
||||||
nghttpx will choose certificates based on the hostname
|
nghttpx will choose certificates based on the hostname
|
||||||
indicated by client using TLS SNI extension. This
|
indicated by client using TLS SNI extension. This
|
||||||
option can be used multiple times.
|
option can be used multiple times. To make OCSP
|
||||||
|
stapling work, <CERTPATH> must be absolute path.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -429,14 +435,23 @@ are stored in memory.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-tls\-ctx\-per\-worker
|
.B \-\-fetch\-ocsp\-response\-file=<PATH>
|
||||||
Create OpenSSL\(aqs SSL_CTX per worker, so that no internal
|
Path to fetch\-ocsp\-response script file. It should be
|
||||||
locking is required. This may improve scalability with
|
absolute path.
|
||||||
multi threaded configuration. If this option is
|
.sp
|
||||||
enabled, session ID is no longer shared accross SSL_CTX
|
Default: \fB/usr/local/share/nghttp2/fetch\-ocsp\-response\fP
|
||||||
objects, which means session ID generated by one worker
|
.UNINDENT
|
||||||
is not acceptable by another worker. On the other hand,
|
.INDENT 0.0
|
||||||
session ticket key is shared across all worker threads.
|
.TP
|
||||||
|
.B \-\-ocsp\-update\-interval=<DURATION>
|
||||||
|
Set interval to update OCSP response cache.
|
||||||
|
.sp
|
||||||
|
Default: \fB4h\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-no\-ocsp
|
||||||
|
Disable OCSP stapling.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.SS HTTP/2 and SPDY
|
.SS HTTP/2 and SPDY
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
@@ -617,7 +632,8 @@ Default: \fB$remote_addr \- \- [$time_local] "$request" $status $body_bytes_sent
|
|||||||
.TP
|
.TP
|
||||||
.B \-\-errorlog\-file=<PATH>
|
.B \-\-errorlog\-file=<PATH>
|
||||||
Set path to write error log. To reopen file, send USR1
|
Set path to write error log. To reopen file, send USR1
|
||||||
signal to nghttpx.
|
signal to nghttpx. stderr will be redirected to the
|
||||||
|
error log file unless \fI\%\-\-errorlog\-syslog\fP is used.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB/dev/stderr\fP
|
Default: \fB/dev/stderr\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -688,6 +704,23 @@ won\(aqt replace anything already set. This option can be
|
|||||||
used several times to specify multiple header fields.
|
used several times to specify multiple header fields.
|
||||||
Example: \fI\%\-\-add\-response\-header\fP="foo: bar"
|
Example: \fI\%\-\-add\-response\-header\fP="foo: bar"
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-header\-field\-buffer=<SIZE>
|
||||||
|
Set maximum buffer size for incoming HTTP header field
|
||||||
|
list. This is the sum of header name and value in
|
||||||
|
bytes.
|
||||||
|
.sp
|
||||||
|
Default: \fB64K\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-max\-header\-fields=<N>
|
||||||
|
Set maximum number of incoming HTTP header fields, which
|
||||||
|
appear in one request or response header field list.
|
||||||
|
.sp
|
||||||
|
Default: \fB100\fP
|
||||||
|
.UNINDENT
|
||||||
.SS Debug
|
.SS Debug
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -755,8 +788,9 @@ The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
|||||||
10 * 1024). Units are K, M and G (powers of 1024).
|
10 * 1024). Units are K, M and G (powers of 1024).
|
||||||
.sp
|
.sp
|
||||||
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
||||||
is 1 second and 500ms is 500 milliseconds). Units are s or ms. If
|
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
|
||||||
a unit is omitted, a second is used as unit.
|
(hours, minutes, seconds and milliseconds, respectively). If a unit
|
||||||
|
is omitted, a second is used as unit.
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -845,6 +879,15 @@ specified socket already exists in the file system, nghttpx first
|
|||||||
deletes it. However, if SIGUSR2 is used to execute new binary and
|
deletes it. However, if SIGUSR2 is used to execute new binary and
|
||||||
both old and new configurations use same filename, new binary does not
|
both old and new configurations use same filename, new binary does not
|
||||||
delete the socket and continues to use it.
|
delete the socket and continues to use it.
|
||||||
|
.SH OCSP STAPLING
|
||||||
|
.sp
|
||||||
|
OCSP query is done using external perl script \fBfetch\-ocsp\-response\fP,
|
||||||
|
which has been developed as part of h2o project
|
||||||
|
(\fI\%https://github.com/h2o/h2o\fP).
|
||||||
|
.sp
|
||||||
|
The script file is usually installed under
|
||||||
|
\fB$(prefix)/share/nghttp2/\fP directory. The actual path to script can
|
||||||
|
be customized using \fI\%\-\-fetch\-ocsp\-response\-file\fP option.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.sp
|
.sp
|
||||||
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fIh2load(1)\fP
|
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fIh2load(1)\fP
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
.. program:: nghttpx
|
||||||
|
|
||||||
nghttpx(1)
|
nghttpx(1)
|
||||||
==========
|
==========
|
||||||
|
|
||||||
@@ -21,7 +23,8 @@ A reverse proxy for HTTP/2, HTTP/1 and SPDY.
|
|||||||
.. describe:: <CERT>
|
.. describe:: <CERT>
|
||||||
|
|
||||||
Set path to server's certificate. Required unless :option:`-p`\,
|
Set path to server's certificate. Required unless :option:`-p`\,
|
||||||
:option:`--client` or :option:`\--frontend-no-tls` are given.
|
:option:`--client` or :option:`\--frontend-no-tls` are given. To make OCSP
|
||||||
|
stapling work, this must be absolute path.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
@@ -34,13 +37,10 @@ Connections
|
|||||||
|
|
||||||
.. option:: -b, --backend=<HOST,PORT>
|
.. option:: -b, --backend=<HOST,PORT>
|
||||||
|
|
||||||
Set backend host and port. For HTTP/1 backend, multiple
|
Set backend host and port. The multiple backend
|
||||||
backend addresses are accepted by repeating this option.
|
addresses are accepted by repeating this option. UNIX
|
||||||
HTTP/2 backend does not support multiple backend
|
domain socket can be specified by prefixing path name
|
||||||
addresses and the first occurrence of this option is
|
with "unix:" (e.g., unix:/var/run/backend.sock)
|
||||||
used. UNIX domain socket can be specified by prefixing
|
|
||||||
path name with "unix:" (e.g.,
|
|
||||||
unix:/var/run/backend.sock)
|
|
||||||
|
|
||||||
Default: ``127.0.0.1,80``
|
Default: ``127.0.0.1,80``
|
||||||
|
|
||||||
@@ -161,6 +161,12 @@ Performance
|
|||||||
|
|
||||||
Default: ``0``
|
Default: ``0``
|
||||||
|
|
||||||
|
.. option:: --backend-http2-connections-per-worker=<N>
|
||||||
|
|
||||||
|
Set maximum number of HTTP/2 connections per worker.
|
||||||
|
The default value is 0, which means the number of
|
||||||
|
backend addresses specified by :option:`-b` option.
|
||||||
|
|
||||||
.. option:: --backend-http1-connections-per-host=<N>
|
.. option:: --backend-http1-connections-per-host=<N>
|
||||||
|
|
||||||
Set maximum number of backend concurrent HTTP/1
|
Set maximum number of backend concurrent HTTP/1
|
||||||
@@ -209,13 +215,13 @@ Timeout
|
|||||||
Specify read timeout for HTTP/2 and SPDY frontend
|
Specify read timeout for HTTP/2 and SPDY frontend
|
||||||
connection.
|
connection.
|
||||||
|
|
||||||
Default: ``180s``
|
Default: ``3m``
|
||||||
|
|
||||||
.. option:: --frontend-read-timeout=<DURATION>
|
.. option:: --frontend-read-timeout=<DURATION>
|
||||||
|
|
||||||
Specify read timeout for HTTP/1.1 frontend connection.
|
Specify read timeout for HTTP/1.1 frontend connection.
|
||||||
|
|
||||||
Default: ``180s``
|
Default: ``3m``
|
||||||
|
|
||||||
.. option:: --frontend-write-timeout=<DURATION>
|
.. option:: --frontend-write-timeout=<DURATION>
|
||||||
|
|
||||||
@@ -241,7 +247,7 @@ Timeout
|
|||||||
|
|
||||||
Specify read timeout for backend connection.
|
Specify read timeout for backend connection.
|
||||||
|
|
||||||
Default: ``180s``
|
Default: ``3m``
|
||||||
|
|
||||||
.. option:: --backend-write-timeout=<DURATION>
|
.. option:: --backend-write-timeout=<DURATION>
|
||||||
|
|
||||||
@@ -298,7 +304,8 @@ SSL/TLS
|
|||||||
Specify additional certificate and private key file.
|
Specify additional certificate and private key file.
|
||||||
nghttpx will choose certificates based on the hostname
|
nghttpx will choose certificates based on the hostname
|
||||||
indicated by client using TLS SNI extension. This
|
indicated by client using TLS SNI extension. This
|
||||||
option can be used multiple times.
|
option can be used multiple times. To make OCSP
|
||||||
|
stapling work, <CERTPATH> must be absolute path.
|
||||||
|
|
||||||
.. option:: --backend-tls-sni-field=<HOST>
|
.. option:: --backend-tls-sni-field=<HOST>
|
||||||
|
|
||||||
@@ -372,15 +379,22 @@ SSL/TLS
|
|||||||
automatically and renewed every 12hrs. At most 2 keys
|
automatically and renewed every 12hrs. At most 2 keys
|
||||||
are stored in memory.
|
are stored in memory.
|
||||||
|
|
||||||
.. option:: --tls-ctx-per-worker
|
.. option:: --fetch-ocsp-response-file=<PATH>
|
||||||
|
|
||||||
Create OpenSSL's SSL_CTX per worker, so that no internal
|
Path to fetch-ocsp-response script file. It should be
|
||||||
locking is required. This may improve scalability with
|
absolute path.
|
||||||
multi threaded configuration. If this option is
|
|
||||||
enabled, session ID is no longer shared accross SSL_CTX
|
Default: ``/usr/local/share/nghttp2/fetch-ocsp-response``
|
||||||
objects, which means session ID generated by one worker
|
|
||||||
is not acceptable by another worker. On the other hand,
|
.. option:: --ocsp-update-interval=<DURATION>
|
||||||
session ticket key is shared across all worker threads.
|
|
||||||
|
Set interval to update OCSP response cache.
|
||||||
|
|
||||||
|
Default: ``4h``
|
||||||
|
|
||||||
|
.. option:: --no-ocsp
|
||||||
|
|
||||||
|
Disable OCSP stapling.
|
||||||
|
|
||||||
|
|
||||||
HTTP/2 and SPDY
|
HTTP/2 and SPDY
|
||||||
@@ -539,7 +553,8 @@ Logging
|
|||||||
.. option:: --errorlog-file=<PATH>
|
.. option:: --errorlog-file=<PATH>
|
||||||
|
|
||||||
Set path to write error log. To reopen file, send USR1
|
Set path to write error log. To reopen file, send USR1
|
||||||
signal to nghttpx.
|
signal to nghttpx. stderr will be redirected to the
|
||||||
|
error log file unless :option:`--errorlog-syslog` is used.
|
||||||
|
|
||||||
Default: ``/dev/stderr``
|
Default: ``/dev/stderr``
|
||||||
|
|
||||||
@@ -604,6 +619,21 @@ HTTP
|
|||||||
used several times to specify multiple header fields.
|
used several times to specify multiple header fields.
|
||||||
Example: :option:`--add-response-header`\="foo: bar"
|
Example: :option:`--add-response-header`\="foo: bar"
|
||||||
|
|
||||||
|
.. option:: --header-field-buffer=<SIZE>
|
||||||
|
|
||||||
|
Set maximum buffer size for incoming HTTP header field
|
||||||
|
list. This is the sum of header name and value in
|
||||||
|
bytes.
|
||||||
|
|
||||||
|
Default: ``64K``
|
||||||
|
|
||||||
|
.. option:: --max-header-fields=<N>
|
||||||
|
|
||||||
|
Set maximum number of incoming HTTP header fields, which
|
||||||
|
appear in one request or response header field list.
|
||||||
|
|
||||||
|
Default: ``100``
|
||||||
|
|
||||||
|
|
||||||
Debug
|
Debug
|
||||||
~~~~~
|
~~~~~
|
||||||
@@ -667,12 +697,14 @@ Misc
|
|||||||
Print this help and exit.
|
Print this help and exit.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||||
10 * 1024). Units are K, M and G (powers of 1024).
|
10 * 1024). Units are K, M and G (powers of 1024).
|
||||||
|
|
||||||
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
||||||
is 1 second and 500ms is 500 milliseconds). Units are s or ms. If
|
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
|
||||||
a unit is omitted, a second is used as unit.
|
(hours, minutes, seconds and milliseconds, respectively). If a unit
|
||||||
|
is omitted, a second is used as unit.
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
-----
|
-----
|
||||||
@@ -760,6 +792,17 @@ deletes it. However, if SIGUSR2 is used to execute new binary and
|
|||||||
both old and new configurations use same filename, new binary does not
|
both old and new configurations use same filename, new binary does not
|
||||||
delete the socket and continues to use it.
|
delete the socket and continues to use it.
|
||||||
|
|
||||||
|
OCSP STAPLING
|
||||||
|
-------------
|
||||||
|
|
||||||
|
OCSP query is done using external perl script ``fetch-ocsp-response``,
|
||||||
|
which has been developed as part of h2o project
|
||||||
|
(https://github.com/h2o/h2o).
|
||||||
|
|
||||||
|
The script file is usually installed under
|
||||||
|
``$(prefix)/share/nghttp2/`` directory. The actual path to script can
|
||||||
|
be customized using :option:`--fetch-ocsp-response-file` option.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,17 @@ deletes it. However, if SIGUSR2 is used to execute new binary and
|
|||||||
both old and new configurations use same filename, new binary does not
|
both old and new configurations use same filename, new binary does not
|
||||||
delete the socket and continues to use it.
|
delete the socket and continues to use it.
|
||||||
|
|
||||||
|
OCSP STAPLING
|
||||||
|
-------------
|
||||||
|
|
||||||
|
OCSP query is done using external perl script ``fetch-ocsp-response``,
|
||||||
|
which has been developed as part of h2o project
|
||||||
|
(https://github.com/h2o/h2o).
|
||||||
|
|
||||||
|
The script file is usually installed under
|
||||||
|
``$(prefix)/share/nghttp2/`` directory. The actual path to script can
|
||||||
|
be customized using :option:`--fetch-ocsp-response-file` option.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
API Reference
|
Programmers' Guide
|
||||||
=============
|
==================
|
||||||
|
|
||||||
Includes
|
Includes
|
||||||
--------
|
--------
|
||||||
@@ -32,6 +32,8 @@ value. The applications are responsible to receive it before calling
|
|||||||
these functions if :type:`nghttp2_session` is configured as server and
|
these functions if :type:`nghttp2_session` is configured as server and
|
||||||
`nghttp2_option_set_recv_client_preface()` is not used.
|
`nghttp2_option_set_recv_client_preface()` is not used.
|
||||||
|
|
||||||
|
.. _http-messaging:
|
||||||
|
|
||||||
HTTP Messaging
|
HTTP Messaging
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
@@ -84,6 +86,11 @@ are floating around in existing internet and resetting stream just
|
|||||||
because of this may break many web sites. This is especially true if
|
because of this may break many web sites. This is especially true if
|
||||||
we forward to or translate from HTTP/1 traffic.
|
we forward to or translate from HTTP/1 traffic.
|
||||||
|
|
||||||
|
For "http" or "https" URIs, ":path" pseudo header fields must start
|
||||||
|
with "/". The only exception is OPTIONS request, in that case, "*" is
|
||||||
|
allowed in ":path" pseudo header field to represent system-wide
|
||||||
|
OPTIONS request.
|
||||||
|
|
||||||
With the above validations, nghttp2 library guarantees that header
|
With the above validations, nghttp2 library guarantees that header
|
||||||
field name passed to `nghttp2_on_header_callback()` is not empty.
|
field name passed to `nghttp2_on_header_callback()` is not empty.
|
||||||
Also required pseudo headers are all present and not empty.
|
Also required pseudo headers are all present and not empty.
|
||||||
@@ -50,8 +50,9 @@ Flow Control
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
HTTP/2 and SPDY/3 or later employ flow control and it may affect
|
HTTP/2 and SPDY/3 or later employ flow control and it may affect
|
||||||
benchmarking results. To adjust receiver flow control window size,
|
benchmarking results. By default, h2load uses large enough flow
|
||||||
there is following options:
|
control window, which effectively disables flow control. To adjust
|
||||||
|
receiver flow control window size, there are following options:
|
||||||
|
|
||||||
``-w``
|
``-w``
|
||||||
Sets the stream level initial window size to
|
Sets the stream level initial window size to
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ Contents:
|
|||||||
h2load.1
|
h2load.1
|
||||||
nghttpx-howto
|
nghttpx-howto
|
||||||
h2load-howto
|
h2load-howto
|
||||||
|
programmers-guide
|
||||||
apiref
|
apiref
|
||||||
libnghttp2_asio
|
libnghttp2_asio
|
||||||
python-apiref
|
python-apiref
|
||||||
|
|||||||
@@ -220,6 +220,10 @@ HTTP/2 servers
|
|||||||
|
|
||||||
This is a value of ``:path`` header field.
|
This is a value of ``:path`` header field.
|
||||||
|
|
||||||
|
.. py:attribute:: headers
|
||||||
|
|
||||||
|
Request header fields.
|
||||||
|
|
||||||
A :py:class:`BaseRequestHandler` has the following methods:
|
A :py:class:`BaseRequestHandler` has the following methods:
|
||||||
|
|
||||||
.. py:method:: on_headers()
|
.. py:method:: on_headers()
|
||||||
@@ -250,9 +254,27 @@ HTTP/2 servers
|
|||||||
is additional response headers. The *:status* header field will
|
is additional response headers. The *:status* header field will
|
||||||
be appended by the library. The *body* is the response body.
|
be appended by the library. The *body* is the response body.
|
||||||
It could be ``None`` if response body is empty. Or it must be
|
It could be ``None`` if response body is empty. Or it must be
|
||||||
instance of either ``str``, ``bytes`` or :py:class:`io.IOBase`.
|
instance of either ``str``, ``bytes``, :py:class:`io.IOBase` or
|
||||||
If instance of ``str`` is specified, it will be encoded using
|
callable, called body generator, which takes one parameter,
|
||||||
UTF-8.
|
size. The body generator generates response body. It can pause
|
||||||
|
generation of response so that it can wait for slow backend data
|
||||||
|
generation. When invoked, it should return tuple, byte string
|
||||||
|
at most size length and flag. The flag is either
|
||||||
|
:py:data:`DATA_OK`, :py:data:`DATA_EOF` or
|
||||||
|
:py:data:`DATA_DEFERRED`. For non-empty byte string and it is
|
||||||
|
not the last chunk of response, :py:data:`DATA_OK` must be
|
||||||
|
returned as flag. If this is the last chunk of the response
|
||||||
|
(byte string could be ``None``), :py:data:`DATA_EOF` must be
|
||||||
|
returned as flag. If there is no data available right now, but
|
||||||
|
additional data are anticipated, return tuple (``None``,
|
||||||
|
:py:data:`DATA_DEFERRD`). When data arrived, call
|
||||||
|
:py:meth:`resume()` and restart response body transmission.
|
||||||
|
|
||||||
|
Only the body generator can pause response body generation;
|
||||||
|
instance of :py:class:`io.IOBase` must not block.
|
||||||
|
|
||||||
|
If instance of ``str`` is specified as *body*, it will be
|
||||||
|
encoded using UTF-8.
|
||||||
|
|
||||||
The *headers* is a list of tuple of the form ``(name,
|
The *headers* is a list of tuple of the form ``(name,
|
||||||
value)``. The ``name`` and ``value`` can be either byte string
|
value)``. The ``name`` and ``value`` can be either byte string
|
||||||
@@ -273,10 +295,8 @@ HTTP/2 servers
|
|||||||
|
|
||||||
The *status* is HTTP status code. The *headers* is additional
|
The *status* is HTTP status code. The *headers* is additional
|
||||||
response headers. The ``:status`` header field is appended by
|
response headers. The ``:status`` header field is appended by
|
||||||
the library. The *body* is the response body. It could be
|
the library. The *body* is the response body. It has the same
|
||||||
``None`` if response body is empty. Or it must be instance of
|
semantics of *body* parameter of :py:meth:`send_response()`.
|
||||||
either ``str``, ``bytes`` or ``io.IOBase``. If instance of
|
|
||||||
``str`` is specified, it is encoded using UTF-8.
|
|
||||||
|
|
||||||
The headers and request_headers are a list of tuple of the form
|
The headers and request_headers are a list of tuple of the form
|
||||||
``(name, value)``. The ``name`` and ``value`` can be either byte
|
``(name, value)``. The ``name`` and ``value`` can be either byte
|
||||||
@@ -288,6 +308,27 @@ HTTP/2 servers
|
|||||||
|
|
||||||
Raises the exception if any error occurs.
|
Raises the exception if any error occurs.
|
||||||
|
|
||||||
|
.. py:method:: resume()
|
||||||
|
|
||||||
|
Signals the restarting of response body transmission paused by
|
||||||
|
``DATA_DEFERRED`` from the body generator (see
|
||||||
|
:py:meth:`send_response()` about the body generator). It is not
|
||||||
|
an error calling this method while response body transmission is
|
||||||
|
not paused.
|
||||||
|
|
||||||
|
.. py:data:: DATA_OK
|
||||||
|
|
||||||
|
``DATA_OK`` indicates non empty data is generated from body generator.
|
||||||
|
|
||||||
|
.. py:data:: DATA_EOF
|
||||||
|
|
||||||
|
``DATA_EOF`` indicates the end of response body.
|
||||||
|
|
||||||
|
.. py:data:: DATA_DEFERRED
|
||||||
|
|
||||||
|
``DATA_DEFERRED`` indicates that data are not available right now
|
||||||
|
and response should be paused.
|
||||||
|
|
||||||
The following example illustrates :py:class:`HTTP2Server` and
|
The following example illustrates :py:class:`HTTP2Server` and
|
||||||
:py:class:`BaseRequestHandler` usage:
|
:py:class:`BaseRequestHandler` usage:
|
||||||
|
|
||||||
@@ -296,6 +337,7 @@ The following example illustrates :py:class:`HTTP2Server` and
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import io, ssl
|
import io, ssl
|
||||||
|
|
||||||
import nghttp2
|
import nghttp2
|
||||||
|
|
||||||
class Handler(nghttp2.BaseRequestHandler):
|
class Handler(nghttp2.BaseRequestHandler):
|
||||||
@@ -311,9 +353,85 @@ The following example illustrates :py:class:`HTTP2Server` and
|
|||||||
body=io.BytesIO(b'nghttp2-python FTW'))
|
body=io.BytesIO(b'nghttp2-python FTW'))
|
||||||
|
|
||||||
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||||
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2
|
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
|
||||||
ctx.load_cert_chain('server.crt', 'server.key')
|
ctx.load_cert_chain('server.crt', 'server.key')
|
||||||
|
|
||||||
# give None to ssl to make the server non-SSL/TLS
|
# give None to ssl to make the server non-SSL/TLS
|
||||||
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
|
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
|
||||||
server.serve_forever()
|
server.serve_forever()
|
||||||
|
|
||||||
|
The following example illustrates HTTP/2 server using asynchronous
|
||||||
|
response body generation. This is simplified reverse proxy:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import ssl
|
||||||
|
import os
|
||||||
|
import urllib
|
||||||
|
import asyncio
|
||||||
|
import io
|
||||||
|
|
||||||
|
import nghttp2
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def get_http_header(handler, url):
|
||||||
|
url = urllib.parse.urlsplit(url)
|
||||||
|
ssl = url.scheme == 'https'
|
||||||
|
if url.port == None:
|
||||||
|
if url.scheme == 'https':
|
||||||
|
port = 443
|
||||||
|
else:
|
||||||
|
port = 80
|
||||||
|
else:
|
||||||
|
port = url.port
|
||||||
|
|
||||||
|
connect = asyncio.open_connection(url.hostname, port, ssl=ssl)
|
||||||
|
reader, writer = yield from connect
|
||||||
|
req = 'GET {path} HTTP/1.0\r\n\r\n'.format(path=url.path or '/')
|
||||||
|
writer.write(req.encode('utf-8'))
|
||||||
|
# skip response header fields
|
||||||
|
while True:
|
||||||
|
line = yield from reader.readline()
|
||||||
|
line = line.rstrip()
|
||||||
|
if not line:
|
||||||
|
break
|
||||||
|
# read body
|
||||||
|
while True:
|
||||||
|
b = yield from reader.read(4096)
|
||||||
|
if not b:
|
||||||
|
break
|
||||||
|
handler.buf.write(b)
|
||||||
|
writer.close()
|
||||||
|
handler.buf.seek(0)
|
||||||
|
handler.eof = True
|
||||||
|
handler.resume()
|
||||||
|
|
||||||
|
class Body:
|
||||||
|
def __init__(self, handler):
|
||||||
|
self.handler = handler
|
||||||
|
self.handler.eof = False
|
||||||
|
self.handler.buf = io.BytesIO()
|
||||||
|
|
||||||
|
def generate(self, n):
|
||||||
|
buf = self.handler.buf
|
||||||
|
data = buf.read1(n)
|
||||||
|
if not data and not self.handler.eof:
|
||||||
|
return None, nghttp2.DATA_DEFERRED
|
||||||
|
return data, nghttp2.DATA_EOF if self.handler.eof else nghttp2.DATA_OK
|
||||||
|
|
||||||
|
class Handler(nghttp2.BaseRequestHandler):
|
||||||
|
|
||||||
|
def on_headers(self):
|
||||||
|
body = Body(self)
|
||||||
|
asyncio.async(get_http_header(
|
||||||
|
self, 'http://localhost' + self.path.decode('utf-8')))
|
||||||
|
self.send_response(status=200, body=body.generate)
|
||||||
|
|
||||||
|
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||||
|
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
|
||||||
|
ctx.load_cert_chain('server.crt', 'server.key')
|
||||||
|
|
||||||
|
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
|
||||||
|
server.serve_forever()
|
||||||
|
|||||||
@@ -60,7 +60,10 @@ if ENABLE_ASIO_LIB
|
|||||||
|
|
||||||
noinst_PROGRAMS += asio-sv asio-sv2 asio-cl asio-cl2
|
noinst_PROGRAMS += asio-sv asio-sv2 asio-cl asio-cl2
|
||||||
|
|
||||||
ASIOCPPFLAGS = ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
|
# AM_CPPFLAGS must be placed first, so that header file (e.g.,
|
||||||
|
# nghttp2/nghttp2.h) in this package is used rather than installed
|
||||||
|
# one.
|
||||||
|
ASIOCPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
|
||||||
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
|
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
|
||||||
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
|
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
|
||||||
$(top_builddir)/third-party/libhttp-parser.la \
|
$(top_builddir)/third-party/libhttp-parser.la \
|
||||||
|
|||||||
@@ -258,8 +258,7 @@ static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
|
|||||||
stream), if it is closed, we send GOAWAY and tear down the
|
stream), if it is closed, we send GOAWAY and tear down the
|
||||||
session */
|
session */
|
||||||
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||||
uint32_t error_code,
|
uint32_t error_code, void *user_data) {
|
||||||
void *user_data) {
|
|
||||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ typedef enum {
|
|||||||
NGHTTP2_TOKEN__METHOD,
|
NGHTTP2_TOKEN__METHOD,
|
||||||
NGHTTP2_TOKEN__PATH,
|
NGHTTP2_TOKEN__PATH,
|
||||||
NGHTTP2_TOKEN__SCHEME,
|
NGHTTP2_TOKEN__SCHEME,
|
||||||
NGHTTP2_TOKEN_HOST,
|
NGHTTP2_TOKEN_HOST
|
||||||
} nghttp2_token;
|
} nghttp2_token;
|
||||||
|
|
||||||
/* Inspired by h2o header lookup. https://github.com/h2o/h2o */
|
/* Inspired by h2o header lookup. https://github.com/h2o/h2o */
|
||||||
@@ -658,19 +658,52 @@ static void stream_error(connection *conn, int32_t stream_id,
|
|||||||
error_code);
|
error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t fd_read_callback(nghttp2_session *session _U_,
|
static int send_data_callback(nghttp2_session *session _U_,
|
||||||
int32_t stream_id _U_, uint8_t *buf,
|
nghttp2_frame *frame, const uint8_t *framehd,
|
||||||
size_t length, uint32_t *data_flags,
|
size_t length, nghttp2_data_source *source,
|
||||||
nghttp2_data_source *source,
|
void *user_data) {
|
||||||
void *user_data _U_) {
|
connection *conn = user_data;
|
||||||
|
uint8_t *p = conn->buf.last;
|
||||||
stream *strm = source->ptr;
|
stream *strm = source->ptr;
|
||||||
ssize_t nread;
|
|
||||||
|
|
||||||
while ((nread = read(strm->filefd, buf, length)) == -1 && errno == EINTR)
|
/* We never use padding in this program */
|
||||||
|
assert(frame->data.padlen == 0);
|
||||||
|
|
||||||
|
if ((size_t)io_buf_left(&conn->buf) < 9 + frame->hd.length) {
|
||||||
|
return NGHTTP2_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(p, framehd, 9);
|
||||||
|
p += 9;
|
||||||
|
|
||||||
|
while (length) {
|
||||||
|
ssize_t nread;
|
||||||
|
while ((nread = read(strm->filefd, p, length)) == -1 && errno == EINTR)
|
||||||
;
|
;
|
||||||
if (nread == -1) {
|
if (nread == -1) {
|
||||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
length -= nread;
|
||||||
|
p += nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->buf.last = p;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t fd_read_callback(nghttp2_session *session _U_,
|
||||||
|
int32_t stream_id _U_, uint8_t *buf _U_,
|
||||||
|
size_t length, uint32_t *data_flags,
|
||||||
|
nghttp2_data_source *source,
|
||||||
|
void *user_data _U_) {
|
||||||
|
stream *strm = source->ptr;
|
||||||
|
ssize_t nread =
|
||||||
|
(int64_t)length < strm->fileleft ? (int64_t)length : strm->fileleft;
|
||||||
|
|
||||||
|
*data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
|
||||||
|
|
||||||
strm->fileleft -= nread;
|
strm->fileleft -= nread;
|
||||||
if (nread == 0 || strm->fileleft == 0) {
|
if (nread == 0 || strm->fileleft == 0) {
|
||||||
if (strm->fileleft != 0) {
|
if (strm->fileleft != 0) {
|
||||||
@@ -1274,6 +1307,8 @@ int main(int argc, char **argv) {
|
|||||||
shared_callbacks, on_stream_close_callback);
|
shared_callbacks, on_stream_close_callback);
|
||||||
nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||||
shared_callbacks, on_frame_not_send_callback);
|
shared_callbacks, on_frame_not_send_callback);
|
||||||
|
nghttp2_session_callbacks_set_send_data_callback(shared_callbacks,
|
||||||
|
send_data_callback);
|
||||||
|
|
||||||
rv = nghttp2_option_new(&shared_option);
|
rv = nghttp2_option_new(&shared_option);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ int lookup_token(const uint8_t *name, size_t namelen) {
|
|||||||
print '''\
|
print '''\
|
||||||
case {}:'''.format(size)
|
case {}:'''.format(size)
|
||||||
print '''\
|
print '''\
|
||||||
switch (name[namelen - 1]) {'''
|
switch (name[{}]) {{'''.format(size - 1)
|
||||||
for c in sorted(ents.keys()):
|
for c in sorted(ents.keys()):
|
||||||
headers = sorted(ents[c])
|
headers = sorted(ents[c])
|
||||||
print '''\
|
print '''\
|
||||||
|
|||||||
@@ -1,19 +1,72 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
HEADERS = [
|
HEADERS = [
|
||||||
':authority',
|
(':authority', 0),
|
||||||
':method',
|
(':method', 1),
|
||||||
':path',
|
(':method', 2),
|
||||||
':scheme',
|
(':path', 3),
|
||||||
':status',
|
(':path', 4),
|
||||||
"content-length",
|
(':scheme', 5),
|
||||||
"host",
|
(':scheme', 6),
|
||||||
"te",
|
(':status', 7),
|
||||||
'connection',
|
(':status', 8),
|
||||||
'keep-alive',
|
(':status', 9),
|
||||||
'proxy-connection',
|
(':status', 10),
|
||||||
'transfer-encoding',
|
(':status', 11),
|
||||||
'upgrade'
|
(':status', 12),
|
||||||
|
(':status', 13),
|
||||||
|
('accept-charset', 14),
|
||||||
|
('accept-encoding', 15),
|
||||||
|
('accept-language', 16),
|
||||||
|
('accept-ranges', 17),
|
||||||
|
('accept', 18),
|
||||||
|
('access-control-allow-origin', 19),
|
||||||
|
('age', 20),
|
||||||
|
('allow', 21),
|
||||||
|
('authorization', 22),
|
||||||
|
('cache-control', 23),
|
||||||
|
('content-disposition', 24),
|
||||||
|
('content-encoding', 25),
|
||||||
|
('content-language', 26),
|
||||||
|
('content-length', 27),
|
||||||
|
('content-location', 28),
|
||||||
|
('content-range', 29),
|
||||||
|
('content-type', 30),
|
||||||
|
('cookie', 31),
|
||||||
|
('date', 32),
|
||||||
|
('etag', 33),
|
||||||
|
('expect', 34),
|
||||||
|
('expires', 35),
|
||||||
|
('from', 36),
|
||||||
|
('host', 37),
|
||||||
|
('if-match', 38),
|
||||||
|
('if-modified-since', 39),
|
||||||
|
('if-none-match', 40),
|
||||||
|
('if-range', 41),
|
||||||
|
('if-unmodified-since', 42),
|
||||||
|
('last-modified', 43),
|
||||||
|
('link', 44),
|
||||||
|
('location', 45),
|
||||||
|
('max-forwards', 46),
|
||||||
|
('proxy-authenticate', 47),
|
||||||
|
('proxy-authorization', 48),
|
||||||
|
('range', 49),
|
||||||
|
('referer', 50),
|
||||||
|
('refresh', 51),
|
||||||
|
('retry-after', 52),
|
||||||
|
('server', 53),
|
||||||
|
('set-cookie', 54),
|
||||||
|
('strict-transport-security', 55),
|
||||||
|
('transfer-encoding', 56),
|
||||||
|
('user-agent', 57),
|
||||||
|
('vary', 58),
|
||||||
|
('via', 59),
|
||||||
|
('www-authenticate', 60),
|
||||||
|
('te', None),
|
||||||
|
('connection', None),
|
||||||
|
('keep-alive',None),
|
||||||
|
('proxy-connection', None),
|
||||||
|
('upgrade', None),
|
||||||
]
|
]
|
||||||
|
|
||||||
def to_enum_hd(k):
|
def to_enum_hd(k):
|
||||||
@@ -27,7 +80,7 @@ def to_enum_hd(k):
|
|||||||
|
|
||||||
def build_header(headers):
|
def build_header(headers):
|
||||||
res = {}
|
res = {}
|
||||||
for k in headers:
|
for k, _ in headers:
|
||||||
size = len(k)
|
size = len(k)
|
||||||
if size not in res:
|
if size not in res:
|
||||||
res[size] = {}
|
res[size] = {}
|
||||||
@@ -40,18 +93,20 @@ def build_header(headers):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def gen_enum():
|
def gen_enum():
|
||||||
print '''\
|
name = ''
|
||||||
typedef enum {'''
|
print 'typedef enum {'
|
||||||
for k in sorted(HEADERS):
|
for k, token in HEADERS:
|
||||||
print '''\
|
if token is None:
|
||||||
{},'''.format(to_enum_hd(k))
|
print ' {},'.format(to_enum_hd(k))
|
||||||
print '''\
|
else:
|
||||||
NGHTTP2_TOKEN_MAXIDX,
|
if name != k:
|
||||||
} nghttp2_token;'''
|
name = k
|
||||||
|
print ' {} = {},'.format(to_enum_hd(k), token)
|
||||||
|
print '} nghttp2_token;'
|
||||||
|
|
||||||
def gen_index_header():
|
def gen_index_header():
|
||||||
print '''\
|
print '''\
|
||||||
static int lookup_token(const uint8_t *name, size_t namelen) {
|
static inline int lookup_token(const uint8_t *name, size_t namelen) {
|
||||||
switch (namelen) {'''
|
switch (namelen) {'''
|
||||||
b = build_header(HEADERS)
|
b = build_header(HEADERS)
|
||||||
for size in sorted(b.keys()):
|
for size in sorted(b.keys()):
|
||||||
@@ -59,14 +114,14 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
|||||||
print '''\
|
print '''\
|
||||||
case {}:'''.format(size)
|
case {}:'''.format(size)
|
||||||
print '''\
|
print '''\
|
||||||
switch (name[namelen - 1]) {'''
|
switch (name[{}]) {{'''.format(size - 1)
|
||||||
for c in sorted(ents.keys()):
|
for c in sorted(ents.keys()):
|
||||||
headers = sorted(ents[c])
|
headers = sorted(ents[c])
|
||||||
print '''\
|
print '''\
|
||||||
case '{}':'''.format(c)
|
case '{}':'''.format(c)
|
||||||
for k in headers:
|
for k in headers:
|
||||||
print '''\
|
print '''\
|
||||||
if (streq("{}", name, {})) {{
|
if (lstreq("{}", name, {})) {{
|
||||||
return {};
|
return {};
|
||||||
}}'''.format(k[:-1], size - 1, to_enum_hd(k))
|
}}'''.format(k[:-1], size - 1, to_enum_hd(k))
|
||||||
print '''\
|
print '''\
|
||||||
|
|||||||
11
help2rst.py
11
help2rst.py
@@ -61,6 +61,8 @@ def help2man(infile):
|
|||||||
description.append(line)
|
description.append(line)
|
||||||
|
|
||||||
print '''
|
print '''
|
||||||
|
.. program:: {cmdname}
|
||||||
|
|
||||||
{cmdname}(1)
|
{cmdname}(1)
|
||||||
{cmdnameunderline}
|
{cmdnameunderline}
|
||||||
|
|
||||||
@@ -78,6 +80,7 @@ DESCRIPTION
|
|||||||
synopsis=synopsis, description=format_text('\n'.join(description)))
|
synopsis=synopsis, description=format_text('\n'.join(description)))
|
||||||
|
|
||||||
in_arg = False
|
in_arg = False
|
||||||
|
in_footer = False
|
||||||
|
|
||||||
for line in infile:
|
for line in infile:
|
||||||
line = line.rstrip()
|
line = line.rstrip()
|
||||||
@@ -95,6 +98,14 @@ DESCRIPTION
|
|||||||
print ''
|
print ''
|
||||||
in_arg = False
|
in_arg = False
|
||||||
|
|
||||||
|
if line == '--':
|
||||||
|
in_footer = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if in_footer:
|
||||||
|
print line.strip()
|
||||||
|
continue
|
||||||
|
|
||||||
if line == 'Options:':
|
if line == 'Options:':
|
||||||
print 'OPTIONS'
|
print 'OPTIONS'
|
||||||
print '-------'
|
print '-------'
|
||||||
|
|||||||
2
integration-tests/.gitignore
vendored
Normal file
2
integration-tests/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# generated files
|
||||||
|
config.go
|
||||||
@@ -246,6 +246,72 @@ func TestH1H1RequestTrailer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH1H1HeaderFieldBufferPath tests that request with request path
|
||||||
|
// larger than configured buffer size is rejected.
|
||||||
|
func TestH1H1HeaderFieldBufferPath(t *testing.T) {
|
||||||
|
// The value 100 is chosen so that sum of header fields bytes
|
||||||
|
// does not exceed it. We use > 100 bytes URI to exceed this
|
||||||
|
// limit.
|
||||||
|
st := newServerTester([]string{"--header-field-buffer=100"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
t.Fatal("execution path should not be here")
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http1(requestParam{
|
||||||
|
name: "TestH1H1HeaderFieldBufferPath",
|
||||||
|
path: "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http1() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 431; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH1H1HeaderFieldBuffer tests that request with header fields
|
||||||
|
// larger than configured buffer size is rejected.
|
||||||
|
func TestH1H1HeaderFieldBuffer(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
t.Fatal("execution path should not be here")
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http1(requestParam{
|
||||||
|
name: "TestH1H1HeaderFieldBuffer",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http1() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 431; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH1H1HeaderFields tests that request with header fields more
|
||||||
|
// than configured number is rejected.
|
||||||
|
func TestH1H1HeaderFields(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
t.Fatal("execution path should not be here")
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http1(requestParam{
|
||||||
|
name: "TestH1H1HeaderFields",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
// Add extra header field to ensure that
|
||||||
|
// header field limit exceeds
|
||||||
|
pair("Connection", "close"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http1() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 431; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH1H2ConnectFailure tests that server handles the situation that
|
// TestH1H2ConnectFailure tests that server handles the situation that
|
||||||
// connection attempt to HTTP/2 backend failed.
|
// connection attempt to HTTP/2 backend failed.
|
||||||
func TestH1H2ConnectFailure(t *testing.T) {
|
func TestH1H2ConnectFailure(t *testing.T) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -494,7 +495,9 @@ func TestH2H1SNI(t *testing.T) {
|
|||||||
func TestH2H1ServerPush(t *testing.T) {
|
func TestH2H1ServerPush(t *testing.T) {
|
||||||
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
// only resources marked as rel=preload are pushed
|
// only resources marked as rel=preload are pushed
|
||||||
|
if !strings.HasPrefix(r.URL.Path, "/css/") {
|
||||||
w.Header().Add("Link", "</css/main.css>; rel=preload, </foo>, </css/theme.css>; rel=preload")
|
w.Header().Add("Link", "</css/main.css>; rel=preload, </foo>, </css/theme.css>; rel=preload")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
|
|
||||||
@@ -555,6 +558,79 @@ func TestH2H1RequestTrailer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H1HeaderFieldBuffer tests that request with header fields
|
||||||
|
// larger than configured buffer size is rejected.
|
||||||
|
func TestH2H1HeaderFieldBuffer(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
t.Fatal("execution path should not be here")
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1HeaderFieldBuffer",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 431; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1HeaderFields tests that request with header fields more
|
||||||
|
// than configured number is rejected.
|
||||||
|
func TestH2H1HeaderFields(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
t.Fatal("execution path should not be here")
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1HeaderFields",
|
||||||
|
// we have at least 4 pseudo-header fields sent, and
|
||||||
|
// that ensures that buffer limit exceeds.
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 431; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1Upgrade tests HTTP Upgrade to HTTP/2
|
||||||
|
func TestH2H1Upgrade(t *testing.T) {
|
||||||
|
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http1(requestParam{
|
||||||
|
name: "TestH2H1Upgrade",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("Connection", "Upgrade, HTTP2-Settings"),
|
||||||
|
pair("Upgrade", "h2c-14"),
|
||||||
|
pair("HTTP2-Settings", "AAMAAABkAAQAAP__"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http1() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 101; got != want {
|
||||||
|
t.Errorf("res.status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = st.http2(requestParam{
|
||||||
|
httpUpgrade: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("res.status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2H1GracefulShutdown tests graceful shutdown.
|
// TestH2H1GracefulShutdown tests graceful shutdown.
|
||||||
func TestH2H1GracefulShutdown(t *testing.T) {
|
func TestH2H1GracefulShutdown(t *testing.T) {
|
||||||
st := newServerTester(nil, t, noopHandler)
|
st := newServerTester(nil, t, noopHandler)
|
||||||
|
|||||||
@@ -170,6 +170,46 @@ func TestS3H1NoVia(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestS3H1HeaderFieldBuffer tests that request with header fields
|
||||||
|
// larger than configured buffer size is rejected.
|
||||||
|
func TestS3H1HeaderFieldBuffer(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
t.Fatal("execution path should not be here")
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.spdy(requestParam{
|
||||||
|
name: "TestS3H1HeaderFieldBuffer",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.spdy() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.spdyRstErrCode, spdy.InternalError; got != want {
|
||||||
|
t.Errorf("res.spdyRstErrCode: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestS3H1HeaderFields tests that request with header fields more
|
||||||
|
// than configured number is rejected.
|
||||||
|
func TestS3H1HeaderFields(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
t.Fatal("execution path should not be here")
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.spdy(requestParam{
|
||||||
|
name: "TestS3H1HeaderFields",
|
||||||
|
// we have at least 5 pseudo-header fields sent, and
|
||||||
|
// that ensures that buffer limit exceeds.
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.spdy() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.spdyRstErrCode, spdy.InternalError; got != want {
|
||||||
|
t.Errorf("res.spdyRstErrCode: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestS3H2ConnectFailure tests that server handles the situation that
|
// TestS3H2ConnectFailure tests that server handles the situation that
|
||||||
// connection attempt to HTTP/2 backend failed.
|
// connection attempt to HTTP/2 backend failed.
|
||||||
func TestS3H2ConnectFailure(t *testing.T) {
|
func TestS3H2ConnectFailure(t *testing.T) {
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ type requestParam struct {
|
|||||||
header []hpack.HeaderField // additional request header fields
|
header []hpack.HeaderField // additional request header fields
|
||||||
body []byte // request body
|
body []byte // request body
|
||||||
trailer []hpack.HeaderField // trailer part
|
trailer []hpack.HeaderField // trailer part
|
||||||
|
httpUpgrade bool // true if upgraded to HTTP/2 through HTTP Upgrade
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrapper for request body to set trailer part
|
// wrapper for request body to set trailer part
|
||||||
@@ -296,7 +297,19 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
|
|||||||
body = cbr
|
body = cbr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req, err := http.NewRequest(method, st.url, body)
|
|
||||||
|
reqURL := st.url
|
||||||
|
|
||||||
|
if rp.path != "" {
|
||||||
|
u, err := url.Parse(st.url)
|
||||||
|
if err != nil {
|
||||||
|
st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err)
|
||||||
|
}
|
||||||
|
u.Path = rp.path
|
||||||
|
reqURL = u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, reqURL, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -478,6 +491,7 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
|
|||||||
streams := make(map[uint32]*serverResponse)
|
streams := make(map[uint32]*serverResponse)
|
||||||
streams[id] = res
|
streams[id] = res
|
||||||
|
|
||||||
|
if !rp.httpUpgrade {
|
||||||
method := "GET"
|
method := "GET"
|
||||||
if rp.method != "" {
|
if rp.method != "" {
|
||||||
method = rp.method
|
method = rp.method
|
||||||
@@ -540,7 +554,7 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
loop:
|
loop:
|
||||||
for {
|
for {
|
||||||
fr, err := st.readFrame()
|
fr, err := st.readFrame()
|
||||||
|
|||||||
3
lib/.gitignore
vendored
Normal file
3
lib/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# generated files
|
||||||
|
includes/nghttp2/nghttp2ver.h
|
||||||
|
libnghttp2.pc
|
||||||
@@ -2,15 +2,14 @@
|
|||||||
# GNU Makefile for nghttp2 / MSVC.
|
# GNU Makefile for nghttp2 / MSVC.
|
||||||
#
|
#
|
||||||
# By G. Vanem <gvanem@yahoo.no> 2013
|
# By G. Vanem <gvanem@yahoo.no> 2013
|
||||||
|
# Updated 3/2015 by Remo Eichenberger @remoe
|
||||||
# The MIT License apply.
|
# The MIT License apply.
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
# Choose your weapons:
|
# Choose your weapons:
|
||||||
# Set 'ZLIB_ROOT' to the root of zlib.
|
|
||||||
# Set 'USE_CYTHON=1' to build and install the 'nghttp2.pyd' Python extension.
|
# 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
|
USE_CYTHON = 1
|
||||||
|
|
||||||
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV], //g')
|
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV], //g')
|
||||||
@@ -38,7 +37,7 @@ INSTALL_HDR = $(VC_ROOT)/include
|
|||||||
TARGETS = nghttp2.lib nghttp2.dll nghttp2_imp.lib \
|
TARGETS = nghttp2.lib nghttp2.dll nghttp2_imp.lib \
|
||||||
nghttp2d.lib nghttp2d.dll nghttp2d_imp.lib
|
nghttp2d.lib nghttp2d.dll nghttp2d_imp.lib
|
||||||
|
|
||||||
EXT_LIBS = $(ZLIB_ROOT)/zlib.lib ws2_32.lib
|
EXT_LIBS =
|
||||||
|
|
||||||
OBJ_DIR = MSVC_obj
|
OBJ_DIR = MSVC_obj
|
||||||
|
|
||||||
@@ -46,32 +45,34 @@ NGHTTP2_PDB_R = $(OBJ_DIR)/nghttp2.pdb
|
|||||||
NGHTTP2_PDB_D = $(OBJ_DIR)/nghttp2d.pdb
|
NGHTTP2_PDB_D = $(OBJ_DIR)/nghttp2d.pdb
|
||||||
|
|
||||||
CC = cl
|
CC = cl
|
||||||
CFLAGS = -I./includes -I$(ZLIB_ROOT) -DHAVE_WINSOCK2_H -Dssize_t=long
|
CFLAGS = -I./includes -Dssize_t=long -D_U_=""
|
||||||
|
|
||||||
CFLAGS_R = -nologo -MD -W3 -Zi -Fd./$(NGHTTP2_PDB_R)
|
CFLAGS_R = -nologo -MD -W3 -Zi -Fd./$(NGHTTP2_PDB_R)
|
||||||
CFLAGS_D = -nologo -MDd -W3 -Zi -Fd./$(NGHTTP2_PDB_D) \
|
CFLAGS_D = -nologo -MDd -W3 -Zi -Fd./$(NGHTTP2_PDB_D) \
|
||||||
-Ot -D_DEBUG -GF -RTCs -RTCu # -RTCc -GS
|
-Ot -D_DEBUG -GF -RTCs -RTCu # -RTCc -GS
|
||||||
|
|
||||||
LDFLAGS = -nologo -machine:i386 -map -debug -incremental:no # -verbose
|
LDFLAGS = -nologo -machine:x64 -map -debug -incremental:no # -verbose
|
||||||
|
|
||||||
NGHTTP2_SRC = nghttp2_buf.c \
|
NGHTTP2_SRC = nghttp2_pq.c \
|
||||||
nghttp2_callbacks.c \
|
nghttp2_map.c \
|
||||||
|
nghttp2_queue.c \
|
||||||
nghttp2_frame.c \
|
nghttp2_frame.c \
|
||||||
|
nghttp2_buf.c \
|
||||||
|
nghttp2_stream.c \
|
||||||
|
nghttp2_outbound_item.c \
|
||||||
|
nghttp2_session.c \
|
||||||
|
nghttp2_submit.c \
|
||||||
nghttp2_helper.c \
|
nghttp2_helper.c \
|
||||||
|
nghttp2_npn.c \
|
||||||
nghttp2_hd.c \
|
nghttp2_hd.c \
|
||||||
nghttp2_hd_huffman.c \
|
nghttp2_hd_huffman.c \
|
||||||
nghttp2_hd_huffman_data.c \
|
nghttp2_hd_huffman_data.c \
|
||||||
nghttp2_map.c \
|
nghttp2_version.c \
|
||||||
nghttp2_npn.c \
|
|
||||||
nghttp2_option.c \
|
|
||||||
nghttp2_outbound_item.c \
|
|
||||||
nghttp2_priority_spec.c \
|
nghttp2_priority_spec.c \
|
||||||
nghttp2_pq.c \
|
nghttp2_option.c \
|
||||||
nghttp2_queue.c \
|
nghttp2_callbacks.c \
|
||||||
nghttp2_session.c \
|
nghttp2_mem.c \
|
||||||
nghttp2_stream.c \
|
nghttp2_http.c
|
||||||
nghttp2_submit.c \
|
|
||||||
nghttp2_version.c
|
|
||||||
|
|
||||||
NGHTTP2_OBJ_R = $(addprefix $(OBJ_DIR)/r_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
NGHTTP2_OBJ_R = $(addprefix $(OBJ_DIR)/r_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
||||||
NGHTTP2_OBJ_D = $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
NGHTTP2_OBJ_D = $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
||||||
@@ -116,13 +117,13 @@ nghttp2d.lib: $(NGHTTP2_OBJ_D)
|
|||||||
lib -nologo -out:$@ $^
|
lib -nologo -out:$@ $^
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
nghttp2.dll nghttp2_imp.lib: $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(OBJ_DIR)/r_nghttp2.def
|
nghttp2.dll nghttp2_imp.lib: $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res
|
||||||
link $(LDFLAGS) -dll -out:nghttp2.dll -implib:nghttp2_imp.lib -def:$(OBJ_DIR)/r_nghttp2.def \
|
link $(LDFLAGS) -dll -out:nghttp2.dll -implib:nghttp2_imp.lib \
|
||||||
$(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(EXT_LIBS)
|
$(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(EXT_LIBS)
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
nghttp2d.dll nghttp2d_imp.lib: $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(OBJ_DIR)/d_nghttp2.def
|
nghttp2d.dll nghttp2d_imp.lib: $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res
|
||||||
link $(LDFLAGS) -dll -out:nghttp2d.dll -implib:nghttp2d_imp.lib -def:$(OBJ_DIR)/d_nghttp2.def \
|
link $(LDFLAGS) -dll -out:nghttp2d.dll -implib:nghttp2d_imp.lib \
|
||||||
$(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(EXT_LIBS)
|
$(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(EXT_LIBS)
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
@@ -219,24 +220,6 @@ nghttp2.rc: Makefile.MSVC
|
|||||||
@echo ' */' >> $@
|
@echo ' */' >> $@
|
||||||
@echo "$$RES_FILE" >> $@
|
@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:
|
clean:
|
||||||
rm -f $(OBJ_DIR)/* nghttp2_imp.exp nghttp2_imp.exp \
|
rm -f $(OBJ_DIR)/* nghttp2_imp.exp nghttp2_imp.exp \
|
||||||
nghttp2.map nghttp2d.map nghttp2.rc includes/nghttp2/nghttp2ver.h
|
nghttp2.map nghttp2d.map nghttp2.rc includes/nghttp2/nghttp2ver.h
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -410,36 +410,46 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
|
|||||||
len += nghttp2_buf_len(&chain->buf);
|
len += nghttp2_buf_len(&chain->buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!len) {
|
if (len == 0) {
|
||||||
res = NULL;
|
res = NULL;
|
||||||
} else {
|
return 0;
|
||||||
res = nghttp2_mem_malloc(bufs->mem, len);
|
}
|
||||||
|
|
||||||
|
res = nghttp2_mem_malloc(bufs->mem, len);
|
||||||
if (res == NULL) {
|
if (res == NULL) {
|
||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
nghttp2_buf_wrap_init(&resbuf, res, len);
|
nghttp2_buf_wrap_init(&resbuf, res, len);
|
||||||
|
|
||||||
for (chain = bufs->head; chain; chain = chain->next) {
|
for (chain = bufs->head; chain; chain = chain->next) {
|
||||||
buf = &chain->buf;
|
buf = &chain->buf;
|
||||||
|
|
||||||
if (resbuf.last) {
|
|
||||||
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
|
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_buf_reset(buf);
|
|
||||||
nghttp2_buf_shift_right(&chain->buf, bufs->offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
bufs->cur = bufs->head;
|
|
||||||
|
|
||||||
*out = res;
|
*out = res;
|
||||||
|
|
||||||
return (ssize_t)len;
|
return (ssize_t)len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) {
|
||||||
|
size_t len;
|
||||||
|
nghttp2_buf_chain *chain;
|
||||||
|
nghttp2_buf *buf;
|
||||||
|
nghttp2_buf resbuf;
|
||||||
|
|
||||||
|
len = nghttp2_bufs_len(bufs);
|
||||||
|
|
||||||
|
nghttp2_buf_wrap_init(&resbuf, out, len);
|
||||||
|
|
||||||
|
for (chain = bufs->head; chain; chain = chain->next) {
|
||||||
|
buf = &chain->buf;
|
||||||
|
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
|
void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
|
||||||
nghttp2_buf_chain *chain, *ci;
|
nghttp2_buf_chain *chain, *ci;
|
||||||
size_t k;
|
size_t k;
|
||||||
|
|||||||
@@ -313,9 +313,8 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
|
|||||||
* function allocates the contagious memory to store all data in
|
* function allocates the contagious memory to store all data in
|
||||||
* |bufs| and assigns it to |*out|.
|
* |bufs| and assigns it to |*out|.
|
||||||
*
|
*
|
||||||
* On successful return, nghttp2_bufs_len(bufs) returns 0, just like
|
* The contents of |bufs| is left unchanged.
|
||||||
* after calling nghttp2_bufs_reset().
|
*
|
||||||
|
|
||||||
* This function returns the length of copied data and assigns the
|
* This function returns the length of copied data and assigns the
|
||||||
* pointer to copied data to |*out| if it succeeds, or one of the
|
* pointer to copied data to |*out| if it succeeds, or one of the
|
||||||
* following negative error codes:
|
* following negative error codes:
|
||||||
@@ -325,6 +324,17 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
|
|||||||
*/
|
*/
|
||||||
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
|
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copies all data stored in |bufs| to |out|. This function assumes
|
||||||
|
* that the buffer space pointed by |out| has at least
|
||||||
|
* nghttp2_bufs(bufs) bytes.
|
||||||
|
*
|
||||||
|
* The contents of |bufs| is left unchanged.
|
||||||
|
*
|
||||||
|
* This function returns the length of copied data.
|
||||||
|
*/
|
||||||
|
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resets |bufs| and makes the buffers empty.
|
* Resets |bufs| and makes the buffers empty.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -121,3 +121,9 @@ void nghttp2_session_callbacks_set_on_begin_frame_callback(
|
|||||||
nghttp2_on_begin_frame_callback on_begin_frame_callback) {
|
nghttp2_on_begin_frame_callback on_begin_frame_callback) {
|
||||||
cbs->on_begin_frame_callback = on_begin_frame_callback;
|
cbs->on_begin_frame_callback = on_begin_frame_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nghttp2_session_callbacks_set_send_data_callback(
|
||||||
|
nghttp2_session_callbacks *cbs,
|
||||||
|
nghttp2_send_data_callback send_data_callback) {
|
||||||
|
cbs->send_data_callback = send_data_callback;
|
||||||
|
}
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ struct nghttp2_session_callbacks {
|
|||||||
* Sets callback function invoked when a frame header is received.
|
* Sets callback function invoked when a frame header is received.
|
||||||
*/
|
*/
|
||||||
nghttp2_on_begin_frame_callback on_begin_frame_callback;
|
nghttp2_on_begin_frame_callback on_begin_frame_callback;
|
||||||
|
nghttp2_send_data_callback send_data_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* NGHTTP2_CALLBACKS_H */
|
#endif /* NGHTTP2_CALLBACKS_H */
|
||||||
|
|||||||
@@ -739,7 +739,8 @@ int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
|
|||||||
nghttp2_nv *p;
|
nghttp2_nv *p;
|
||||||
|
|
||||||
for (i = 0; i < nvlen; ++i) {
|
for (i = 0; i < nvlen; ++i) {
|
||||||
buflen += nva[i].namelen + nva[i].valuelen;
|
/* + 2 for null-termination */
|
||||||
|
buflen += nva[i].namelen + nva[i].valuelen + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nvlen == 0) {
|
if (nvlen == 0) {
|
||||||
@@ -765,12 +766,14 @@ int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
|
|||||||
memcpy(data, nva[i].name, nva[i].namelen);
|
memcpy(data, nva[i].name, nva[i].namelen);
|
||||||
p->name = data;
|
p->name = data;
|
||||||
p->namelen = nva[i].namelen;
|
p->namelen = nva[i].namelen;
|
||||||
|
data[p->namelen] = '\0';
|
||||||
nghttp2_downcase(p->name, p->namelen);
|
nghttp2_downcase(p->name, p->namelen);
|
||||||
data += nva[i].namelen;
|
data += nva[i].namelen + 1;
|
||||||
memcpy(data, nva[i].value, nva[i].valuelen);
|
memcpy(data, nva[i].value, nva[i].valuelen);
|
||||||
p->value = data;
|
p->value = data;
|
||||||
p->valuelen = nva[i].valuelen;
|
p->valuelen = nva[i].valuelen;
|
||||||
data += nva[i].valuelen;
|
data[p->valuelen] = '\0';
|
||||||
|
data += nva[i].valuelen + 1;
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -810,7 +813,7 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
|
static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) {
|
||||||
size_t trail_padlen;
|
size_t trail_padlen;
|
||||||
size_t newlen;
|
size_t newlen;
|
||||||
|
|
||||||
@@ -825,6 +828,10 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
|
|||||||
newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen;
|
newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen;
|
||||||
nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3]));
|
nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3]));
|
||||||
|
|
||||||
|
if (framehd_only) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
trail_padlen = padlen - 1;
|
trail_padlen = padlen - 1;
|
||||||
buf->pos[NGHTTP2_FRAME_HDLEN] = trail_padlen;
|
buf->pos[NGHTTP2_FRAME_HDLEN] = trail_padlen;
|
||||||
|
|
||||||
@@ -833,12 +840,10 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
|
|||||||
/* extend buffers trail_padlen bytes, since we ate previous padlen -
|
/* extend buffers trail_padlen bytes, since we ate previous padlen -
|
||||||
trail_padlen byte(s) */
|
trail_padlen byte(s) */
|
||||||
buf->last += trail_padlen;
|
buf->last += trail_padlen;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||||
size_t padlen) {
|
size_t padlen, int framehd_only) {
|
||||||
nghttp2_buf *buf;
|
nghttp2_buf *buf;
|
||||||
|
|
||||||
if (padlen == 0) {
|
if (padlen == 0) {
|
||||||
@@ -871,7 +876,7 @@ int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
|||||||
|
|
||||||
assert(nghttp2_buf_avail(buf) >= (ssize_t)padlen - 1);
|
assert(nghttp2_buf_avail(buf) >= (ssize_t)padlen - 1);
|
||||||
|
|
||||||
frame_set_pad(buf, padlen);
|
frame_set_pad(buf, padlen, framehd_only);
|
||||||
|
|
||||||
hd->length += padlen;
|
hd->length += padlen;
|
||||||
hd->flags |= NGHTTP2_FLAG_PADDED;
|
hd->flags |= NGHTTP2_FLAG_PADDED;
|
||||||
|
|||||||
@@ -471,7 +471,9 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
|
|||||||
/*
|
/*
|
||||||
* Copies name/value pairs from |nva|, which contains |nvlen| pairs,
|
* Copies name/value pairs from |nva|, which contains |nvlen| pairs,
|
||||||
* to |*nva_ptr|, which is dynamically allocated so that all items can
|
* to |*nva_ptr|, which is dynamically allocated so that all items can
|
||||||
* be stored.
|
* be stored. The resultant name and value in nghttp2_nv are
|
||||||
|
* guaranteed to be NULL-terminated even if the input is not
|
||||||
|
* null-terminated.
|
||||||
*
|
*
|
||||||
* The |*nva_ptr| must be freed using nghttp2_nv_array_del().
|
* The |*nva_ptr| must be freed using nghttp2_nv_array_del().
|
||||||
*
|
*
|
||||||
@@ -508,7 +510,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
|
|||||||
* Sets Pad Length field and flags and adjusts frame header position
|
* Sets Pad Length field and flags and adjusts frame header position
|
||||||
* of each buffers in |bufs|. The number of padding is given in the
|
* of each buffers in |bufs|. The number of padding is given in the
|
||||||
* |padlen| including Pad Length field. The |hd| is the frame header
|
* |padlen| including Pad Length field. The |hd| is the frame header
|
||||||
* for the serialized data.
|
* for the serialized data. This function fills zeros padding region
|
||||||
|
* unless framehd_only is nonzero.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
* negative error codes:
|
* negative error codes:
|
||||||
@@ -519,6 +522,6 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
|
|||||||
* The length of the resulting frame is too large.
|
* The length of the resulting frame is too large.
|
||||||
*/
|
*/
|
||||||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||||
size_t padlen);
|
size_t padlen, int framehd_only);
|
||||||
|
|
||||||
#endif /* NGHTTP2_FRAME_H */
|
#endif /* NGHTTP2_FRAME_H */
|
||||||
|
|||||||
986
lib/nghttp2_hd.c
986
lib/nghttp2_hd.c
File diff suppressed because it is too large
Load Diff
106
lib/nghttp2_hd.h
106
lib/nghttp2_hd.h
@@ -49,7 +49,68 @@
|
|||||||
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
|
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
|
||||||
|
|
||||||
/* Exported for unit test */
|
/* Exported for unit test */
|
||||||
extern const size_t NGHTTP2_STATIC_TABLE_LENGTH;
|
#define NGHTTP2_STATIC_TABLE_LENGTH 61
|
||||||
|
|
||||||
|
/* Generated by genlibtokenlookup.py */
|
||||||
|
typedef enum {
|
||||||
|
NGHTTP2_TOKEN__AUTHORITY = 0,
|
||||||
|
NGHTTP2_TOKEN__METHOD = 1,
|
||||||
|
NGHTTP2_TOKEN__PATH = 3,
|
||||||
|
NGHTTP2_TOKEN__SCHEME = 5,
|
||||||
|
NGHTTP2_TOKEN__STATUS = 7,
|
||||||
|
NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
|
||||||
|
NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
|
||||||
|
NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
|
||||||
|
NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
|
||||||
|
NGHTTP2_TOKEN_ACCEPT = 18,
|
||||||
|
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
|
||||||
|
NGHTTP2_TOKEN_AGE = 20,
|
||||||
|
NGHTTP2_TOKEN_ALLOW = 21,
|
||||||
|
NGHTTP2_TOKEN_AUTHORIZATION = 22,
|
||||||
|
NGHTTP2_TOKEN_CACHE_CONTROL = 23,
|
||||||
|
NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
|
||||||
|
NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
|
||||||
|
NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
|
||||||
|
NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
|
||||||
|
NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
|
||||||
|
NGHTTP2_TOKEN_CONTENT_RANGE = 29,
|
||||||
|
NGHTTP2_TOKEN_CONTENT_TYPE = 30,
|
||||||
|
NGHTTP2_TOKEN_COOKIE = 31,
|
||||||
|
NGHTTP2_TOKEN_DATE = 32,
|
||||||
|
NGHTTP2_TOKEN_ETAG = 33,
|
||||||
|
NGHTTP2_TOKEN_EXPECT = 34,
|
||||||
|
NGHTTP2_TOKEN_EXPIRES = 35,
|
||||||
|
NGHTTP2_TOKEN_FROM = 36,
|
||||||
|
NGHTTP2_TOKEN_HOST = 37,
|
||||||
|
NGHTTP2_TOKEN_IF_MATCH = 38,
|
||||||
|
NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
|
||||||
|
NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
|
||||||
|
NGHTTP2_TOKEN_IF_RANGE = 41,
|
||||||
|
NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
|
||||||
|
NGHTTP2_TOKEN_LAST_MODIFIED = 43,
|
||||||
|
NGHTTP2_TOKEN_LINK = 44,
|
||||||
|
NGHTTP2_TOKEN_LOCATION = 45,
|
||||||
|
NGHTTP2_TOKEN_MAX_FORWARDS = 46,
|
||||||
|
NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
|
||||||
|
NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
|
||||||
|
NGHTTP2_TOKEN_RANGE = 49,
|
||||||
|
NGHTTP2_TOKEN_REFERER = 50,
|
||||||
|
NGHTTP2_TOKEN_REFRESH = 51,
|
||||||
|
NGHTTP2_TOKEN_RETRY_AFTER = 52,
|
||||||
|
NGHTTP2_TOKEN_SERVER = 53,
|
||||||
|
NGHTTP2_TOKEN_SET_COOKIE = 54,
|
||||||
|
NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
|
||||||
|
NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
|
||||||
|
NGHTTP2_TOKEN_USER_AGENT = 57,
|
||||||
|
NGHTTP2_TOKEN_VARY = 58,
|
||||||
|
NGHTTP2_TOKEN_VIA = 59,
|
||||||
|
NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
|
||||||
|
NGHTTP2_TOKEN_TE,
|
||||||
|
NGHTTP2_TOKEN_CONNECTION,
|
||||||
|
NGHTTP2_TOKEN_KEEP_ALIVE,
|
||||||
|
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
||||||
|
NGHTTP2_TOKEN_UPGRADE
|
||||||
|
} nghttp2_token;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NGHTTP2_HD_FLAG_NONE = 0,
|
NGHTTP2_HD_FLAG_NONE = 0,
|
||||||
@@ -67,18 +128,14 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nghttp2_nv nv;
|
nghttp2_nv nv;
|
||||||
uint32_t name_hash;
|
/* nghttp2_token value for nv.name. It could be -1 if we have no
|
||||||
uint32_t value_hash;
|
token for that header field name. */
|
||||||
|
int token;
|
||||||
/* Reference count */
|
/* Reference count */
|
||||||
uint8_t ref;
|
uint8_t ref;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
} nghttp2_hd_entry;
|
} nghttp2_hd_entry;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
nghttp2_hd_entry ent;
|
|
||||||
size_t index;
|
|
||||||
} nghttp2_hd_static_entry;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nghttp2_hd_entry **buffer;
|
nghttp2_hd_entry **buffer;
|
||||||
size_t mask;
|
size_t mask;
|
||||||
@@ -107,6 +164,12 @@ typedef enum {
|
|||||||
NGHTTP2_HD_STATE_READ_VALUE
|
NGHTTP2_HD_STATE_READ_VALUE
|
||||||
} nghttp2_hd_inflate_state;
|
} nghttp2_hd_inflate_state;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NGHTTP2_HD_WITH_INDEXING,
|
||||||
|
NGHTTP2_HD_WITHOUT_INDEXING,
|
||||||
|
NGHTTP2_HD_NEVER_INDEXING
|
||||||
|
} nghttp2_hd_indexing_mode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* dynamic header table */
|
/* dynamic header table */
|
||||||
nghttp2_hd_ringbuf hd_table;
|
nghttp2_hd_ringbuf hd_table;
|
||||||
@@ -176,9 +239,8 @@ struct nghttp2_hd_inflater {
|
|||||||
* set in the |flags|, the content pointed by the |name| with length
|
* set in the |flags|, the content pointed by the |name| with length
|
||||||
* |namelen| is copied. Likewise, if NGHTTP2_HD_FLAG_VALUE_ALLOC bit
|
* |namelen| is copied. Likewise, if NGHTTP2_HD_FLAG_VALUE_ALLOC bit
|
||||||
* set in the |flags|, the content pointed by the |value| with length
|
* set in the |flags|, the content pointed by the |value| with length
|
||||||
* |valuelen| is copied. The |name_hash| and |value_hash| are hash
|
* |valuelen| is copied. The |token| is enum number looked up by
|
||||||
* value for |name| and |value| respectively. The hash function is
|
* |name|. It could be -1 if we don't have that enum value.
|
||||||
* defined in nghttp2_hd.c.
|
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
* negative error codes:
|
* negative error codes:
|
||||||
@@ -188,8 +250,7 @@ struct nghttp2_hd_inflater {
|
|||||||
*/
|
*/
|
||||||
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
|
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
|
||||||
size_t namelen, uint8_t *value, size_t valuelen,
|
size_t namelen, uint8_t *value, size_t valuelen,
|
||||||
uint32_t name_hash, uint32_t value_hash,
|
int token, nghttp2_mem *mem);
|
||||||
nghttp2_mem *mem);
|
|
||||||
|
|
||||||
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent, nghttp2_mem *mem);
|
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent, nghttp2_mem *mem);
|
||||||
|
|
||||||
@@ -271,13 +332,25 @@ int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
|
|||||||
*/
|
*/
|
||||||
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
|
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Similar to nghttp2_hd_inflate_hd(), but this takes additional
|
||||||
|
* output parameter |token|. On successful header emission, it
|
||||||
|
* contains nghttp2_token value for nv_out->name. It could be -1 if
|
||||||
|
* we don't have enum value for the name. Other than that return
|
||||||
|
* values and semantics are the same as nghttp2_hd_inflate_hd().
|
||||||
|
*/
|
||||||
|
ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
|
||||||
|
nghttp2_nv *nv_out, int *inflate_flags,
|
||||||
|
int *token, uint8_t *in, size_t inlen,
|
||||||
|
int in_final);
|
||||||
|
|
||||||
/* For unittesting purpose */
|
/* For unittesting purpose */
|
||||||
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
|
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
|
||||||
nghttp2_nv *nv, int inc_indexing);
|
nghttp2_nv *nv, int indexing_mode);
|
||||||
|
|
||||||
/* For unittesting purpose */
|
/* For unittesting purpose */
|
||||||
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
||||||
int inc_indexing);
|
int indexing_mode);
|
||||||
|
|
||||||
/* For unittesting purpose */
|
/* For unittesting purpose */
|
||||||
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
|
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
|
||||||
@@ -324,8 +397,7 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
|
|||||||
* be initialized by nghttp2_hd_huff_decode_context_init(). The result
|
* be initialized by nghttp2_hd_huff_decode_context_init(). The result
|
||||||
* will be added to |dest|. This function may expand |dest| as
|
* will be added to |dest|. This function may expand |dest| as
|
||||||
* needed. The caller is responsible to release the memory of |dest|
|
* needed. The caller is responsible to release the memory of |dest|
|
||||||
* by calling nghttp2_bufs_free() or export its content using
|
* by calling nghttp2_bufs_free().
|
||||||
* nghttp2_bufs_remove().
|
|
||||||
*
|
*
|
||||||
* The caller must set the |final| to nonzero if the given input is
|
* The caller must set the |final| to nonzero if the given input is
|
||||||
* the final block.
|
* the final block.
|
||||||
|
|||||||
@@ -168,10 +168,27 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
|
|||||||
ctx->accept = 1;
|
ctx->accept = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Use macro to make the code simpler..., but error case is tricky.
|
||||||
|
We spent most of the CPU in decoding, so we are doing this
|
||||||
|
thing. */
|
||||||
|
#define hd_huff_decode_sym_emit(bufs, sym, avail) \
|
||||||
|
do { \
|
||||||
|
if ((avail)) { \
|
||||||
|
nghttp2_bufs_fast_addb((bufs), (sym)); \
|
||||||
|
--(avail); \
|
||||||
|
} else { \
|
||||||
|
rv = nghttp2_bufs_addb((bufs), (sym)); \
|
||||||
|
if (rv != 0) { \
|
||||||
|
return rv; \
|
||||||
|
} \
|
||||||
|
(avail) = nghttp2_bufs_cur_avail((bufs)); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||||
nghttp2_bufs *bufs, const uint8_t *src,
|
nghttp2_bufs *bufs, const uint8_t *src,
|
||||||
size_t srclen, int final) {
|
size_t srclen, int final) {
|
||||||
size_t i, j;
|
size_t i;
|
||||||
int rv;
|
int rv;
|
||||||
size_t avail;
|
size_t avail;
|
||||||
|
|
||||||
@@ -180,30 +197,28 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
|||||||
/* We use the decoding algorithm described in
|
/* We use the decoding algorithm described in
|
||||||
http://graphics.ics.uci.edu/pub/Prefix.pdf */
|
http://graphics.ics.uci.edu/pub/Prefix.pdf */
|
||||||
for (i = 0; i < srclen; ++i) {
|
for (i = 0; i < srclen; ++i) {
|
||||||
uint8_t in = src[i] >> 4;
|
|
||||||
for (j = 0; j < 2; ++j) {
|
|
||||||
const nghttp2_huff_decode *t;
|
const nghttp2_huff_decode *t;
|
||||||
|
|
||||||
t = &huff_decode_table[ctx->state][in];
|
t = &huff_decode_table[ctx->state][src[i] >> 4];
|
||||||
if (t->flags & NGHTTP2_HUFF_FAIL) {
|
if (t->flags & NGHTTP2_HUFF_FAIL) {
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
return NGHTTP2_ERR_HEADER_COMP;
|
||||||
}
|
}
|
||||||
if (t->flags & NGHTTP2_HUFF_SYM) {
|
if (t->flags & NGHTTP2_HUFF_SYM) {
|
||||||
if (avail) {
|
/* this is macro, and may return from this function on error */
|
||||||
nghttp2_bufs_fast_addb(bufs, t->sym);
|
hd_huff_decode_sym_emit(bufs, t->sym, avail);
|
||||||
--avail;
|
|
||||||
} else {
|
|
||||||
rv = nghttp2_bufs_addb(bufs, t->sym);
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
avail = nghttp2_bufs_cur_avail(bufs);
|
|
||||||
|
t = &huff_decode_table[t->state][src[i] & 0xf];
|
||||||
|
if (t->flags & NGHTTP2_HUFF_FAIL) {
|
||||||
|
return NGHTTP2_ERR_HEADER_COMP;
|
||||||
}
|
}
|
||||||
|
if (t->flags & NGHTTP2_HUFF_SYM) {
|
||||||
|
/* this is macro, and may return from this function on error */
|
||||||
|
hd_huff_decode_sym_emit(bufs, t->sym, avail);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->state = t->state;
|
ctx->state = t->state;
|
||||||
ctx->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
|
ctx->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
|
||||||
in = src[i] & 0xf;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (final && !ctx->accept) {
|
if (final && !ctx->accept) {
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
return NGHTTP2_ERR_HEADER_COMP;
|
||||||
|
|||||||
@@ -29,12 +29,16 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif /* HAVE_CONFIG_H */
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
#include "nghttp2_mem.h"
|
#include "nghttp2_mem.h"
|
||||||
|
|
||||||
#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
|
#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
|
||||||
#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
|
#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
|
||||||
|
|
||||||
|
#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
|
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
|
||||||
* network byte order.
|
* network byte order.
|
||||||
|
|||||||
@@ -28,11 +28,8 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
static int memeq(const void *a, const void *b, size_t n) {
|
#include "nghttp2_hd.h"
|
||||||
return memcmp(a, b, n) == 0;
|
#include "nghttp2_helper.h"
|
||||||
}
|
|
||||||
|
|
||||||
#define streq(A, B, N) ((sizeof((A)) - 1) == (N) && memeq((A), (B), (N)))
|
|
||||||
|
|
||||||
static char downcase(char c) {
|
static char downcase(char c) {
|
||||||
return 'A' <= c && c <= 'Z' ? (c - 'A' + 'a') : c;
|
return 'A' <= c && c <= 'Z' ? (c - 'A' + 'a') : c;
|
||||||
@@ -50,129 +47,7 @@ static int memieq(const void *a, const void *b, size_t n) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define strieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
|
#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
NGHTTP2_TOKEN__AUTHORITY,
|
|
||||||
NGHTTP2_TOKEN__METHOD,
|
|
||||||
NGHTTP2_TOKEN__PATH,
|
|
||||||
NGHTTP2_TOKEN__SCHEME,
|
|
||||||
NGHTTP2_TOKEN__STATUS,
|
|
||||||
NGHTTP2_TOKEN_CONNECTION,
|
|
||||||
NGHTTP2_TOKEN_CONTENT_LENGTH,
|
|
||||||
NGHTTP2_TOKEN_HOST,
|
|
||||||
NGHTTP2_TOKEN_KEEP_ALIVE,
|
|
||||||
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
|
||||||
NGHTTP2_TOKEN_TE,
|
|
||||||
NGHTTP2_TOKEN_TRANSFER_ENCODING,
|
|
||||||
NGHTTP2_TOKEN_UPGRADE,
|
|
||||||
NGHTTP2_TOKEN_MAXIDX,
|
|
||||||
} nghttp2_token;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function was generated by genlibtokenlookup.py. Inspired by
|
|
||||||
* h2o header lookup. https://github.com/h2o/h2o
|
|
||||||
*/
|
|
||||||
static int lookup_token(const uint8_t *name, size_t namelen) {
|
|
||||||
switch (namelen) {
|
|
||||||
case 2:
|
|
||||||
switch (name[namelen - 1]) {
|
|
||||||
case 'e':
|
|
||||||
if (streq("t", name, 1)) {
|
|
||||||
return NGHTTP2_TOKEN_TE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
switch (name[namelen - 1]) {
|
|
||||||
case 't':
|
|
||||||
if (streq("hos", name, 3)) {
|
|
||||||
return NGHTTP2_TOKEN_HOST;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
switch (name[namelen - 1]) {
|
|
||||||
case 'h':
|
|
||||||
if (streq(":pat", name, 4)) {
|
|
||||||
return NGHTTP2_TOKEN__PATH;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
switch (name[namelen - 1]) {
|
|
||||||
case 'd':
|
|
||||||
if (streq(":metho", name, 6)) {
|
|
||||||
return NGHTTP2_TOKEN__METHOD;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
if (streq(":schem", name, 6)) {
|
|
||||||
return NGHTTP2_TOKEN__SCHEME;
|
|
||||||
}
|
|
||||||
if (streq("upgrad", name, 6)) {
|
|
||||||
return NGHTTP2_TOKEN_UPGRADE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
if (streq(":statu", name, 6)) {
|
|
||||||
return NGHTTP2_TOKEN__STATUS;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
switch (name[namelen - 1]) {
|
|
||||||
case 'e':
|
|
||||||
if (streq("keep-aliv", name, 9)) {
|
|
||||||
return NGHTTP2_TOKEN_KEEP_ALIVE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
if (streq("connectio", name, 9)) {
|
|
||||||
return NGHTTP2_TOKEN_CONNECTION;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'y':
|
|
||||||
if (streq(":authorit", name, 9)) {
|
|
||||||
return NGHTTP2_TOKEN__AUTHORITY;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 14:
|
|
||||||
switch (name[namelen - 1]) {
|
|
||||||
case 'h':
|
|
||||||
if (streq("content-lengt", name, 13)) {
|
|
||||||
return NGHTTP2_TOKEN_CONTENT_LENGTH;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
switch (name[namelen - 1]) {
|
|
||||||
case 'n':
|
|
||||||
if (streq("proxy-connectio", name, 15)) {
|
|
||||||
return NGHTTP2_TOKEN_PROXY_CONNECTION;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 17:
|
|
||||||
switch (name[namelen - 1]) {
|
|
||||||
case 'g':
|
|
||||||
if (streq("transfer-encodin", name, 16)) {
|
|
||||||
return NGHTTP2_TOKEN_TRANSFER_ENCODING;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t parse_uint(const uint8_t *s, size_t len) {
|
static int64_t parse_uint(const uint8_t *s, size_t len) {
|
||||||
int64_t n = 0;
|
int64_t n = 0;
|
||||||
@@ -225,10 +100,20 @@ static int expect_response_body(nghttp2_stream *stream) {
|
|||||||
stream->status_code != 204;
|
stream->status_code != 204;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
/* For "http" or "https" URIs, OPTIONS request may have "*" in :path
|
||||||
int trailer) {
|
header field to represent system-wide OPTIONS request. Otherwise,
|
||||||
int token;
|
:path header field value must start with "/". This function must
|
||||||
|
be called after ":method" header field was received. This function
|
||||||
|
returns nonzero if path is valid.*/
|
||||||
|
static int check_path(nghttp2_stream *stream) {
|
||||||
|
return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 ||
|
||||||
|
((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) ||
|
||||||
|
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) &&
|
||||||
|
(stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||||
|
int token, int trailer) {
|
||||||
if (nv->name[0] == ':') {
|
if (nv->name[0] == ':') {
|
||||||
if (trailer ||
|
if (trailer ||
|
||||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||||
@@ -236,8 +121,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
token = lookup_token(nv->name, nv->namelen);
|
|
||||||
|
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case NGHTTP2_TOKEN__AUTHORITY:
|
case NGHTTP2_TOKEN__AUTHORITY:
|
||||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
|
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
|
||||||
@@ -248,9 +131,16 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
|
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
}
|
}
|
||||||
if (streq("HEAD", nv->value, nv->valuelen)) {
|
switch (nv->valuelen) {
|
||||||
|
case 4:
|
||||||
|
if (lstreq("HEAD", nv->value, nv->valuelen)) {
|
||||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
|
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
|
||||||
} else if (streq("CONNECT", nv->value, nv->valuelen)) {
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
switch (nv->value[6]) {
|
||||||
|
case 'T':
|
||||||
|
if (lstreq("CONNECT", nv->value, nv->valuelen)) {
|
||||||
if (stream->stream_id % 2 == 0) {
|
if (stream->stream_id % 2 == 0) {
|
||||||
/* we won't allow CONNECT for push */
|
/* we won't allow CONNECT for push */
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
@@ -262,6 +152,15 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (lstreq("OPTIONS", nv->value, nv->valuelen)) {
|
||||||
|
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_OPTIONS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case NGHTTP2_TOKEN__PATH:
|
case NGHTTP2_TOKEN__PATH:
|
||||||
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
|
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
@@ -269,6 +168,11 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
|
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
}
|
}
|
||||||
|
if (nv->value[0] == '/') {
|
||||||
|
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR;
|
||||||
|
} else if (nv->valuelen == 1 && nv->value[0] == '*') {
|
||||||
|
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_TOKEN__SCHEME:
|
case NGHTTP2_TOKEN__SCHEME:
|
||||||
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
|
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
|
||||||
@@ -277,6 +181,10 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
|
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
}
|
}
|
||||||
|
if ((nv->valuelen == 4 && memieq("http", nv->value, 4)) ||
|
||||||
|
(nv->valuelen == 5 && memieq("https", nv->value, 5))) {
|
||||||
|
stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_TOKEN_HOST:
|
case NGHTTP2_TOKEN_HOST:
|
||||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
|
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
|
||||||
@@ -301,7 +209,7 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
case NGHTTP2_TOKEN_UPGRADE:
|
case NGHTTP2_TOKEN_UPGRADE:
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
case NGHTTP2_TOKEN_TE:
|
case NGHTTP2_TOKEN_TE:
|
||||||
if (!strieq("trailers", nv->value, nv->valuelen)) {
|
if (!lstrieq("trailers", nv->value, nv->valuelen)) {
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -319,9 +227,7 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||||
int trailer) {
|
int token, int trailer) {
|
||||||
int token;
|
|
||||||
|
|
||||||
if (nv->name[0] == ':') {
|
if (nv->name[0] == ':') {
|
||||||
if (trailer ||
|
if (trailer ||
|
||||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||||
@@ -329,8 +235,6 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
token = lookup_token(nv->name, nv->namelen);
|
|
||||||
|
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case NGHTTP2_TOKEN__STATUS: {
|
case NGHTTP2_TOKEN__STATUS: {
|
||||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
|
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
|
||||||
@@ -363,7 +267,7 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
case NGHTTP2_TOKEN_UPGRADE:
|
case NGHTTP2_TOKEN_UPGRADE:
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
case NGHTTP2_TOKEN_TE:
|
case NGHTTP2_TOKEN_TE:
|
||||||
if (!strieq("trailers", nv->value, nv->valuelen)) {
|
if (!lstrieq("trailers", nv->value, nv->valuelen)) {
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -381,7 +285,8 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||||
nghttp2_frame *frame, nghttp2_nv *nv, int trailer) {
|
nghttp2_frame *frame, nghttp2_nv *nv, int token,
|
||||||
|
int trailer) {
|
||||||
/* We are strict for pseudo header field. One bad character should
|
/* We are strict for pseudo header field. One bad character should
|
||||||
lead to fail. OTOH, we should be a bit forgiving for regular
|
lead to fail. OTOH, we should be a bit forgiving for regular
|
||||||
headers, since existing public internet has so much illegal
|
headers, since existing public internet has so much illegal
|
||||||
@@ -421,10 +326,10 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
||||||
return http_request_on_header(stream, nv, trailer);
|
return http_request_on_header(stream, nv, token, trailer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return http_response_on_header(stream, nv, trailer);
|
return http_response_on_header(stream, nv, token, trailer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
|
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
|
||||||
@@ -434,12 +339,17 @@ int nghttp2_http_on_request_headers(nghttp2_stream *stream,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
stream->content_length = -1;
|
stream->content_length = -1;
|
||||||
} else if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
|
} else {
|
||||||
|
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
|
||||||
NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
|
NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
|
||||||
(stream->http_flags &
|
(stream->http_flags &
|
||||||
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
|
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (!check_path(stream)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
||||||
/* we are going to reuse data fields for upcoming response. Clear
|
/* we are going to reuse data fields for upcoming response. Clear
|
||||||
@@ -532,14 +442,15 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
|||||||
/* TODO we should do this strictly. */
|
/* TODO we should do this strictly. */
|
||||||
for (i = 0; i < nvlen; ++i) {
|
for (i = 0; i < nvlen; ++i) {
|
||||||
const nghttp2_nv *nv = &nva[i];
|
const nghttp2_nv *nv = &nva[i];
|
||||||
if (lookup_token(nv->name, nv->namelen) != NGHTTP2_TOKEN__METHOD) {
|
if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
|
||||||
|
memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (streq("CONNECT", nv->value, nv->valuelen)) {
|
if (lstreq("CONNECT", nv->value, nv->valuelen)) {
|
||||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
|
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (streq("HEAD", nv->value, nv->valuelen)) {
|
if (lstreq("HEAD", nv->value, nv->valuelen)) {
|
||||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
|
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,8 @@
|
|||||||
/*
|
/*
|
||||||
* This function is called when HTTP header field |nv| in |frame| is
|
* This function is called when HTTP header field |nv| in |frame| is
|
||||||
* received for |stream|. This function will validate |nv| against
|
* received for |stream|. This function will validate |nv| against
|
||||||
* the current state of stream.
|
* the current state of stream. The |token| is nghttp2_token value
|
||||||
|
* for nv->name, or -1 if we don't have enum value for the name.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
* negative error codes:
|
* negative error codes:
|
||||||
@@ -48,7 +49,8 @@
|
|||||||
* if it was not received because of compatibility reasons.
|
* if it was not received because of compatibility reasons.
|
||||||
*/
|
*/
|
||||||
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||||
nghttp2_frame *frame, nghttp2_nv *nv, int trailer);
|
nghttp2_frame *frame, nghttp2_nv *nv, int token,
|
||||||
|
int trailer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is called when request header is received. This
|
* This function is called when request header is received. This
|
||||||
|
|||||||
@@ -39,7 +39,8 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef int (*nghttp2_compar)(const void *lhs, const void *rhs);
|
/* "less" function, return nonzero if |lhs| is less than |rhs|. */
|
||||||
|
typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
|
||||||
|
|
||||||
/* Internal error code. They must be in the range [-499, -100],
|
/* Internal error code. They must be in the range [-499, -100],
|
||||||
inclusive. */
|
inclusive. */
|
||||||
@@ -51,7 +52,7 @@ typedef enum {
|
|||||||
* Invalid HTTP header field was received but it can be treated as
|
* Invalid HTTP header field was received but it can be treated as
|
||||||
* if it was not received because of compatibility reasons.
|
* if it was not received because of compatibility reasons.
|
||||||
*/
|
*/
|
||||||
NGHTTP2_ERR_IGN_HTTP_HEADER = -105,
|
NGHTTP2_ERR_IGN_HTTP_HEADER = -105
|
||||||
} nghttp2_internal_error;
|
} nghttp2_internal_error;
|
||||||
|
|
||||||
#endif /* NGHTTP2_INT_H */
|
#endif /* NGHTTP2_INT_H */
|
||||||
|
|||||||
@@ -37,8 +37,55 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif /* HAVE_NETINET_IN_H */
|
#endif /* HAVE_NETINET_IN_H */
|
||||||
|
|
||||||
#ifdef HAVE_WINSOCK2_H
|
#include <nghttp2/nghttp2.h>
|
||||||
#include <winsock2.h>
|
|
||||||
#endif /* HAVE_WINSOCK2_H */
|
#if defined(WIN32)
|
||||||
|
/* Windows requires ws2_32 library for ntonl family functions. We
|
||||||
|
define inline functions for those function so that we don't have
|
||||||
|
dependeny on that lib. */
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define STIN static __inline
|
||||||
|
#else
|
||||||
|
#define STIN static inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STIN uint32_t htonl(uint32_t hostlong) {
|
||||||
|
uint32_t res;
|
||||||
|
unsigned char *p = (unsigned char *)&res;
|
||||||
|
*p++ = hostlong >> 24;
|
||||||
|
*p++ = (hostlong >> 16) & 0xffu;
|
||||||
|
*p++ = (hostlong >> 8) & 0xffu;
|
||||||
|
*p = hostlong & 0xffu;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
STIN uint16_t htons(uint16_t hostshort) {
|
||||||
|
uint16_t res;
|
||||||
|
unsigned char *p = (unsigned char *)&res;
|
||||||
|
*p++ = hostshort >> 8;
|
||||||
|
*p = hostshort & 0xffu;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
STIN uint32_t ntohl(uint32_t netlong) {
|
||||||
|
uint32_t res;
|
||||||
|
unsigned char *p = (unsigned char *)&netlong;
|
||||||
|
res = *p++ << 24;
|
||||||
|
res += *p++ << 16;
|
||||||
|
res += *p++ << 8;
|
||||||
|
res += *p;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
STIN uint16_t ntohs(uint16_t netshort) {
|
||||||
|
uint16_t res;
|
||||||
|
unsigned char *p = (unsigned char *)&netshort;
|
||||||
|
res = *p++ << 8;
|
||||||
|
res += *p;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WIN32 */
|
||||||
|
|
||||||
#endif /* NGHTTP2_NET_H */
|
#endif /* NGHTTP2_NET_H */
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
|
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
|
||||||
NGHTTP2_OPT_RECV_CLIENT_PREFACE = 1 << 2,
|
NGHTTP2_OPT_RECV_CLIENT_PREFACE = 1 << 2,
|
||||||
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
|
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3
|
||||||
} nghttp2_option_flag;
|
} nghttp2_option_flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,6 +25,15 @@
|
|||||||
#include "nghttp2_outbound_item.h"
|
#include "nghttp2_outbound_item.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void nghttp2_outbound_item_init(nghttp2_outbound_item *item) {
|
||||||
|
item->cycle = 0;
|
||||||
|
item->qnext = NULL;
|
||||||
|
item->queued = 0;
|
||||||
|
|
||||||
|
memset(&item->aux_data, 0, sizeof(nghttp2_aux_data));
|
||||||
|
}
|
||||||
|
|
||||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
|
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
|
||||||
nghttp2_frame *frame;
|
nghttp2_frame *frame;
|
||||||
@@ -65,3 +74,32 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q) {
|
||||||
|
q->head = q->tail = NULL;
|
||||||
|
q->n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
|
||||||
|
nghttp2_outbound_item *item) {
|
||||||
|
if (q->tail) {
|
||||||
|
q->tail = q->tail->qnext = item;
|
||||||
|
} else {
|
||||||
|
q->head = q->tail = item;
|
||||||
|
}
|
||||||
|
++q->n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q) {
|
||||||
|
nghttp2_outbound_item *item;
|
||||||
|
if (!q->head) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item = q->head;
|
||||||
|
q->head = q->head->qnext;
|
||||||
|
item->qnext = NULL;
|
||||||
|
if (!q->head) {
|
||||||
|
q->tail = NULL;
|
||||||
|
}
|
||||||
|
--q->n;
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,13 +33,6 @@
|
|||||||
#include "nghttp2_frame.h"
|
#include "nghttp2_frame.h"
|
||||||
#include "nghttp2_mem.h"
|
#include "nghttp2_mem.h"
|
||||||
|
|
||||||
/* A bit higher weight for non-DATA frames */
|
|
||||||
#define NGHTTP2_OB_EX_WEIGHT 300
|
|
||||||
/* Higher weight for SETTINGS */
|
|
||||||
#define NGHTTP2_OB_SETTINGS_WEIGHT 301
|
|
||||||
/* Highest weight for PING */
|
|
||||||
#define NGHTTP2_OB_PING_WEIGHT 302
|
|
||||||
|
|
||||||
/* struct used for HEADERS and PUSH_PROMISE frame */
|
/* struct used for HEADERS and PUSH_PROMISE frame */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nghttp2_data_provider data_prd;
|
nghttp2_data_provider data_prd;
|
||||||
@@ -74,6 +67,10 @@ typedef struct {
|
|||||||
* |eof| is 0. It becomes 1 after all data were read.
|
* |eof| is 0. It becomes 1 after all data were read.
|
||||||
*/
|
*/
|
||||||
uint8_t eof;
|
uint8_t eof;
|
||||||
|
/**
|
||||||
|
* The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used.
|
||||||
|
*/
|
||||||
|
uint8_t no_copy;
|
||||||
} nghttp2_data_aux_data;
|
} nghttp2_data_aux_data;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -84,7 +81,7 @@ typedef enum {
|
|||||||
/* indicates that this GOAWAY is just a notification for graceful
|
/* indicates that this GOAWAY is just a notification for graceful
|
||||||
shutdown. No nghttp2_session.goaway_flags should be updated on
|
shutdown. No nghttp2_session.goaway_flags should be updated on
|
||||||
the reaction to this frame. */
|
the reaction to this frame. */
|
||||||
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2,
|
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2
|
||||||
} nghttp2_goaway_aux_flag;
|
} nghttp2_goaway_aux_flag;
|
||||||
|
|
||||||
/* struct used for GOAWAY frame */
|
/* struct used for GOAWAY frame */
|
||||||
@@ -100,19 +97,31 @@ typedef union {
|
|||||||
nghttp2_goaway_aux_data goaway;
|
nghttp2_goaway_aux_data goaway;
|
||||||
} nghttp2_aux_data;
|
} nghttp2_aux_data;
|
||||||
|
|
||||||
typedef struct {
|
struct nghttp2_outbound_item;
|
||||||
|
typedef struct nghttp2_outbound_item nghttp2_outbound_item;
|
||||||
|
|
||||||
|
struct nghttp2_outbound_item {
|
||||||
nghttp2_frame frame;
|
nghttp2_frame frame;
|
||||||
nghttp2_aux_data aux_data;
|
nghttp2_aux_data aux_data;
|
||||||
int64_t seq;
|
/* The priority used in priority comparion. Smaller is served
|
||||||
/* Reset count of weight. See comment for last_cycle in
|
ealier. For PING, SETTINGS and non-DATA frames (excluding
|
||||||
nghttp2_session.h */
|
response HEADERS frame) have dedicated cycle value defined above.
|
||||||
|
For DATA frame, cycle is computed by taking into account of
|
||||||
|
effective weight and frame payload length previously sent, so
|
||||||
|
that the amount of transmission is distributed across streams
|
||||||
|
proportional to effective weight (inside a tree). */
|
||||||
uint64_t cycle;
|
uint64_t cycle;
|
||||||
/* The priority used in priority comparion. Larger is served
|
nghttp2_outbound_item *qnext;
|
||||||
ealier. */
|
|
||||||
int32_t weight;
|
|
||||||
/* nonzero if this object is queued. */
|
/* nonzero if this object is queued. */
|
||||||
uint8_t queued;
|
uint8_t queued;
|
||||||
} nghttp2_outbound_item;
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes |item|. No memory allocation is done in this function.
|
||||||
|
* Don't call nghttp2_outbound_item_free() until frame member is
|
||||||
|
* initialized.
|
||||||
|
*/
|
||||||
|
void nghttp2_outbound_item_init(nghttp2_outbound_item *item);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deallocates resource for |item|. If |item| is NULL, this function
|
* Deallocates resource for |item|. If |item| is NULL, this function
|
||||||
@@ -120,4 +129,29 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem);
|
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* queue for nghttp2_outbound_item.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
nghttp2_outbound_item *head, *tail;
|
||||||
|
/* number of items in this queue. */
|
||||||
|
size_t n;
|
||||||
|
} nghttp2_outbound_queue;
|
||||||
|
|
||||||
|
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q);
|
||||||
|
|
||||||
|
/* Pushes |item| into |q| */
|
||||||
|
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
|
||||||
|
nghttp2_outbound_item *item);
|
||||||
|
|
||||||
|
/* Pops |item| at the top from |q|. If |q| is empty, nothing
|
||||||
|
happens. */
|
||||||
|
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q);
|
||||||
|
|
||||||
|
/* Returns the top item. */
|
||||||
|
#define nghttp2_outbound_queue_top(Q) ((Q)->head)
|
||||||
|
|
||||||
|
/* Returns the size of the queue */
|
||||||
|
#define nghttp2_outbound_queue_size(Q) ((Q)->n)
|
||||||
|
|
||||||
#endif /* NGHTTP2_OUTBOUND_ITEM_H */
|
#endif /* NGHTTP2_OUTBOUND_ITEM_H */
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "nghttp2_pq.h"
|
#include "nghttp2_pq.h"
|
||||||
|
|
||||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar compar, nghttp2_mem *mem) {
|
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
|
||||||
pq->mem = mem;
|
pq->mem = mem;
|
||||||
pq->capacity = 128;
|
pq->capacity = 128;
|
||||||
pq->q = nghttp2_mem_malloc(mem, pq->capacity * sizeof(void *));
|
pq->q = nghttp2_mem_malloc(mem, pq->capacity * sizeof(void *));
|
||||||
@@ -32,7 +32,7 @@ int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar compar, nghttp2_mem *mem) {
|
|||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
pq->length = 0;
|
pq->length = 0;
|
||||||
pq->compar = compar;
|
pq->less = less;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ static void bubble_up(nghttp2_pq *pq, size_t index) {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
size_t parent = (index - 1) / 2;
|
size_t parent = (index - 1) / 2;
|
||||||
if (pq->compar(pq->q[parent], pq->q[index]) > 0) {
|
if (pq->less(pq->q[index], pq->q[parent])) {
|
||||||
swap(pq, parent, index);
|
swap(pq, parent, index);
|
||||||
bubble_up(pq, parent);
|
bubble_up(pq, parent);
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ static void bubble_down(nghttp2_pq *pq, size_t index) {
|
|||||||
if (j >= pq->length) {
|
if (j >= pq->length) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (pq->compar(pq->q[minindex], pq->q[j]) > 0) {
|
if (pq->less(pq->q[j], pq->q[minindex])) {
|
||||||
minindex = j;
|
minindex = j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ typedef struct {
|
|||||||
/* The maximum number of items this pq can store. This is
|
/* The maximum number of items this pq can store. This is
|
||||||
automatically extended when length is reached to this value. */
|
automatically extended when length is reached to this value. */
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
/* The compare function between items */
|
/* The less function between items */
|
||||||
nghttp2_compar compar;
|
nghttp2_less less;
|
||||||
} nghttp2_pq;
|
} nghttp2_pq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -58,7 +58,7 @@ typedef struct {
|
|||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
*/
|
*/
|
||||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar cmp, nghttp2_mem *mem);
|
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deallocates any resources allocated for |pq|. The stored items are
|
* Deallocates any resources allocated for |pq|. The stored items are
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -47,12 +47,13 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
|
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
|
||||||
NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE = 1 << 1,
|
NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE = 1 << 1,
|
||||||
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
|
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2
|
||||||
} nghttp2_optmask;
|
} nghttp2_optmask;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NGHTTP2_OB_POP_ITEM,
|
NGHTTP2_OB_POP_ITEM,
|
||||||
NGHTTP2_OB_SEND_DATA
|
NGHTTP2_OB_SEND_DATA,
|
||||||
|
NGHTTP2_OB_SEND_NO_COPY
|
||||||
} nghttp2_outbound_state;
|
} nghttp2_outbound_state;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -83,7 +84,7 @@ typedef enum {
|
|||||||
NGHTTP2_IB_READ_PAD_DATA,
|
NGHTTP2_IB_READ_PAD_DATA,
|
||||||
NGHTTP2_IB_READ_DATA,
|
NGHTTP2_IB_READ_DATA,
|
||||||
NGHTTP2_IB_IGN_DATA,
|
NGHTTP2_IB_IGN_DATA,
|
||||||
NGHTTP2_IB_IGN_ALL,
|
NGHTTP2_IB_IGN_ALL
|
||||||
} nghttp2_inbound_state;
|
} nghttp2_inbound_state;
|
||||||
|
|
||||||
#define NGHTTP2_INBOUND_NUM_IV 7
|
#define NGHTTP2_INBOUND_NUM_IV 7
|
||||||
@@ -135,18 +136,21 @@ typedef enum {
|
|||||||
/* Flag means GOAWAY was sent */
|
/* Flag means GOAWAY was sent */
|
||||||
NGHTTP2_GOAWAY_SENT = 0x4,
|
NGHTTP2_GOAWAY_SENT = 0x4,
|
||||||
/* Flag means GOAWAY was received */
|
/* Flag means GOAWAY was received */
|
||||||
NGHTTP2_GOAWAY_RECV = 0x8,
|
NGHTTP2_GOAWAY_RECV = 0x8
|
||||||
} nghttp2_goaway_flag;
|
} nghttp2_goaway_flag;
|
||||||
|
|
||||||
struct nghttp2_session {
|
struct nghttp2_session {
|
||||||
nghttp2_map /* <nghttp2_stream*> */ streams;
|
nghttp2_map /* <nghttp2_stream*> */ streams;
|
||||||
nghttp2_stream_roots roots;
|
nghttp2_stream_roots roots;
|
||||||
/* Queue for outbound frames other than stream-creating HEADERS and
|
/* Queue for outbound urgent frames (PING and SETTINGS) */
|
||||||
DATA */
|
nghttp2_outbound_queue ob_urgent;
|
||||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq;
|
/* Queue for non-DATA frames */
|
||||||
/* Queue for outbound stream-creating HEADERS frame */
|
nghttp2_outbound_queue ob_reg;
|
||||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_ss_pq;
|
/* Queue for outbound stream-creating HEADERS (request or push
|
||||||
/* QUeue for DATA frame */
|
response) frame, which are subject to
|
||||||
|
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
|
||||||
|
nghttp2_outbound_queue ob_syn;
|
||||||
|
/* Queue for DATA frame */
|
||||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_da_pq;
|
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_da_pq;
|
||||||
nghttp2_active_outbound_item aob;
|
nghttp2_active_outbound_item aob;
|
||||||
nghttp2_inbound_frame iframe;
|
nghttp2_inbound_frame iframe;
|
||||||
@@ -155,22 +159,8 @@ struct nghttp2_session {
|
|||||||
nghttp2_session_callbacks callbacks;
|
nghttp2_session_callbacks callbacks;
|
||||||
/* Memory allocator */
|
/* Memory allocator */
|
||||||
nghttp2_mem mem;
|
nghttp2_mem mem;
|
||||||
/* Sequence number of outbound frame to maintain the order of
|
/* Base value when we schedule next DATA frame write. This is
|
||||||
enqueue if priority is equal. */
|
updated when one frame was written. */
|
||||||
int64_t next_seq;
|
|
||||||
/* Reset count of nghttp2_outbound_item's weight. We decrements
|
|
||||||
weight each time DATA is sent to simulate resource sharing. We
|
|
||||||
use priority queue and larger weight has the precedence. If
|
|
||||||
weight is reached to lowest weight, it resets to its initial
|
|
||||||
weight. If this happens, other items which have the lower weight
|
|
||||||
currently but same initial weight cannot send DATA until item
|
|
||||||
having large weight is decreased. To avoid this, we use this
|
|
||||||
cycle variable. Initally, this is set to 1. If weight gets
|
|
||||||
lowest weight, and if item's cycle == last_cycle, we increments
|
|
||||||
last_cycle and assigns it to item's cycle. Otherwise, just
|
|
||||||
assign last_cycle. In priority queue comparator, we first
|
|
||||||
compare items' cycle value. Lower cycle value has the
|
|
||||||
precedence. */
|
|
||||||
uint64_t last_cycle;
|
uint64_t last_cycle;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
/* Points to the latest closed stream. NULL if there is no closed
|
/* Points to the latest closed stream. NULL if there is no closed
|
||||||
@@ -290,14 +280,6 @@ typedef struct {
|
|||||||
int nghttp2_session_is_my_stream_id(nghttp2_session *session,
|
int nghttp2_session_is_my_stream_id(nghttp2_session *session,
|
||||||
int32_t stream_id);
|
int32_t stream_id);
|
||||||
|
|
||||||
/*
|
|
||||||
* Initializes |item|. No memory allocation is done in this function.
|
|
||||||
* Don't call nghttp2_outbound_item_free() until frame member is
|
|
||||||
* initialized.
|
|
||||||
*/
|
|
||||||
void nghttp2_session_outbound_item_init(nghttp2_session *session,
|
|
||||||
nghttp2_outbound_item *item);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adds |item| to the outbound queue in |session|. When this function
|
* Adds |item| to the outbound queue in |session|. When this function
|
||||||
* succeeds, it takes ownership of |item|. So caller must not free it
|
* succeeds, it takes ownership of |item|. So caller must not free it
|
||||||
@@ -703,13 +685,8 @@ nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
|
|||||||
*/
|
*/
|
||||||
int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
||||||
size_t datamax, nghttp2_frame *frame,
|
size_t datamax, nghttp2_frame *frame,
|
||||||
nghttp2_data_aux_data *aux_data);
|
nghttp2_data_aux_data *aux_data,
|
||||||
|
nghttp2_stream *stream);
|
||||||
/*
|
|
||||||
* Returns top of outbound frame queue. This function returns NULL if
|
|
||||||
* queue is empty.
|
|
||||||
*/
|
|
||||||
nghttp2_outbound_item *nghttp2_session_get_ob_pq_top(nghttp2_session *session);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pops and returns next item to send. If there is no such item,
|
* Pops and returns next item to send. If there is no such item,
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
|||||||
stream->effective_weight = stream->weight;
|
stream->effective_weight = stream->weight;
|
||||||
stream->sum_dep_weight = 0;
|
stream->sum_dep_weight = 0;
|
||||||
stream->sum_norest_weight = 0;
|
stream->sum_norest_weight = 0;
|
||||||
stream->sum_top_weight = 0;
|
|
||||||
|
|
||||||
stream->roots = roots;
|
stream->roots = roots;
|
||||||
stream->root_prev = NULL;
|
stream->root_prev = NULL;
|
||||||
@@ -87,7 +86,8 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
|
static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
|
||||||
int rv;
|
/* This is required for Android NDK r10d */
|
||||||
|
int rv = 0;
|
||||||
nghttp2_outbound_item *item;
|
nghttp2_outbound_item *item;
|
||||||
|
|
||||||
assert(stream->item);
|
assert(stream->item);
|
||||||
@@ -101,33 +101,33 @@ static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->weight > stream->effective_weight) {
|
|
||||||
item->weight = stream->effective_weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
item->cycle = session->last_cycle;
|
|
||||||
|
|
||||||
switch (item->frame.hd.type) {
|
switch (item->frame.hd.type) {
|
||||||
case NGHTTP2_DATA:
|
case NGHTTP2_DATA:
|
||||||
|
/* Penalize item by delaying scheduling according to effective
|
||||||
|
weight. This will delay low priority stream, which is good.
|
||||||
|
OTOH, this may incur delay for high priority item. Will
|
||||||
|
see. */
|
||||||
|
item->cycle =
|
||||||
|
session->last_cycle +
|
||||||
|
NGHTTP2_DATA_PAYLOADLEN * NGHTTP2_MAX_WEIGHT / stream->effective_weight;
|
||||||
|
|
||||||
rv = nghttp2_pq_push(&session->ob_da_pq, item);
|
rv = nghttp2_pq_push(&session->ob_da_pq, item);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_HEADERS:
|
case NGHTTP2_HEADERS:
|
||||||
if (stream->state == NGHTTP2_STREAM_RESERVED) {
|
if (stream->state == NGHTTP2_STREAM_RESERVED) {
|
||||||
rv = nghttp2_pq_push(&session->ob_ss_pq, item);
|
nghttp2_outbound_queue_push(&session->ob_syn, item);
|
||||||
} else {
|
} else {
|
||||||
rv = nghttp2_pq_push(&session->ob_pq, item);
|
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rv = 0;
|
|
||||||
/* should not reach here */
|
/* should not reach here */
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
item->queued = 1;
|
item->queued = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -178,18 +178,6 @@ int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
|
|||||||
return nghttp2_max(1, 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);
|
static void stream_update_dep_set_rest(nghttp2_stream *stream);
|
||||||
|
|
||||||
/* Updates effective_weight of descendant streams in subtree of
|
/* Updates effective_weight of descendant streams in subtree of
|
||||||
@@ -199,10 +187,9 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
|
|||||||
nghttp2_stream *si;
|
nghttp2_stream *si;
|
||||||
|
|
||||||
DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight "
|
DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight "
|
||||||
"stream(%p)=%d, weight=%d, sum_norest_weight=%d, "
|
"stream(%p)=%d, weight=%d, sum_norest_weight=%d\n",
|
||||||
"sum_top_weight=%d\n",
|
|
||||||
stream, stream->stream_id, stream->weight,
|
stream, stream->stream_id, stream->weight,
|
||||||
stream->sum_norest_weight, stream->sum_top_weight));
|
stream->sum_norest_weight));
|
||||||
|
|
||||||
/* stream->sum_norest_weight == 0 means there is no
|
/* stream->sum_norest_weight == 0 means there is no
|
||||||
NGHTTP2_STREAM_DPRI_TOP under stream */
|
NGHTTP2_STREAM_DPRI_TOP under stream */
|
||||||
@@ -211,10 +198,6 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
|
|||||||
return;
|
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) {
|
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||||
if (si->dpri != NGHTTP2_STREAM_DPRI_REST) {
|
if (si->dpri != NGHTTP2_STREAM_DPRI_REST) {
|
||||||
si->effective_weight =
|
si->effective_weight =
|
||||||
@@ -223,36 +206,6 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
|
|||||||
|
|
||||||
stream_update_dep_effective_weight(si);
|
stream_update_dep_effective_weight(si);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there is at least one direct descendant whose dpri is
|
|
||||||
NGHTTP2_STREAM_DPRI_TOP, we won't give a chance to indirect
|
|
||||||
descendants, since closed or blocked stream's weight is
|
|
||||||
distributed among its siblings */
|
|
||||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
|
||||||
if (si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (si->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM) {
|
|
||||||
DEBUGF(fprintf(stderr, "stream: stream=%d no_item, ignored\n",
|
|
||||||
si->stream_id));
|
|
||||||
|
|
||||||
/* Since we marked NGHTTP2_STREAM_DPRI_TOP under si, we make
|
|
||||||
them NGHTTP2_STREAM_DPRI_REST again. */
|
|
||||||
stream_update_dep_set_rest(si->dep_next);
|
|
||||||
} else {
|
|
||||||
DEBUGF(
|
|
||||||
fprintf(stderr, "stream: stream=%d rest, ignored\n", si->stream_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stream_update_dep_set_rest(nghttp2_stream *stream) {
|
static void stream_update_dep_set_rest(nghttp2_stream *stream) {
|
||||||
@@ -347,25 +300,20 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates stream->sum_norest_weight and stream->sum_top_weight
|
* Updates stream->sum_norest_weight recursively. We have to gather
|
||||||
* recursively. We have to gather effective sum of weight of
|
* effective sum of weight of descendants. If stream->dpri ==
|
||||||
* descendants. If stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM, we
|
* NGHTTP2_STREAM_DPRI_NO_ITEM, we have to go deeper and check that
|
||||||
* have to go deeper and check that any of its descendants has dpri
|
* any of its descendants has dpri value of NGHTTP2_STREAM_DPRI_TOP.
|
||||||
* value of NGHTTP2_STREAM_DPRI_TOP. If so, we have to add weight of
|
* If so, we have to add weight of its direct descendants to
|
||||||
* its direct descendants to stream->sum_norest_weight. To make this
|
* stream->sum_norest_weight. To make this work, this function
|
||||||
* work, this function returns 1 if any of its descendants has dpri
|
* returns 1 if any of its descendants has dpri value of
|
||||||
* value of NGHTTP2_STREAM_DPRI_TOP, otherwise 0.
|
* 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) {
|
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) {
|
||||||
nghttp2_stream *si;
|
nghttp2_stream *si;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
stream->sum_norest_weight = 0;
|
stream->sum_norest_weight = 0;
|
||||||
stream->sum_top_weight = 0;
|
|
||||||
|
|
||||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -383,10 +331,6 @@ static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) {
|
|||||||
rv = 1;
|
rv = 1;
|
||||||
stream->sum_norest_weight += si->weight;
|
stream->sum_norest_weight += si->weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
|
||||||
stream->sum_top_weight += si->weight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
|||||||
@@ -120,10 +120,20 @@ typedef enum {
|
|||||||
/* HTTP method flags */
|
/* HTTP method flags */
|
||||||
NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
|
NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
|
||||||
NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
|
NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
|
||||||
NGHTTP2_HTTP_FLAG_METH_ALL =
|
NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
|
||||||
NGHTTP2_HTTP_FLAG_METH_CONNECT | NGHTTP2_HTTP_FLAG_METH_HEAD,
|
NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT |
|
||||||
|
NGHTTP2_HTTP_FLAG_METH_HEAD |
|
||||||
|
NGHTTP2_HTTP_FLAG_METH_OPTIONS,
|
||||||
|
/* :path category */
|
||||||
|
/* path starts with "/" */
|
||||||
|
NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 10,
|
||||||
|
/* path "*" */
|
||||||
|
NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 11,
|
||||||
|
/* scheme */
|
||||||
|
/* "http" or "https" scheme */
|
||||||
|
NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 12,
|
||||||
/* set if final response is expected */
|
/* set if final response is expected */
|
||||||
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 9,
|
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 13
|
||||||
} nghttp2_http_flag;
|
} nghttp2_http_flag;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -144,6 +154,10 @@ typedef struct nghttp2_stream nghttp2_stream;
|
|||||||
struct nghttp2_stream {
|
struct nghttp2_stream {
|
||||||
/* Intrusive Map */
|
/* Intrusive Map */
|
||||||
nghttp2_map_entry map_entry;
|
nghttp2_map_entry map_entry;
|
||||||
|
/* Content-Length of request/response body. -1 if unknown. */
|
||||||
|
int64_t content_length;
|
||||||
|
/* Received body so far */
|
||||||
|
int64_t recv_content_length;
|
||||||
/* pointers to form dependency tree. If multiple streams depend on
|
/* pointers to form dependency tree. If multiple streams depend on
|
||||||
a stream, only one stream (left most) has non-NULL dep_prev which
|
a stream, only one stream (left most) has non-NULL dep_prev which
|
||||||
points to the stream it depends on. The remaining streams are
|
points to the stream it depends on. The remaining streams are
|
||||||
@@ -203,22 +217,15 @@ struct nghttp2_stream {
|
|||||||
descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this
|
descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this
|
||||||
value to calculate effective weight. */
|
value to calculate effective weight. */
|
||||||
int32_t sum_norest_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;
|
nghttp2_stream_state state;
|
||||||
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
|
|
||||||
uint8_t flags;
|
|
||||||
/* Bitwise OR of zero or more nghttp2_shut_flag values */
|
|
||||||
uint8_t shut_flags;
|
|
||||||
/* Content-Length of request/response body. -1 if unknown. */
|
|
||||||
int64_t content_length;
|
|
||||||
/* Received body so far */
|
|
||||||
int64_t recv_content_length;
|
|
||||||
/* status code from remote server */
|
/* status code from remote server */
|
||||||
int16_t status_code;
|
int16_t status_code;
|
||||||
/* Bitwise OR of zero or more nghttp2_http_flag values */
|
/* Bitwise OR of zero or more nghttp2_http_flag values */
|
||||||
uint16_t http_flags;
|
uint16_t http_flags;
|
||||||
|
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
|
||||||
|
uint8_t flags;
|
||||||
|
/* Bitwise OR of zero or more nghttp2_shut_flag values */
|
||||||
|
uint8_t shut_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_session_outbound_item_init(session, item);
|
nghttp2_outbound_item_init(item);
|
||||||
|
|
||||||
if (data_prd != NULL && data_prd->read_callback != NULL) {
|
if (data_prd != NULL && data_prd->read_callback != NULL) {
|
||||||
item->aux_data.headers.data_prd = *data_prd;
|
item->aux_data.headers.data_prd = *data_prd;
|
||||||
@@ -212,7 +212,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
|
|||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_session_outbound_item_init(session, item);
|
nghttp2_outbound_item_init(item);
|
||||||
|
|
||||||
frame = &item->frame;
|
frame = &item->frame;
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
|||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_session_outbound_item_init(session, item);
|
nghttp2_outbound_item_init(item);
|
||||||
|
|
||||||
item->aux_data.headers.stream_user_data = promised_stream_user_data;
|
item->aux_data.headers.stream_user_data = promised_stream_user_data;
|
||||||
|
|
||||||
@@ -453,7 +453,7 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
|||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_session_outbound_item_init(session, item);
|
nghttp2_outbound_item_init(item);
|
||||||
|
|
||||||
frame = &item->frame;
|
frame = &item->frame;
|
||||||
aux_data = &item->aux_data.data;
|
aux_data = &item->aux_data.data;
|
||||||
|
|||||||
402
mkhufftbl.py
402
mkhufftbl.py
@@ -10,8 +10,271 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import StringIO
|
||||||
|
|
||||||
|
# From [1]
|
||||||
|
HUFFMAN_CODE_TABLE = """\
|
||||||
|
( 0) |11111111|11000 1ff8 [13]
|
||||||
|
( 1) |11111111|11111111|1011000 7fffd8 [23]
|
||||||
|
( 2) |11111111|11111111|11111110|0010 fffffe2 [28]
|
||||||
|
( 3) |11111111|11111111|11111110|0011 fffffe3 [28]
|
||||||
|
( 4) |11111111|11111111|11111110|0100 fffffe4 [28]
|
||||||
|
( 5) |11111111|11111111|11111110|0101 fffffe5 [28]
|
||||||
|
( 6) |11111111|11111111|11111110|0110 fffffe6 [28]
|
||||||
|
( 7) |11111111|11111111|11111110|0111 fffffe7 [28]
|
||||||
|
( 8) |11111111|11111111|11111110|1000 fffffe8 [28]
|
||||||
|
( 9) |11111111|11111111|11101010 ffffea [24]
|
||||||
|
( 10) |11111111|11111111|11111111|111100 3ffffffc [30]
|
||||||
|
( 11) |11111111|11111111|11111110|1001 fffffe9 [28]
|
||||||
|
( 12) |11111111|11111111|11111110|1010 fffffea [28]
|
||||||
|
( 13) |11111111|11111111|11111111|111101 3ffffffd [30]
|
||||||
|
( 14) |11111111|11111111|11111110|1011 fffffeb [28]
|
||||||
|
( 15) |11111111|11111111|11111110|1100 fffffec [28]
|
||||||
|
( 16) |11111111|11111111|11111110|1101 fffffed [28]
|
||||||
|
( 17) |11111111|11111111|11111110|1110 fffffee [28]
|
||||||
|
( 18) |11111111|11111111|11111110|1111 fffffef [28]
|
||||||
|
( 19) |11111111|11111111|11111111|0000 ffffff0 [28]
|
||||||
|
( 20) |11111111|11111111|11111111|0001 ffffff1 [28]
|
||||||
|
( 21) |11111111|11111111|11111111|0010 ffffff2 [28]
|
||||||
|
( 22) |11111111|11111111|11111111|111110 3ffffffe [30]
|
||||||
|
( 23) |11111111|11111111|11111111|0011 ffffff3 [28]
|
||||||
|
( 24) |11111111|11111111|11111111|0100 ffffff4 [28]
|
||||||
|
( 25) |11111111|11111111|11111111|0101 ffffff5 [28]
|
||||||
|
( 26) |11111111|11111111|11111111|0110 ffffff6 [28]
|
||||||
|
( 27) |11111111|11111111|11111111|0111 ffffff7 [28]
|
||||||
|
( 28) |11111111|11111111|11111111|1000 ffffff8 [28]
|
||||||
|
( 29) |11111111|11111111|11111111|1001 ffffff9 [28]
|
||||||
|
( 30) |11111111|11111111|11111111|1010 ffffffa [28]
|
||||||
|
( 31) |11111111|11111111|11111111|1011 ffffffb [28]
|
||||||
|
' ' ( 32) |010100 14 [ 6]
|
||||||
|
'!' ( 33) |11111110|00 3f8 [10]
|
||||||
|
'"' ( 34) |11111110|01 3f9 [10]
|
||||||
|
'#' ( 35) |11111111|1010 ffa [12]
|
||||||
|
'$' ( 36) |11111111|11001 1ff9 [13]
|
||||||
|
'%' ( 37) |010101 15 [ 6]
|
||||||
|
'&' ( 38) |11111000 f8 [ 8]
|
||||||
|
''' ( 39) |11111111|010 7fa [11]
|
||||||
|
'(' ( 40) |11111110|10 3fa [10]
|
||||||
|
')' ( 41) |11111110|11 3fb [10]
|
||||||
|
'*' ( 42) |11111001 f9 [ 8]
|
||||||
|
'+' ( 43) |11111111|011 7fb [11]
|
||||||
|
',' ( 44) |11111010 fa [ 8]
|
||||||
|
'-' ( 45) |010110 16 [ 6]
|
||||||
|
'.' ( 46) |010111 17 [ 6]
|
||||||
|
'/' ( 47) |011000 18 [ 6]
|
||||||
|
'0' ( 48) |00000 0 [ 5]
|
||||||
|
'1' ( 49) |00001 1 [ 5]
|
||||||
|
'2' ( 50) |00010 2 [ 5]
|
||||||
|
'3' ( 51) |011001 19 [ 6]
|
||||||
|
'4' ( 52) |011010 1a [ 6]
|
||||||
|
'5' ( 53) |011011 1b [ 6]
|
||||||
|
'6' ( 54) |011100 1c [ 6]
|
||||||
|
'7' ( 55) |011101 1d [ 6]
|
||||||
|
'8' ( 56) |011110 1e [ 6]
|
||||||
|
'9' ( 57) |011111 1f [ 6]
|
||||||
|
':' ( 58) |1011100 5c [ 7]
|
||||||
|
';' ( 59) |11111011 fb [ 8]
|
||||||
|
'<' ( 60) |11111111|1111100 7ffc [15]
|
||||||
|
'=' ( 61) |100000 20 [ 6]
|
||||||
|
'>' ( 62) |11111111|1011 ffb [12]
|
||||||
|
'?' ( 63) |11111111|00 3fc [10]
|
||||||
|
'@' ( 64) |11111111|11010 1ffa [13]
|
||||||
|
'A' ( 65) |100001 21 [ 6]
|
||||||
|
'B' ( 66) |1011101 5d [ 7]
|
||||||
|
'C' ( 67) |1011110 5e [ 7]
|
||||||
|
'D' ( 68) |1011111 5f [ 7]
|
||||||
|
'E' ( 69) |1100000 60 [ 7]
|
||||||
|
'F' ( 70) |1100001 61 [ 7]
|
||||||
|
'G' ( 71) |1100010 62 [ 7]
|
||||||
|
'H' ( 72) |1100011 63 [ 7]
|
||||||
|
'I' ( 73) |1100100 64 [ 7]
|
||||||
|
'J' ( 74) |1100101 65 [ 7]
|
||||||
|
'K' ( 75) |1100110 66 [ 7]
|
||||||
|
'L' ( 76) |1100111 67 [ 7]
|
||||||
|
'M' ( 77) |1101000 68 [ 7]
|
||||||
|
'N' ( 78) |1101001 69 [ 7]
|
||||||
|
'O' ( 79) |1101010 6a [ 7]
|
||||||
|
'P' ( 80) |1101011 6b [ 7]
|
||||||
|
'Q' ( 81) |1101100 6c [ 7]
|
||||||
|
'R' ( 82) |1101101 6d [ 7]
|
||||||
|
'S' ( 83) |1101110 6e [ 7]
|
||||||
|
'T' ( 84) |1101111 6f [ 7]
|
||||||
|
'U' ( 85) |1110000 70 [ 7]
|
||||||
|
'V' ( 86) |1110001 71 [ 7]
|
||||||
|
'W' ( 87) |1110010 72 [ 7]
|
||||||
|
'X' ( 88) |11111100 fc [ 8]
|
||||||
|
'Y' ( 89) |1110011 73 [ 7]
|
||||||
|
'Z' ( 90) |11111101 fd [ 8]
|
||||||
|
'[' ( 91) |11111111|11011 1ffb [13]
|
||||||
|
'\' ( 92) |11111111|11111110|000 7fff0 [19]
|
||||||
|
']' ( 93) |11111111|11100 1ffc [13]
|
||||||
|
'^' ( 94) |11111111|111100 3ffc [14]
|
||||||
|
'_' ( 95) |100010 22 [ 6]
|
||||||
|
'`' ( 96) |11111111|1111101 7ffd [15]
|
||||||
|
'a' ( 97) |00011 3 [ 5]
|
||||||
|
'b' ( 98) |100011 23 [ 6]
|
||||||
|
'c' ( 99) |00100 4 [ 5]
|
||||||
|
'd' (100) |100100 24 [ 6]
|
||||||
|
'e' (101) |00101 5 [ 5]
|
||||||
|
'f' (102) |100101 25 [ 6]
|
||||||
|
'g' (103) |100110 26 [ 6]
|
||||||
|
'h' (104) |100111 27 [ 6]
|
||||||
|
'i' (105) |00110 6 [ 5]
|
||||||
|
'j' (106) |1110100 74 [ 7]
|
||||||
|
'k' (107) |1110101 75 [ 7]
|
||||||
|
'l' (108) |101000 28 [ 6]
|
||||||
|
'm' (109) |101001 29 [ 6]
|
||||||
|
'n' (110) |101010 2a [ 6]
|
||||||
|
'o' (111) |00111 7 [ 5]
|
||||||
|
'p' (112) |101011 2b [ 6]
|
||||||
|
'q' (113) |1110110 76 [ 7]
|
||||||
|
'r' (114) |101100 2c [ 6]
|
||||||
|
's' (115) |01000 8 [ 5]
|
||||||
|
't' (116) |01001 9 [ 5]
|
||||||
|
'u' (117) |101101 2d [ 6]
|
||||||
|
'v' (118) |1110111 77 [ 7]
|
||||||
|
'w' (119) |1111000 78 [ 7]
|
||||||
|
'x' (120) |1111001 79 [ 7]
|
||||||
|
'y' (121) |1111010 7a [ 7]
|
||||||
|
'z' (122) |1111011 7b [ 7]
|
||||||
|
'{' (123) |11111111|1111110 7ffe [15]
|
||||||
|
'|' (124) |11111111|100 7fc [11]
|
||||||
|
'}' (125) |11111111|111101 3ffd [14]
|
||||||
|
'~' (126) |11111111|11101 1ffd [13]
|
||||||
|
(127) |11111111|11111111|11111111|1100 ffffffc [28]
|
||||||
|
(128) |11111111|11111110|0110 fffe6 [20]
|
||||||
|
(129) |11111111|11111111|010010 3fffd2 [22]
|
||||||
|
(130) |11111111|11111110|0111 fffe7 [20]
|
||||||
|
(131) |11111111|11111110|1000 fffe8 [20]
|
||||||
|
(132) |11111111|11111111|010011 3fffd3 [22]
|
||||||
|
(133) |11111111|11111111|010100 3fffd4 [22]
|
||||||
|
(134) |11111111|11111111|010101 3fffd5 [22]
|
||||||
|
(135) |11111111|11111111|1011001 7fffd9 [23]
|
||||||
|
(136) |11111111|11111111|010110 3fffd6 [22]
|
||||||
|
(137) |11111111|11111111|1011010 7fffda [23]
|
||||||
|
(138) |11111111|11111111|1011011 7fffdb [23]
|
||||||
|
(139) |11111111|11111111|1011100 7fffdc [23]
|
||||||
|
(140) |11111111|11111111|1011101 7fffdd [23]
|
||||||
|
(141) |11111111|11111111|1011110 7fffde [23]
|
||||||
|
(142) |11111111|11111111|11101011 ffffeb [24]
|
||||||
|
(143) |11111111|11111111|1011111 7fffdf [23]
|
||||||
|
(144) |11111111|11111111|11101100 ffffec [24]
|
||||||
|
(145) |11111111|11111111|11101101 ffffed [24]
|
||||||
|
(146) |11111111|11111111|010111 3fffd7 [22]
|
||||||
|
(147) |11111111|11111111|1100000 7fffe0 [23]
|
||||||
|
(148) |11111111|11111111|11101110 ffffee [24]
|
||||||
|
(149) |11111111|11111111|1100001 7fffe1 [23]
|
||||||
|
(150) |11111111|11111111|1100010 7fffe2 [23]
|
||||||
|
(151) |11111111|11111111|1100011 7fffe3 [23]
|
||||||
|
(152) |11111111|11111111|1100100 7fffe4 [23]
|
||||||
|
(153) |11111111|11111110|11100 1fffdc [21]
|
||||||
|
(154) |11111111|11111111|011000 3fffd8 [22]
|
||||||
|
(155) |11111111|11111111|1100101 7fffe5 [23]
|
||||||
|
(156) |11111111|11111111|011001 3fffd9 [22]
|
||||||
|
(157) |11111111|11111111|1100110 7fffe6 [23]
|
||||||
|
(158) |11111111|11111111|1100111 7fffe7 [23]
|
||||||
|
(159) |11111111|11111111|11101111 ffffef [24]
|
||||||
|
(160) |11111111|11111111|011010 3fffda [22]
|
||||||
|
(161) |11111111|11111110|11101 1fffdd [21]
|
||||||
|
(162) |11111111|11111110|1001 fffe9 [20]
|
||||||
|
(163) |11111111|11111111|011011 3fffdb [22]
|
||||||
|
(164) |11111111|11111111|011100 3fffdc [22]
|
||||||
|
(165) |11111111|11111111|1101000 7fffe8 [23]
|
||||||
|
(166) |11111111|11111111|1101001 7fffe9 [23]
|
||||||
|
(167) |11111111|11111110|11110 1fffde [21]
|
||||||
|
(168) |11111111|11111111|1101010 7fffea [23]
|
||||||
|
(169) |11111111|11111111|011101 3fffdd [22]
|
||||||
|
(170) |11111111|11111111|011110 3fffde [22]
|
||||||
|
(171) |11111111|11111111|11110000 fffff0 [24]
|
||||||
|
(172) |11111111|11111110|11111 1fffdf [21]
|
||||||
|
(173) |11111111|11111111|011111 3fffdf [22]
|
||||||
|
(174) |11111111|11111111|1101011 7fffeb [23]
|
||||||
|
(175) |11111111|11111111|1101100 7fffec [23]
|
||||||
|
(176) |11111111|11111111|00000 1fffe0 [21]
|
||||||
|
(177) |11111111|11111111|00001 1fffe1 [21]
|
||||||
|
(178) |11111111|11111111|100000 3fffe0 [22]
|
||||||
|
(179) |11111111|11111111|00010 1fffe2 [21]
|
||||||
|
(180) |11111111|11111111|1101101 7fffed [23]
|
||||||
|
(181) |11111111|11111111|100001 3fffe1 [22]
|
||||||
|
(182) |11111111|11111111|1101110 7fffee [23]
|
||||||
|
(183) |11111111|11111111|1101111 7fffef [23]
|
||||||
|
(184) |11111111|11111110|1010 fffea [20]
|
||||||
|
(185) |11111111|11111111|100010 3fffe2 [22]
|
||||||
|
(186) |11111111|11111111|100011 3fffe3 [22]
|
||||||
|
(187) |11111111|11111111|100100 3fffe4 [22]
|
||||||
|
(188) |11111111|11111111|1110000 7ffff0 [23]
|
||||||
|
(189) |11111111|11111111|100101 3fffe5 [22]
|
||||||
|
(190) |11111111|11111111|100110 3fffe6 [22]
|
||||||
|
(191) |11111111|11111111|1110001 7ffff1 [23]
|
||||||
|
(192) |11111111|11111111|11111000|00 3ffffe0 [26]
|
||||||
|
(193) |11111111|11111111|11111000|01 3ffffe1 [26]
|
||||||
|
(194) |11111111|11111110|1011 fffeb [20]
|
||||||
|
(195) |11111111|11111110|001 7fff1 [19]
|
||||||
|
(196) |11111111|11111111|100111 3fffe7 [22]
|
||||||
|
(197) |11111111|11111111|1110010 7ffff2 [23]
|
||||||
|
(198) |11111111|11111111|101000 3fffe8 [22]
|
||||||
|
(199) |11111111|11111111|11110110|0 1ffffec [25]
|
||||||
|
(200) |11111111|11111111|11111000|10 3ffffe2 [26]
|
||||||
|
(201) |11111111|11111111|11111000|11 3ffffe3 [26]
|
||||||
|
(202) |11111111|11111111|11111001|00 3ffffe4 [26]
|
||||||
|
(203) |11111111|11111111|11111011|110 7ffffde [27]
|
||||||
|
(204) |11111111|11111111|11111011|111 7ffffdf [27]
|
||||||
|
(205) |11111111|11111111|11111001|01 3ffffe5 [26]
|
||||||
|
(206) |11111111|11111111|11110001 fffff1 [24]
|
||||||
|
(207) |11111111|11111111|11110110|1 1ffffed [25]
|
||||||
|
(208) |11111111|11111110|010 7fff2 [19]
|
||||||
|
(209) |11111111|11111111|00011 1fffe3 [21]
|
||||||
|
(210) |11111111|11111111|11111001|10 3ffffe6 [26]
|
||||||
|
(211) |11111111|11111111|11111100|000 7ffffe0 [27]
|
||||||
|
(212) |11111111|11111111|11111100|001 7ffffe1 [27]
|
||||||
|
(213) |11111111|11111111|11111001|11 3ffffe7 [26]
|
||||||
|
(214) |11111111|11111111|11111100|010 7ffffe2 [27]
|
||||||
|
(215) |11111111|11111111|11110010 fffff2 [24]
|
||||||
|
(216) |11111111|11111111|00100 1fffe4 [21]
|
||||||
|
(217) |11111111|11111111|00101 1fffe5 [21]
|
||||||
|
(218) |11111111|11111111|11111010|00 3ffffe8 [26]
|
||||||
|
(219) |11111111|11111111|11111010|01 3ffffe9 [26]
|
||||||
|
(220) |11111111|11111111|11111111|1101 ffffffd [28]
|
||||||
|
(221) |11111111|11111111|11111100|011 7ffffe3 [27]
|
||||||
|
(222) |11111111|11111111|11111100|100 7ffffe4 [27]
|
||||||
|
(223) |11111111|11111111|11111100|101 7ffffe5 [27]
|
||||||
|
(224) |11111111|11111110|1100 fffec [20]
|
||||||
|
(225) |11111111|11111111|11110011 fffff3 [24]
|
||||||
|
(226) |11111111|11111110|1101 fffed [20]
|
||||||
|
(227) |11111111|11111111|00110 1fffe6 [21]
|
||||||
|
(228) |11111111|11111111|101001 3fffe9 [22]
|
||||||
|
(229) |11111111|11111111|00111 1fffe7 [21]
|
||||||
|
(230) |11111111|11111111|01000 1fffe8 [21]
|
||||||
|
(231) |11111111|11111111|1110011 7ffff3 [23]
|
||||||
|
(232) |11111111|11111111|101010 3fffea [22]
|
||||||
|
(233) |11111111|11111111|101011 3fffeb [22]
|
||||||
|
(234) |11111111|11111111|11110111|0 1ffffee [25]
|
||||||
|
(235) |11111111|11111111|11110111|1 1ffffef [25]
|
||||||
|
(236) |11111111|11111111|11110100 fffff4 [24]
|
||||||
|
(237) |11111111|11111111|11110101 fffff5 [24]
|
||||||
|
(238) |11111111|11111111|11111010|10 3ffffea [26]
|
||||||
|
(239) |11111111|11111111|1110100 7ffff4 [23]
|
||||||
|
(240) |11111111|11111111|11111010|11 3ffffeb [26]
|
||||||
|
(241) |11111111|11111111|11111100|110 7ffffe6 [27]
|
||||||
|
(242) |11111111|11111111|11111011|00 3ffffec [26]
|
||||||
|
(243) |11111111|11111111|11111011|01 3ffffed [26]
|
||||||
|
(244) |11111111|11111111|11111100|111 7ffffe7 [27]
|
||||||
|
(245) |11111111|11111111|11111101|000 7ffffe8 [27]
|
||||||
|
(246) |11111111|11111111|11111101|001 7ffffe9 [27]
|
||||||
|
(247) |11111111|11111111|11111101|010 7ffffea [27]
|
||||||
|
(248) |11111111|11111111|11111101|011 7ffffeb [27]
|
||||||
|
(249) |11111111|11111111|11111111|1110 ffffffe [28]
|
||||||
|
(250) |11111111|11111111|11111101|100 7ffffec [27]
|
||||||
|
(251) |11111111|11111111|11111101|101 7ffffed [27]
|
||||||
|
(252) |11111111|11111111|11111101|110 7ffffee [27]
|
||||||
|
(253) |11111111|11111111|11111101|111 7ffffef [27]
|
||||||
|
(254) |11111111|11111111|11111110|000 7fffff0 [27]
|
||||||
|
(255) |11111111|11111111|11111011|10 3ffffee [26]
|
||||||
|
EOS (256) |11111111|11111111|11111111|111111 3fffffff [30]
|
||||||
|
"""
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
|
|
||||||
def __init__(self, term = None):
|
def __init__(self, term = None):
|
||||||
self.term = term
|
self.term = term
|
||||||
self.left = None
|
self.left = None
|
||||||
@@ -20,21 +283,18 @@ class Node:
|
|||||||
self.id = None
|
self.id = None
|
||||||
self.accept = False
|
self.accept = False
|
||||||
|
|
||||||
def to_bin(s):
|
class Context:
|
||||||
res = []
|
|
||||||
for i in range(0, len(s), 8):
|
|
||||||
x = s[i:i+8]
|
|
||||||
x += '0'*(8 - len(x))
|
|
||||||
a = 0
|
|
||||||
for j in range(8):
|
|
||||||
a *= 2
|
|
||||||
a += ord(x[j]) - ord('0')
|
|
||||||
res.append(a) #chr(a))
|
|
||||||
return res
|
|
||||||
|
|
||||||
nodes = []
|
def __init__(self):
|
||||||
|
self.next_id_ = 0
|
||||||
|
self.root = Node()
|
||||||
|
|
||||||
def insert(node, sym, bits):
|
def next_id(self):
|
||||||
|
id = self.next_id_
|
||||||
|
self.next_id_ += 1
|
||||||
|
return id
|
||||||
|
|
||||||
|
def _add(node, sym, bits):
|
||||||
if len(bits) == 0:
|
if len(bits) == 0:
|
||||||
node.term = sym
|
node.term = sym
|
||||||
return
|
return
|
||||||
@@ -47,67 +307,71 @@ def insert(node, sym, bits):
|
|||||||
if node.right is None:
|
if node.right is None:
|
||||||
node.right = Node()
|
node.right = Node()
|
||||||
child = node.right
|
child = node.right
|
||||||
insert(child, sym, bits[1:])
|
_add(child, sym, bits[1:])
|
||||||
|
|
||||||
def traverse(node, bits, syms, start_node, root, depth):
|
def huffman_tree_add(ctx, sym, bits):
|
||||||
if depth == 4:
|
_add(ctx.root, sym, bits)
|
||||||
if 256 in syms:
|
|
||||||
syms = []
|
def _set_node_id(ctx, node, prefix):
|
||||||
|
if node.term is not None:
|
||||||
|
return
|
||||||
|
if len(prefix) <= 7 and [1] * len(prefix) == prefix:
|
||||||
|
node.accept = True
|
||||||
|
node.id = ctx.next_id()
|
||||||
|
_set_node_id(ctx, node.left, prefix + [0])
|
||||||
|
_set_node_id(ctx, node.right, prefix + [1])
|
||||||
|
|
||||||
|
def huffman_tree_set_node_id(ctx):
|
||||||
|
_set_node_id(ctx, ctx.root, [])
|
||||||
|
|
||||||
|
def _traverse(node, sym, start_node, root, left):
|
||||||
|
if left == 0:
|
||||||
|
if sym == 256:
|
||||||
|
sym = None
|
||||||
node = None
|
node = None
|
||||||
start_node.trans.append((node, bits, syms))
|
start_node.trans.append((node, sym))
|
||||||
return
|
return
|
||||||
|
|
||||||
if node.term is not None:
|
if node.term is not None:
|
||||||
node = root
|
node = root
|
||||||
|
|
||||||
def go(node, bit):
|
def go(node):
|
||||||
nbits = list(bits)
|
|
||||||
nbits.append(bit)
|
|
||||||
nsyms = list(syms)
|
|
||||||
if node.term is not None:
|
if node.term is not None:
|
||||||
nsyms.append(node.term)
|
assert sym is None
|
||||||
traverse(node, nbits, nsyms, start_node, root, depth + 1)
|
nsym = node.term
|
||||||
|
else:
|
||||||
|
nsym = sym
|
||||||
|
|
||||||
go(node.left, 0)
|
_traverse(node, nsym, start_node, root, left - 1)
|
||||||
go(node.right, 1)
|
|
||||||
|
|
||||||
idseed = 0
|
go(node.left)
|
||||||
|
go(node.right)
|
||||||
|
|
||||||
def dfs_setid(node, prefix):
|
def _build_transition_table(ctx, node):
|
||||||
if node.term is not None:
|
|
||||||
return
|
|
||||||
if len(prefix) <= 7 and [1] * len(prefix) == prefix:
|
|
||||||
node.accept = True
|
|
||||||
global idseed
|
|
||||||
node.id = idseed
|
|
||||||
idseed += 1
|
|
||||||
dfs_setid(node.left, prefix + [0])
|
|
||||||
dfs_setid(node.right, prefix + [1])
|
|
||||||
|
|
||||||
def dfs(node, root):
|
|
||||||
if node is None:
|
if node is None:
|
||||||
return
|
return
|
||||||
traverse(node, [], [], node, root, 0)
|
_traverse(node, None, node, ctx.root, 4)
|
||||||
dfs(node.left, root)
|
_build_transition_table(ctx, node.left)
|
||||||
dfs(node.right, root)
|
_build_transition_table(ctx, node.right)
|
||||||
|
|
||||||
|
def huffman_tree_build_transition_table(ctx):
|
||||||
|
_build_transition_table(ctx, ctx.root)
|
||||||
|
|
||||||
NGHTTP2_HUFF_ACCEPTED = 1
|
NGHTTP2_HUFF_ACCEPTED = 1
|
||||||
NGHTTP2_HUFF_SYM = 1 << 1
|
NGHTTP2_HUFF_SYM = 1 << 1
|
||||||
NGHTTP2_HUFF_FAIL = 1 << 2
|
NGHTTP2_HUFF_FAIL = 1 << 2
|
||||||
|
|
||||||
def dfs_print(node):
|
def _print_transition_table(node):
|
||||||
if node.term is not None:
|
if node.term is not None:
|
||||||
return
|
return
|
||||||
print '/* {} */'.format(node.id)
|
print '/* {} */'.format(node.id)
|
||||||
print '{'
|
print '{'
|
||||||
for nd, bits, syms in node.trans:
|
for nd, sym in node.trans:
|
||||||
outlen = len(syms)
|
|
||||||
flags = 0
|
flags = 0
|
||||||
if outlen == 0:
|
if sym is None:
|
||||||
out = 0
|
out = 0
|
||||||
else:
|
else:
|
||||||
assert(outlen == 1)
|
out = sym
|
||||||
out = syms[0]
|
|
||||||
flags |= NGHTTP2_HUFF_SYM
|
flags |= NGHTTP2_HUFF_SYM
|
||||||
if nd is None:
|
if nd is None:
|
||||||
id = 0
|
id = 0
|
||||||
@@ -122,32 +386,32 @@ def dfs_print(node):
|
|||||||
flags |= NGHTTP2_HUFF_ACCEPTED
|
flags |= NGHTTP2_HUFF_ACCEPTED
|
||||||
print ' {{{}, 0x{:02x}, {}}},'.format(id, flags, out)
|
print ' {{{}, 0x{:02x}, {}}},'.format(id, flags, out)
|
||||||
print '},'
|
print '},'
|
||||||
dfs_print(node.left)
|
_print_transition_table(node.left)
|
||||||
dfs_print(node.right)
|
_print_transition_table(node.right)
|
||||||
|
|
||||||
|
def huffman_tree_print_transition_table(ctx):
|
||||||
|
_print_transition_table(ctx.root)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
ctx = Context()
|
||||||
symbol_tbl = [(None, 0) for i in range(257)]
|
symbol_tbl = [(None, 0) for i in range(257)]
|
||||||
tables = {}
|
|
||||||
|
|
||||||
root = Node()
|
for line in StringIO.StringIO(HUFFMAN_CODE_TABLE):
|
||||||
|
m = re.match(
|
||||||
for line in sys.stdin:
|
r'.*\(\s*(\d+)\)\s+([|01]+)\s+(\S+)\s+\[\s*(\d+)\].*', line)
|
||||||
m = re.match(r'.*\(\s*(\d+)\)\s+([|01]+)\s+(\S+)\s+\[\s*(\d+)\].*', line)
|
|
||||||
if m:
|
if m:
|
||||||
#print m.group(1), m.group(2), m.group(4)
|
|
||||||
if len(m.group(3)) > 8:
|
|
||||||
raise Error('Code is more than 4 bytes long')
|
|
||||||
sym = int(m.group(1))
|
sym = int(m.group(1))
|
||||||
bits = re.sub(r'\|', '', m.group(2))
|
bits = re.sub(r'\|', '', m.group(2))
|
||||||
|
code = m.group(3)
|
||||||
nbits = int(m.group(4))
|
nbits = int(m.group(4))
|
||||||
|
if len(code) > 8:
|
||||||
|
raise Error('Code is more than 4 bytes long')
|
||||||
assert(len(bits) == nbits)
|
assert(len(bits) == nbits)
|
||||||
binpat = to_bin(bits)
|
symbol_tbl[sym] = (nbits, code)
|
||||||
assert(len(binpat) == (nbits+7)/8)
|
huffman_tree_add(ctx, sym, bits)
|
||||||
symbol_tbl[sym] = (binpat, nbits, m.group(3))
|
|
||||||
#print "Inserting", sym
|
|
||||||
insert(root, sym, bits)
|
|
||||||
|
|
||||||
dfs_setid(root, [])
|
huffman_tree_set_node_id(ctx)
|
||||||
dfs(root, root)
|
huffman_tree_build_transition_table(ctx)
|
||||||
|
|
||||||
print '''\
|
print '''\
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -159,11 +423,9 @@ typedef struct {
|
|||||||
print '''\
|
print '''\
|
||||||
const nghttp2_huff_sym huff_sym_table[] = {'''
|
const nghttp2_huff_sym huff_sym_table[] = {'''
|
||||||
for i in range(257):
|
for i in range(257):
|
||||||
pat = list(symbol_tbl[i][0])
|
|
||||||
pat += [0]*(4 - len(pat))
|
|
||||||
print '''\
|
print '''\
|
||||||
{{ {}, 0x{}u }}{}\
|
{{ {}, 0x{}u }}{}\
|
||||||
'''.format(symbol_tbl[i][1], symbol_tbl[i][2], ',' if i < 256 else '')
|
'''.format(symbol_tbl[i][0], symbol_tbl[i][1], ',' if i < 256 else '')
|
||||||
print '};'
|
print '};'
|
||||||
print ''
|
print ''
|
||||||
|
|
||||||
@@ -185,5 +447,5 @@ typedef struct {
|
|||||||
|
|
||||||
print '''\
|
print '''\
|
||||||
const nghttp2_huff_decode huff_decode_table[][16] = {'''
|
const nghttp2_huff_decode huff_decode_table[][16] = {'''
|
||||||
dfs_print(root)
|
huffman_tree_print_transition_table(ctx)
|
||||||
print '};'
|
print '};'
|
||||||
|
|||||||
@@ -10,39 +10,17 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import re, sys
|
import re, sys
|
||||||
|
|
||||||
def hash(s):
|
|
||||||
h = 0
|
|
||||||
for c in s:
|
|
||||||
h = h * 31 + ord(c)
|
|
||||||
return h & ((1 << 32) - 1)
|
|
||||||
|
|
||||||
entries = []
|
entries = []
|
||||||
for line in sys.stdin:
|
for line in sys.stdin:
|
||||||
m = re.match(r'(\d+)\s+(\S+)\s+(\S.*)?', line)
|
m = re.match(r'(\d+)\s+(\S+)\s+(\S.*)?', line)
|
||||||
val = m.group(3).strip() if m.group(3) else ''
|
val = m.group(3).strip() if m.group(3) else ''
|
||||||
entries.append((hash(m.group(2)), int(m.group(1)), m.group(2), val))
|
entries.append((int(m.group(1)), m.group(2), val))
|
||||||
|
|
||||||
entries.sort()
|
|
||||||
|
|
||||||
print '/* Sorted by hash(name) and its table index */'
|
|
||||||
print 'static nghttp2_hd_static_entry static_table[] = {'
|
|
||||||
for ent in entries:
|
|
||||||
print 'MAKE_STATIC_ENT({}, "{}", "{}", {}u, {}u),'\
|
|
||||||
.format(ent[1] - 1, ent[2], ent[3], ent[0], hash(ent[3]))
|
|
||||||
print '};'
|
|
||||||
|
|
||||||
print ''
|
|
||||||
|
|
||||||
print '/* Index to the position in static_table */'
|
|
||||||
print 'const size_t static_table_index[] = {'
|
|
||||||
for i in range(len(entries)):
|
|
||||||
for j, ent in enumerate(entries):
|
|
||||||
if ent[1] - 1 == i:
|
|
||||||
sys.stdout.write('{: <2d},'.format(j))
|
|
||||||
break
|
|
||||||
if (i + 1) % 16 == 0:
|
|
||||||
sys.stdout.write('\n')
|
|
||||||
else:
|
|
||||||
sys.stdout.write(' ')
|
|
||||||
|
|
||||||
|
print 'static nghttp2_hd_entry static_table[] = {'
|
||||||
|
idx = 0
|
||||||
|
for i, ent in enumerate(entries):
|
||||||
|
if entries[idx][1] != ent[1]:
|
||||||
|
idx = i
|
||||||
|
print 'MAKE_STATIC_ENT("{}", "{}", {}),'\
|
||||||
|
.format(ent[1], ent[2], entries[idx][0] - 1)
|
||||||
print '};'
|
print '};'
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# * The options which do not take argument in the command-line *take*
|
# * The options which do not take argument in the command-line *take*
|
||||||
# argument in the configuration file. Specify 'yes' as argument
|
# argument in the configuration file. Specify 'yes' as argument
|
||||||
# (e.g., spdy-proxy=yes). If other string is given, it disables the
|
# (e.g., http2-proxy=yes). If other string is given, it disables the
|
||||||
# option.
|
# option.
|
||||||
#
|
#
|
||||||
# * To specify private key and certificate file, use private-key-file
|
# * To specify private key and certificate file, use private-key-file
|
||||||
@@ -25,5 +25,5 @@
|
|||||||
# backend=127.0.0.1,80
|
# backend=127.0.0.1,80
|
||||||
# private-key-file=/path/to/server.key
|
# private-key-file=/path/to/server.key
|
||||||
# certificate-file=/path/to/server.crt
|
# certificate-file=/path/to/server.crt
|
||||||
# spdy-proxy=no
|
# http2-proxy=no
|
||||||
# workers=1
|
# workers=1
|
||||||
|
|||||||
4
python/.gitignore
vendored
Normal file
4
python/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# generated files
|
||||||
|
MANIFEST
|
||||||
|
dist/
|
||||||
|
setup.py
|
||||||
@@ -34,6 +34,7 @@ cdef extern from 'nghttp2/nghttp2.h':
|
|||||||
|
|
||||||
ctypedef enum nghttp2_error:
|
ctypedef enum nghttp2_error:
|
||||||
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
|
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
|
||||||
|
NGHTTP2_ERR_DEFERRED
|
||||||
|
|
||||||
ctypedef enum nghttp2_flag:
|
ctypedef enum nghttp2_flag:
|
||||||
NGHTTP2_FLAG_NONE
|
NGHTTP2_FLAG_NONE
|
||||||
@@ -282,6 +283,9 @@ cdef extern from 'nghttp2/nghttp2.h':
|
|||||||
int nghttp2_session_terminate_session(nghttp2_session *session,
|
int nghttp2_session_terminate_session(nghttp2_session *session,
|
||||||
uint32_t error_code)
|
uint32_t error_code)
|
||||||
|
|
||||||
|
int nghttp2_session_resume_data(nghttp2_session *session,
|
||||||
|
int32_t stream_id)
|
||||||
|
|
||||||
const char* nghttp2_strerror(int lib_error_code)
|
const char* nghttp2_strerror(int lib_error_code)
|
||||||
|
|
||||||
int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
|
int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
|
||||||
|
|||||||
@@ -258,19 +258,35 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
asyncio = None
|
asyncio = None
|
||||||
|
|
||||||
|
# body generator flags
|
||||||
|
DATA_OK = 0
|
||||||
|
DATA_EOF = 1
|
||||||
|
DATA_DEFERRED = 2
|
||||||
|
|
||||||
|
class _ByteIOWrapper:
|
||||||
|
|
||||||
|
def __init__(self, b):
|
||||||
|
self.b = b
|
||||||
|
|
||||||
|
def generate(self, n):
|
||||||
|
data = self.b.read1(n)
|
||||||
|
if not data:
|
||||||
|
return None, DATA_EOF
|
||||||
|
return data, DATA_OK
|
||||||
|
|
||||||
def wrap_body(body):
|
def wrap_body(body):
|
||||||
if body is None:
|
if body is None:
|
||||||
return body
|
return body
|
||||||
elif isinstance(body, str):
|
elif isinstance(body, str):
|
||||||
return io.BytesIO(body.encode('utf-8'))
|
return _ByteIOWrapper(io.BytesIO(body.encode('utf-8'))).generate
|
||||||
elif isinstance(body, bytes):
|
elif isinstance(body, bytes):
|
||||||
return io.BytesIO(body)
|
return _ByteIOWrapper(io.BytesIO(body)).generate
|
||||||
elif isinstance(body, io.IOBase):
|
elif isinstance(body, io.IOBase):
|
||||||
return body
|
return _ByteIOWrapper(body).generate
|
||||||
else:
|
else:
|
||||||
raise Exception(('body must be None or instance of str or '
|
# assume that callable in the form f(n) returning tuple byte
|
||||||
'bytes or io.IOBase'))
|
# string and flag.
|
||||||
|
return body
|
||||||
|
|
||||||
cdef _get_stream_user_data(cnghttp2.nghttp2_session *session,
|
cdef _get_stream_user_data(cnghttp2.nghttp2_session *session,
|
||||||
int32_t stream_id):
|
int32_t stream_id):
|
||||||
@@ -488,29 +504,39 @@ cdef int on_stream_close(cnghttp2.nghttp2_session *session,
|
|||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
cdef ssize_t server_data_source_read(cnghttp2.nghttp2_session *session,
|
cdef ssize_t data_source_read(cnghttp2.nghttp2_session *session,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
uint8_t *buf, size_t length,
|
uint8_t *buf, size_t length,
|
||||||
uint32_t *data_flags,
|
uint32_t *data_flags,
|
||||||
cnghttp2.nghttp2_data_source *source,
|
cnghttp2.nghttp2_data_source *source,
|
||||||
void *user_data):
|
void *user_data):
|
||||||
cdef http2 = <_HTTP2SessionCore>user_data
|
cdef http2 = <_HTTP2SessionCoreBase>user_data
|
||||||
handler = <object>source.ptr
|
generator = <object>source.ptr
|
||||||
|
|
||||||
|
http2.enter_callback()
|
||||||
try:
|
try:
|
||||||
data = handler.response_body.read(length)
|
data, flag = generator(length)
|
||||||
except:
|
except:
|
||||||
sys.stderr.write(traceback.format_exc())
|
sys.stderr.write(traceback.format_exc())
|
||||||
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||||
|
finally:
|
||||||
|
http2.leave_callback()
|
||||||
|
|
||||||
|
if flag == DATA_DEFERRED:
|
||||||
|
return cnghttp2.NGHTTP2_ERR_DEFERRED
|
||||||
|
|
||||||
if data:
|
if data:
|
||||||
nread = len(data)
|
nread = len(data)
|
||||||
memcpy(buf, <uint8_t*>data, nread)
|
memcpy(buf, <uint8_t*>data, nread)
|
||||||
return nread
|
else:
|
||||||
|
nread = 0
|
||||||
|
|
||||||
|
if flag == DATA_EOF:
|
||||||
data_flags[0] = cnghttp2.NGHTTP2_DATA_FLAG_EOF
|
data_flags[0] = cnghttp2.NGHTTP2_DATA_FLAG_EOF
|
||||||
|
elif flag != DATA_OK:
|
||||||
|
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
|
||||||
|
|
||||||
return 0
|
return nread
|
||||||
|
|
||||||
cdef int client_on_begin_headers(cnghttp2.nghttp2_session *session,
|
cdef int client_on_begin_headers(cnghttp2.nghttp2_session *session,
|
||||||
const cnghttp2.nghttp2_frame *frame,
|
const cnghttp2.nghttp2_frame *frame,
|
||||||
@@ -595,36 +621,13 @@ cdef int client_on_frame_send(cnghttp2.nghttp2_session *session,
|
|||||||
return 0
|
return 0
|
||||||
http2._start_settings_timer()
|
http2._start_settings_timer()
|
||||||
|
|
||||||
cdef ssize_t client_data_source_read(cnghttp2.nghttp2_session *session,
|
|
||||||
int32_t stream_id,
|
|
||||||
uint8_t *buf, size_t length,
|
|
||||||
uint32_t *data_flags,
|
|
||||||
cnghttp2.nghttp2_data_source *source,
|
|
||||||
void *user_data):
|
|
||||||
cdef http2 = <_HTTP2ClientSessionCore>user_data
|
|
||||||
body = <object>source.ptr
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = body.read(length)
|
|
||||||
except:
|
|
||||||
sys.stderr.write(traceback.format_exc())
|
|
||||||
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
|
||||||
|
|
||||||
if data:
|
|
||||||
nread = len(data)
|
|
||||||
memcpy(buf, <uint8_t*>data, nread)
|
|
||||||
return nread
|
|
||||||
|
|
||||||
data_flags[0] = cnghttp2.NGHTTP2_DATA_FLAG_EOF
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
cdef class _HTTP2SessionCoreBase:
|
cdef class _HTTP2SessionCoreBase:
|
||||||
cdef cnghttp2.nghttp2_session *session
|
cdef cnghttp2.nghttp2_session *session
|
||||||
cdef transport
|
cdef transport
|
||||||
cdef handler_class
|
cdef handler_class
|
||||||
cdef handlers
|
cdef handlers
|
||||||
cdef settings_timer
|
cdef settings_timer
|
||||||
|
cdef inside_callback
|
||||||
|
|
||||||
def __cinit__(self, transport, handler_class=None):
|
def __cinit__(self, transport, handler_class=None):
|
||||||
self.session = NULL
|
self.session = NULL
|
||||||
@@ -632,6 +635,7 @@ cdef class _HTTP2SessionCoreBase:
|
|||||||
self.handler_class = handler_class
|
self.handler_class = handler_class
|
||||||
self.handlers = set()
|
self.handlers = set()
|
||||||
self.settings_timer = None
|
self.settings_timer = None
|
||||||
|
self.inside_callback = False
|
||||||
|
|
||||||
def __dealloc__(self):
|
def __dealloc__(self):
|
||||||
cnghttp2.nghttp2_session_del(self.session)
|
cnghttp2.nghttp2_session_del(self.session)
|
||||||
@@ -668,6 +672,17 @@ cdef class _HTTP2SessionCoreBase:
|
|||||||
cnghttp2.nghttp2_session_want_write(self.session) == 0:
|
cnghttp2.nghttp2_session_want_write(self.session) == 0:
|
||||||
self.transport.close()
|
self.transport.close()
|
||||||
|
|
||||||
|
def resume(self, stream_id):
|
||||||
|
cnghttp2.nghttp2_session_resume_data(self.session, stream_id)
|
||||||
|
if not self.inside_callback:
|
||||||
|
self.send_data()
|
||||||
|
|
||||||
|
def enter_callback(self):
|
||||||
|
self.inside_callback = True
|
||||||
|
|
||||||
|
def leave_callback(self):
|
||||||
|
self.inside_callback = False
|
||||||
|
|
||||||
def _make_handler(self, stream_id):
|
def _make_handler(self, stream_id):
|
||||||
logging.debug('_make_handler, stream_id:%s', stream_id)
|
logging.debug('_make_handler, stream_id:%s', stream_id)
|
||||||
handler = self.handler_class(self, stream_id)
|
handler = self.handler_class(self, stream_id)
|
||||||
@@ -815,8 +830,8 @@ cdef class _HTTP2SessionCore(_HTTP2SessionCoreBase):
|
|||||||
nvlen = _make_nva(&nva, handler.response_headers)
|
nvlen = _make_nva(&nva, handler.response_headers)
|
||||||
|
|
||||||
if handler.response_body:
|
if handler.response_body:
|
||||||
prd.source.ptr = <void*>handler
|
prd.source.ptr = <void*>handler.response_body
|
||||||
prd.read_callback = server_data_source_read
|
prd.read_callback = data_source_read
|
||||||
prd_ptr = &prd
|
prd_ptr = &prd
|
||||||
else:
|
else:
|
||||||
prd_ptr = NULL
|
prd_ptr = NULL
|
||||||
@@ -921,8 +936,8 @@ cdef class _HTTP2ClientSessionCore(_HTTP2SessionCoreBase):
|
|||||||
|
|
||||||
custom_headers = _encode_headers(headers)
|
custom_headers = _encode_headers(headers)
|
||||||
headers = [
|
headers = [
|
||||||
(b':scheme', scheme.encode('utf-8')),
|
|
||||||
(b':method', method.encode('utf-8')),
|
(b':method', method.encode('utf-8')),
|
||||||
|
(b':scheme', scheme.encode('utf-8')),
|
||||||
(b':authority', host.encode('utf-8')),
|
(b':authority', host.encode('utf-8')),
|
||||||
(b':path', path.encode('utf-8'))
|
(b':path', path.encode('utf-8'))
|
||||||
]
|
]
|
||||||
@@ -933,7 +948,7 @@ cdef class _HTTP2ClientSessionCore(_HTTP2SessionCoreBase):
|
|||||||
|
|
||||||
if body:
|
if body:
|
||||||
prd.source.ptr = <void*>body
|
prd.source.ptr = <void*>body
|
||||||
prd.read_callback = client_data_source_read
|
prd.read_callback = data_source_read
|
||||||
prd_ptr = &prd
|
prd_ptr = &prd
|
||||||
else:
|
else:
|
||||||
prd_ptr = NULL
|
prd_ptr = NULL
|
||||||
@@ -1095,8 +1110,26 @@ if asyncio:
|
|||||||
additional response headers. The :status header field is
|
additional response headers. The :status header field is
|
||||||
appended by the library. The body is the response body. It
|
appended by the library. The body is the response body. It
|
||||||
could be None if response body is empty. Or it must be
|
could be None if response body is empty. Or it must be
|
||||||
instance of either str, bytes or io.IOBase. If instance of str
|
instance of either str, bytes, io.IOBase or callable,
|
||||||
is specified, it is encoded using UTF-8.
|
called body generator, which takes one parameter,
|
||||||
|
size. The body generator generates response body. It can
|
||||||
|
pause generation of response so that it can wait for slow
|
||||||
|
backend data generation. When invoked, it should return
|
||||||
|
tuple, byte string and flag. The flag is either DATA_OK,
|
||||||
|
DATA_EOF and DATA_DEFERRED. For non-empty byte string and
|
||||||
|
it is not the last chunk of response, DATA_OK is returned
|
||||||
|
as flag. If this is the last chunk of the response (byte
|
||||||
|
string is possibly None), DATA_EOF must be returned as
|
||||||
|
flag. If there is no data available right now, but
|
||||||
|
additional data are anticipated, return tuple (None,
|
||||||
|
DATA_DEFERRD). When data arrived, call resume() and
|
||||||
|
restart response body transmission.
|
||||||
|
|
||||||
|
Only the body generator can pause response body
|
||||||
|
generation; instance of io.IOBase must not block.
|
||||||
|
|
||||||
|
If instance of str is specified as body, it is encoded
|
||||||
|
using UTF-8.
|
||||||
|
|
||||||
The headers is a list of tuple of the form (name,
|
The headers is a list of tuple of the form (name,
|
||||||
value). The name and value can be either unicode string or
|
value). The name and value can be either unicode string or
|
||||||
@@ -1129,11 +1162,9 @@ if asyncio:
|
|||||||
request_headers parameter).
|
request_headers parameter).
|
||||||
|
|
||||||
The status is HTTP status code. The headers is additional
|
The status is HTTP status code. The headers is additional
|
||||||
response headers. The :status header field is appended by the
|
response headers. The :status header field is appended by
|
||||||
library. The body is the response body. It could be None if
|
the library. The body is the response body. It has the
|
||||||
response body is empty. Or it must be instance of either str,
|
same semantics of body parameter of send_response().
|
||||||
bytes or io.IOBase. If instance of str is specified, it is
|
|
||||||
encoded using UTF-8.
|
|
||||||
|
|
||||||
The headers and request_headers are a list of tuple of the
|
The headers and request_headers are a list of tuple of the
|
||||||
form (name, value). The name and value can be either
|
form (name, value). The name and value can be either
|
||||||
@@ -1161,16 +1192,15 @@ if asyncio:
|
|||||||
promised_handler.path = path.encode('utf-8')
|
promised_handler.path = path.encode('utf-8')
|
||||||
promised_handler._set_response_prop(status, headers, body)
|
promised_handler._set_response_prop(status, headers, body)
|
||||||
|
|
||||||
if request_headers is None:
|
headers = [
|
||||||
request_headers = []
|
(b':method', promised_handler.method),
|
||||||
|
(b':scheme', promised_handler.scheme),
|
||||||
|
(b':authority', promised_handler.host),
|
||||||
|
(b':path', promised_handler.path)
|
||||||
|
]
|
||||||
|
headers.extend(_encode_headers(request_headers))
|
||||||
|
|
||||||
request_headers = _encode_headers(request_headers)
|
promised_handler.headers = headers
|
||||||
request_headers.append((b':scheme', promised_handler.scheme))
|
|
||||||
request_headers.append((b':method', promised_handler.method))
|
|
||||||
request_headers.append((b':authority', promised_handler.host))
|
|
||||||
request_headers.append((b':path', promised_handler.path))
|
|
||||||
|
|
||||||
promised_handler.headers = request_headers
|
|
||||||
|
|
||||||
return self.http2.push(self, promised_handler)
|
return self.http2.push(self, promised_handler)
|
||||||
|
|
||||||
@@ -1180,12 +1210,14 @@ if asyncio:
|
|||||||
if headers is None:
|
if headers is None:
|
||||||
headers = []
|
headers = []
|
||||||
|
|
||||||
self.response_headers = _encode_headers(headers)
|
self.response_headers = [(b':status', str(status).encode('utf-8'))]
|
||||||
self.response_headers.append((b':status', str(status)\
|
self.response_headers.extend(_encode_headers(headers))
|
||||||
.encode('utf-8')))
|
|
||||||
|
|
||||||
self.response_body = body
|
self.response_body = body
|
||||||
|
|
||||||
|
def resume(self):
|
||||||
|
self.http2.resume(self.stream_id)
|
||||||
|
|
||||||
def _encode_headers(headers):
|
def _encode_headers(headers):
|
||||||
if not headers:
|
if not headers:
|
||||||
return []
|
return []
|
||||||
@@ -1432,6 +1464,9 @@ if asyncio:
|
|||||||
'''
|
'''
|
||||||
self.http2.push(push_promise, handler)
|
self.http2.push(push_promise, handler)
|
||||||
|
|
||||||
|
def resume(self):
|
||||||
|
self.http2.resume(self.stream_id)
|
||||||
|
|
||||||
class _HTTP2ClientSession(asyncio.Protocol):
|
class _HTTP2ClientSession(asyncio.Protocol):
|
||||||
|
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ setup(
|
|||||||
author = 'Tatsuhiro Tsujikawa',
|
author = 'Tatsuhiro Tsujikawa',
|
||||||
version = '@PACKAGE_VERSION@',
|
version = '@PACKAGE_VERSION@',
|
||||||
author_email = 'tatsuhiro.t@gmail.com',
|
author_email = 'tatsuhiro.t@gmail.com',
|
||||||
url = 'http://tatsuhiro-t.github.io/nghttp2/',
|
url = 'https://nghttp2.org/',
|
||||||
keywords = [],
|
keywords = [],
|
||||||
ext_modules = [Extension("nghttp2",
|
ext_modules = [Extension("nghttp2",
|
||||||
["nghttp2.c"],
|
["nghttp2.c"],
|
||||||
|
|||||||
20
src/.gitignore
vendored
20
src/.gitignore
vendored
@@ -1,12 +1,16 @@
|
|||||||
|
# generated files
|
||||||
|
libnghttp2_asio.pc
|
||||||
|
|
||||||
|
# programs
|
||||||
|
deflatehd
|
||||||
|
h2load
|
||||||
|
inflatehd
|
||||||
nghttp
|
nghttp
|
||||||
nghttpd
|
nghttpd
|
||||||
nghttpx
|
nghttpx
|
||||||
nghttpx-unittest
|
|
||||||
nghttpx-unittest.log
|
# build
|
||||||
nghttpx-unittest.trs
|
|
||||||
test-suite.log
|
|
||||||
.dirstamp
|
|
||||||
libnghttpx.a
|
libnghttpx.a
|
||||||
deflatehd
|
|
||||||
inflatehd
|
# tests
|
||||||
h2load
|
nghttpx-unittest
|
||||||
|
|||||||
@@ -30,7 +30,8 @@
|
|||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|
||||||
ParserData::ParserData(const std::string &base_uri) : base_uri(base_uri) {}
|
ParserData::ParserData(const std::string &base_uri)
|
||||||
|
: base_uri(base_uri), inside_head(0) {}
|
||||||
|
|
||||||
HtmlParser::HtmlParser(const std::string &base_uri)
|
HtmlParser::HtmlParser(const std::string &base_uri)
|
||||||
: base_uri_(base_uri), parser_ctx_(nullptr), parser_data_(base_uri) {}
|
: base_uri_(base_uri), parser_ctx_(nullptr), parser_data_(base_uri) {}
|
||||||
@@ -52,13 +53,13 @@ const char *get_attr(const xmlChar **attrs, const char *name) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void add_link(ParserData *parser_data, const char *uri, RequestPriority pri) {
|
void add_link(ParserData *parser_data, const char *uri, ResourceType res_type) {
|
||||||
auto u = xmlBuildURI(
|
auto u = xmlBuildURI(
|
||||||
reinterpret_cast<const xmlChar *>(uri),
|
reinterpret_cast<const xmlChar *>(uri),
|
||||||
reinterpret_cast<const xmlChar *>(parser_data->base_uri.c_str()));
|
reinterpret_cast<const xmlChar *>(parser_data->base_uri.c_str()));
|
||||||
if (u) {
|
if (u) {
|
||||||
parser_data->links.push_back(
|
parser_data->links.push_back(
|
||||||
std::make_pair(reinterpret_cast<char *>(u), pri));
|
std::make_pair(reinterpret_cast<char *>(u), res_type));
|
||||||
free(u);
|
free(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,6 +69,9 @@ namespace {
|
|||||||
void start_element_func(void *user_data, const xmlChar *name,
|
void start_element_func(void *user_data, const xmlChar *name,
|
||||||
const xmlChar **attrs) {
|
const xmlChar **attrs) {
|
||||||
auto parser_data = static_cast<ParserData *>(user_data);
|
auto parser_data = static_cast<ParserData *>(user_data);
|
||||||
|
if (util::strieq(reinterpret_cast<const char *>(name), "head")) {
|
||||||
|
++parser_data->inside_head;
|
||||||
|
}
|
||||||
if (util::strieq(reinterpret_cast<const char *>(name), "link")) {
|
if (util::strieq(reinterpret_cast<const char *>(name), "link")) {
|
||||||
auto rel_attr = get_attr(attrs, "rel");
|
auto rel_attr = get_attr(attrs, "rel");
|
||||||
auto href_attr = get_attr(attrs, "href");
|
auto href_attr = get_attr(attrs, "href");
|
||||||
@@ -75,22 +79,35 @@ void start_element_func(void *user_data, const xmlChar *name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (util::strieq(rel_attr, "shortcut icon")) {
|
if (util::strieq(rel_attr, "shortcut icon")) {
|
||||||
add_link(parser_data, href_attr, REQ_PRI_LOWEST);
|
add_link(parser_data, href_attr, REQ_OTHERS);
|
||||||
} else if (util::strieq(rel_attr, "stylesheet")) {
|
} else if (util::strieq(rel_attr, "stylesheet")) {
|
||||||
add_link(parser_data, href_attr, REQ_PRI_MEDIUM);
|
add_link(parser_data, href_attr, REQ_CSS);
|
||||||
}
|
}
|
||||||
} else if (util::strieq(reinterpret_cast<const char *>(name), "img")) {
|
} else if (util::strieq(reinterpret_cast<const char *>(name), "img")) {
|
||||||
auto src_attr = get_attr(attrs, "src");
|
auto src_attr = get_attr(attrs, "src");
|
||||||
if (!src_attr) {
|
if (!src_attr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
add_link(parser_data, src_attr, REQ_PRI_LOWEST);
|
add_link(parser_data, src_attr, REQ_IMG);
|
||||||
} else if (util::strieq(reinterpret_cast<const char *>(name), "script")) {
|
} else if (util::strieq(reinterpret_cast<const char *>(name), "script")) {
|
||||||
auto src_attr = get_attr(attrs, "src");
|
auto src_attr = get_attr(attrs, "src");
|
||||||
if (!src_attr) {
|
if (!src_attr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
add_link(parser_data, src_attr, REQ_PRI_LOW);
|
if (parser_data->inside_head) {
|
||||||
|
add_link(parser_data, src_attr, REQ_JS);
|
||||||
|
} else {
|
||||||
|
add_link(parser_data, src_attr, REQ_UNBLOCK_JS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void end_element_func(void *user_data, const xmlChar *name) {
|
||||||
|
auto parser_data = static_cast<ParserData *>(user_data);
|
||||||
|
if (util::strieq(reinterpret_cast<const char *>(name), "head")) {
|
||||||
|
--parser_data->inside_head;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -112,7 +129,7 @@ xmlSAXHandler saxHandler = {
|
|||||||
nullptr, // startDocumentSAXFunc
|
nullptr, // startDocumentSAXFunc
|
||||||
nullptr, // endDocumentSAXFunc
|
nullptr, // endDocumentSAXFunc
|
||||||
&start_element_func, // startElementSAXFunc
|
&start_element_func, // startElementSAXFunc
|
||||||
nullptr, // endElementSAXFunc
|
&end_element_func, // endElementSAXFunc
|
||||||
nullptr, // referenceSAXFunc
|
nullptr, // referenceSAXFunc
|
||||||
nullptr, // charactersSAXFunc
|
nullptr, // charactersSAXFunc
|
||||||
nullptr, // ignorableWhitespaceSAXFunc
|
nullptr, // ignorableWhitespaceSAXFunc
|
||||||
@@ -160,7 +177,7 @@ int HtmlParser::parse_chunk_internal(const char *chunk, size_t size, int fin) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::pair<std::string, RequestPriority>> &
|
const std::vector<std::pair<std::string, ResourceType>> &
|
||||||
HtmlParser::get_links() const {
|
HtmlParser::get_links() const {
|
||||||
return parser_data_.links;
|
return parser_data_.links;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,16 +38,19 @@
|
|||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|
||||||
enum RequestPriority {
|
enum ResourceType {
|
||||||
REQ_PRI_HIGH = 0,
|
REQ_CSS = 1,
|
||||||
REQ_PRI_MEDIUM = 1,
|
REQ_JS,
|
||||||
REQ_PRI_LOW = 2,
|
REQ_UNBLOCK_JS,
|
||||||
REQ_PRI_LOWEST = 3
|
REQ_IMG,
|
||||||
|
REQ_OTHERS,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ParserData {
|
struct ParserData {
|
||||||
std::string base_uri;
|
std::string base_uri;
|
||||||
std::vector<std::pair<std::string, RequestPriority>> links;
|
std::vector<std::pair<std::string, ResourceType>> links;
|
||||||
|
// > 0 if we are inside "head" element.
|
||||||
|
int inside_head;
|
||||||
ParserData(const std::string &base_uri);
|
ParserData(const std::string &base_uri);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -58,7 +61,7 @@ public:
|
|||||||
HtmlParser(const std::string &base_uri);
|
HtmlParser(const std::string &base_uri);
|
||||||
~HtmlParser();
|
~HtmlParser();
|
||||||
int parse_chunk(const char *chunk, size_t size, int fin);
|
int parse_chunk(const char *chunk, size_t size, int fin);
|
||||||
const std::vector<std::pair<std::string, RequestPriority>> &get_links() const;
|
const std::vector<std::pair<std::string, ResourceType>> &get_links() const;
|
||||||
void clear_links();
|
void clear_links();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -75,14 +78,13 @@ class HtmlParser {
|
|||||||
public:
|
public:
|
||||||
HtmlParser(const std::string &base_uri) {}
|
HtmlParser(const std::string &base_uri) {}
|
||||||
int parse_chunk(const char *chunk, size_t size, int fin) { return 0; }
|
int parse_chunk(const char *chunk, size_t size, int fin) { return 0; }
|
||||||
const std::vector<std::pair<std::string, RequestPriority>> &
|
const std::vector<std::pair<std::string, ResourceType>> &get_links() const {
|
||||||
get_links() const {
|
|
||||||
return links_;
|
return links_;
|
||||||
}
|
}
|
||||||
void clear_links() {}
|
void clear_links() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::pair<std::string, RequestPriority>> links_;
|
std::vector<std::pair<std::string, ResourceType>> links_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !HAVE_LIBXML2
|
#endif // !HAVE_LIBXML2
|
||||||
|
|||||||
@@ -57,11 +57,6 @@
|
|||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const std::string STATUS_200 = "200";
|
|
||||||
const std::string STATUS_301 = "301";
|
|
||||||
const std::string STATUS_304 = "304";
|
|
||||||
const std::string STATUS_400 = "400";
|
|
||||||
const std::string STATUS_404 = "404";
|
|
||||||
const std::string DEFAULT_HTML = "index.html";
|
const std::string DEFAULT_HTML = "index.html";
|
||||||
const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION;
|
const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION;
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -94,9 +89,9 @@ template <typename Array> void append_nv(Stream *stream, const Array &nva) {
|
|||||||
Config::Config()
|
Config::Config()
|
||||||
: stream_read_timeout(60.), stream_write_timeout(60.),
|
: stream_read_timeout(60.), stream_write_timeout(60.),
|
||||||
session_option(nullptr), data_ptr(nullptr), padding(0), num_worker(1),
|
session_option(nullptr), data_ptr(nullptr), padding(0), num_worker(1),
|
||||||
header_table_size(-1), port(0), verbose(false), daemon(false),
|
max_concurrent_streams(100), header_table_size(-1), port(0),
|
||||||
verify_client(false), no_tls(false), error_gzip(false),
|
verbose(false), daemon(false), verify_client(false), no_tls(false),
|
||||||
early_response(false) {
|
error_gzip(false), early_response(false), hexdump(false) {
|
||||||
nghttp2_option_new(&session_option);
|
nghttp2_option_new(&session_option);
|
||||||
nghttp2_option_set_recv_client_preface(session_option, 1);
|
nghttp2_option_set_recv_client_preface(session_option, 1);
|
||||||
}
|
}
|
||||||
@@ -171,9 +166,10 @@ void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config);
|
|||||||
|
|
||||||
class Sessions {
|
class Sessions {
|
||||||
public:
|
public:
|
||||||
Sessions(struct ev_loop *loop, const Config *config, SSL_CTX *ssl_ctx)
|
Sessions(HttpServer *sv, struct ev_loop *loop, const Config *config,
|
||||||
: loop_(loop), config_(config), ssl_ctx_(ssl_ctx), callbacks_(nullptr),
|
SSL_CTX *ssl_ctx)
|
||||||
next_session_id_(1), tstamp_cached_(ev_now(loop)),
|
: sv_(sv), loop_(loop), config_(config), ssl_ctx_(ssl_ctx),
|
||||||
|
callbacks_(nullptr), next_session_id_(1), tstamp_cached_(ev_now(loop)),
|
||||||
cached_date_(util::http_date(tstamp_cached_)) {
|
cached_date_(util::http_date(tstamp_cached_)) {
|
||||||
nghttp2_session_callbacks_new(&callbacks_);
|
nghttp2_session_callbacks_new(&callbacks_);
|
||||||
|
|
||||||
@@ -229,7 +225,7 @@ public:
|
|||||||
make_unique<Http2Handler>(this, fd, ssl, get_next_session_id());
|
make_unique<Http2Handler>(this, fd, ssl, get_next_session_id());
|
||||||
handler->setup_bev();
|
handler->setup_bev();
|
||||||
if (!ssl) {
|
if (!ssl) {
|
||||||
if (handler->on_connect() != 0) {
|
if (handler->connection_made() != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,9 +240,37 @@ public:
|
|||||||
}
|
}
|
||||||
return cached_date_;
|
return cached_date_;
|
||||||
}
|
}
|
||||||
|
FileEntry *get_cached_fd(const std::string &path) {
|
||||||
|
auto i = fd_cache_.find(path);
|
||||||
|
if (i == std::end(fd_cache_)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto &ent = (*i).second;
|
||||||
|
++ent.usecount;
|
||||||
|
return &ent;
|
||||||
|
}
|
||||||
|
FileEntry *cache_fd(const std::string &path, const FileEntry &ent) {
|
||||||
|
auto rv = fd_cache_.emplace(path, ent);
|
||||||
|
return &(*rv.first).second;
|
||||||
|
}
|
||||||
|
void release_fd(const std::string &path) {
|
||||||
|
auto i = fd_cache_.find(path);
|
||||||
|
if (i == std::end(fd_cache_)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &ent = (*i).second;
|
||||||
|
if (--ent.usecount == 0) {
|
||||||
|
close(ent.fd);
|
||||||
|
fd_cache_.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const HttpServer *get_server() const { return sv_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<Http2Handler *> handlers_;
|
std::set<Http2Handler *> handlers_;
|
||||||
|
// cache for file descriptors to read file.
|
||||||
|
std::map<std::string, FileEntry> fd_cache_;
|
||||||
|
HttpServer *sv_;
|
||||||
struct ev_loop *loop_;
|
struct ev_loop *loop_;
|
||||||
const Config *config_;
|
const Config *config_;
|
||||||
SSL_CTX *ssl_ctx_;
|
SSL_CTX *ssl_ctx_;
|
||||||
@@ -257,7 +281,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Stream::Stream(Http2Handler *handler, int32_t stream_id)
|
Stream::Stream(Http2Handler *handler, int32_t stream_id)
|
||||||
: handler(handler), body_left(0), stream_id(stream_id), file(-1) {
|
: handler(handler), file_ent(nullptr), body_length(0), body_offset(0),
|
||||||
|
stream_id(stream_id) {
|
||||||
auto config = handler->get_config();
|
auto config = handler->get_config();
|
||||||
ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
|
ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
|
||||||
ev_timer_init(&wtimer, stream_timeout_cb, 0., config->stream_write_timeout);
|
ev_timer_init(&wtimer, stream_timeout_cb, 0., config->stream_write_timeout);
|
||||||
@@ -270,8 +295,9 @@ Stream::Stream(Http2Handler *handler, int32_t stream_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Stream::~Stream() {
|
Stream::~Stream() {
|
||||||
if (file != -1) {
|
if (file_ent != nullptr) {
|
||||||
close(file);
|
auto sessions = handler->get_sessions();
|
||||||
|
sessions->release_fd(file_ent->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto loop = handler->get_loop();
|
auto loop = handler->get_loop();
|
||||||
@@ -371,6 +397,8 @@ struct ev_loop *Http2Handler::get_loop() const {
|
|||||||
return sessions_->get_loop();
|
return sessions_->get_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Http2Handler::WriteBuf *Http2Handler::get_wb() { return &wb_; }
|
||||||
|
|
||||||
int Http2Handler::setup_bev() { return 0; }
|
int Http2Handler::setup_bev() { return 0; }
|
||||||
|
|
||||||
int Http2Handler::fill_wb() {
|
int Http2Handler::fill_wb() {
|
||||||
@@ -426,6 +454,11 @@ int Http2Handler::read_clear() {
|
|||||||
if (nread == 0) {
|
if (nread == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (get_config()->hexdump) {
|
||||||
|
util::hexdump(stdout, buf.data(), nread);
|
||||||
|
}
|
||||||
|
|
||||||
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
|
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
|
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
|
||||||
@@ -515,7 +548,7 @@ int Http2Handler::tls_handshake() {
|
|||||||
read_ = &Http2Handler::read_tls;
|
read_ = &Http2Handler::read_tls;
|
||||||
write_ = &Http2Handler::write_tls;
|
write_ = &Http2Handler::write_tls;
|
||||||
|
|
||||||
if (on_connect() != 0) {
|
if (connection_made() != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,6 +581,11 @@ int Http2Handler::read_tls() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto nread = rv;
|
auto nread = rv;
|
||||||
|
|
||||||
|
if (get_config()->hexdump) {
|
||||||
|
util::hexdump(stdout, buf.data(), nread);
|
||||||
|
}
|
||||||
|
|
||||||
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
|
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
|
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
|
||||||
@@ -619,11 +657,13 @@ int Http2Handler::on_read() { return read_(*this); }
|
|||||||
|
|
||||||
int Http2Handler::on_write() { return write_(*this); }
|
int Http2Handler::on_write() { return write_(*this); }
|
||||||
|
|
||||||
int Http2Handler::on_connect() {
|
int Http2Handler::connection_made() {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
auto config = sessions_->get_config();
|
||||||
|
|
||||||
r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
|
r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
|
||||||
sessions_->get_config()->session_option);
|
config->session_option);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -631,11 +671,11 @@ int Http2Handler::on_connect() {
|
|||||||
size_t niv = 1;
|
size_t niv = 1;
|
||||||
|
|
||||||
entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||||
entry[0].value = 100;
|
entry[0].value = config->max_concurrent_streams;
|
||||||
|
|
||||||
if (sessions_->get_config()->header_table_size >= 0) {
|
if (config->header_table_size >= 0) {
|
||||||
entry[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
entry[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||||
entry[niv].value = sessions_->get_config()->header_table_size;
|
entry[niv].value = config->header_table_size;
|
||||||
++niv;
|
++niv;
|
||||||
}
|
}
|
||||||
r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(), niv);
|
r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(), niv);
|
||||||
@@ -823,21 +863,12 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
|||||||
auto hd = static_cast<Http2Handler *>(user_data);
|
auto hd = static_cast<Http2Handler *>(user_data);
|
||||||
auto stream = hd->get_stream(stream_id);
|
auto stream = hd->get_stream(stream_id);
|
||||||
|
|
||||||
int fd = source->fd;
|
auto nread = std::min(stream->body_length - stream->body_offset,
|
||||||
ssize_t nread;
|
static_cast<int64_t>(length));
|
||||||
|
|
||||||
while ((nread = read(fd, buf, length)) == -1 && errno == EINTR)
|
*data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
|
||||||
;
|
|
||||||
|
|
||||||
if (nread == -1) {
|
if (nread == 0 || stream->body_length == stream->body_offset + nread) {
|
||||||
remove_stream_read_timeout(stream);
|
|
||||||
remove_stream_write_timeout(stream);
|
|
||||||
|
|
||||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream->body_left -= nread;
|
|
||||||
if (nread == 0 || stream->body_left <= 0) {
|
|
||||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||||
|
|
||||||
auto config = hd->get_config();
|
auto config = hd->get_config();
|
||||||
@@ -869,59 +900,27 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void prepare_status_response(Stream *stream, Http2Handler *hd,
|
void prepare_status_response(Stream *stream, Http2Handler *hd, int status) {
|
||||||
const std::string &status) {
|
auto sessions = hd->get_sessions();
|
||||||
int pipefd[2];
|
auto status_page = sessions->get_server()->get_status_page(status);
|
||||||
if (status == STATUS_304 || pipe(pipefd) == -1) {
|
auto file_ent = &status_page->file_ent;
|
||||||
hd->submit_response(status, stream->stream_id, 0);
|
|
||||||
return;
|
// we don't set stream->file_ent since we don't want to expire it.
|
||||||
}
|
stream->body_length = file_ent->length;
|
||||||
std::string body;
|
nghttp2_data_provider data_prd;
|
||||||
body.reserve(256);
|
data_prd.source.fd = file_ent->fd;
|
||||||
body = "<html><head><title>";
|
data_prd.read_callback = file_read_callback;
|
||||||
body += status;
|
|
||||||
body += "</title></head><body><h1>";
|
|
||||||
body += status;
|
|
||||||
body += "</h1><hr><address>";
|
|
||||||
body += NGHTTPD_SERVER;
|
|
||||||
body += " at port ";
|
|
||||||
body += util::utos(hd->get_config()->port);
|
|
||||||
body += "</address>";
|
|
||||||
body += "</body></html>";
|
|
||||||
|
|
||||||
Headers headers;
|
Headers headers;
|
||||||
if (hd->get_config()->error_gzip) {
|
|
||||||
gzFile write_fd = gzdopen(pipefd[1], "w");
|
|
||||||
gzwrite(write_fd, body.c_str(), body.size());
|
|
||||||
gzclose(write_fd);
|
|
||||||
headers.emplace_back("content-encoding", "gzip");
|
|
||||||
} else {
|
|
||||||
ssize_t rv;
|
|
||||||
|
|
||||||
while ((rv = write(pipefd[1], body.c_str(), body.size())) == -1 &&
|
|
||||||
errno == EINTR)
|
|
||||||
;
|
|
||||||
|
|
||||||
if (rv != static_cast<ssize_t>(body.size())) {
|
|
||||||
std::cerr << "Could not write all response body: " << rv << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(pipefd[1]);
|
|
||||||
|
|
||||||
stream->file = pipefd[0];
|
|
||||||
stream->body_left = body.size();
|
|
||||||
nghttp2_data_provider data_prd;
|
|
||||||
data_prd.source.fd = pipefd[0];
|
|
||||||
data_prd.read_callback = file_read_callback;
|
|
||||||
headers.emplace_back("content-type", "text/html; charset=UTF-8");
|
headers.emplace_back("content-type", "text/html; charset=UTF-8");
|
||||||
hd->submit_response(status, stream->stream_id, headers, &data_prd);
|
hd->submit_response(status_page->status, stream->stream_id, headers,
|
||||||
|
&data_prd);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void prepare_redirect_response(Stream *stream, Http2Handler *hd,
|
void prepare_redirect_response(Stream *stream, Http2Handler *hd,
|
||||||
const std::string &path,
|
const std::string &path, int status) {
|
||||||
const std::string &status) {
|
|
||||||
auto scheme =
|
auto scheme =
|
||||||
http2::get_header(stream->hdidx, http2::HD__SCHEME, stream->headers);
|
http2::get_header(stream->hdidx, http2::HD__SCHEME, stream->headers);
|
||||||
auto authority =
|
auto authority =
|
||||||
@@ -938,7 +937,10 @@ void prepare_redirect_response(Stream *stream, Http2Handler *hd,
|
|||||||
|
|
||||||
auto headers = Headers{{"location", redirect_url}};
|
auto headers = Headers{{"location", redirect_url}};
|
||||||
|
|
||||||
hd->submit_response(status, stream->stream_id, headers, nullptr);
|
auto sessions = hd->get_sessions();
|
||||||
|
auto status_page = sessions->get_server()->get_status_page(status);
|
||||||
|
|
||||||
|
hd->submit_response(status_page->status, stream->stream_id, headers, nullptr);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -972,7 +974,7 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
|||||||
|
|
||||||
url = util::percentDecode(url.begin(), url.end());
|
url = util::percentDecode(url.begin(), url.end());
|
||||||
if (!util::check_path(url)) {
|
if (!util::check_path(url)) {
|
||||||
prepare_status_response(stream, hd, STATUS_404);
|
prepare_status_response(stream, hd, 404);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto push_itr = hd->get_config()->push.find(url);
|
auto push_itr = hd->get_config()->push.find(url);
|
||||||
@@ -989,9 +991,14 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
|||||||
if (path[path.size() - 1] == '/') {
|
if (path[path.size() - 1] == '/') {
|
||||||
path += DEFAULT_HTML;
|
path += DEFAULT_HTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto sessions = hd->get_sessions();
|
||||||
|
auto file_ent = sessions->get_cached_fd(path);
|
||||||
|
|
||||||
|
if (file_ent == nullptr) {
|
||||||
int file = open(path.c_str(), O_RDONLY | O_BINARY);
|
int file = open(path.c_str(), O_RDONLY | O_BINARY);
|
||||||
if (file == -1) {
|
if (file == -1) {
|
||||||
prepare_status_response(stream, hd, STATUS_404);
|
prepare_status_response(stream, hd, 404);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1000,7 +1007,7 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
|||||||
|
|
||||||
if (fstat(file, &buf) == -1) {
|
if (fstat(file, &buf) == -1) {
|
||||||
close(file);
|
close(file);
|
||||||
prepare_status_response(stream, hd, STATUS_404);
|
prepare_status_response(stream, hd, 404);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1014,26 +1021,36 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
|||||||
reqpath.insert(query_pos, "/");
|
reqpath.insert(query_pos, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_redirect_response(stream, hd, reqpath, STATUS_301);
|
prepare_redirect_response(stream, hd, reqpath, 301);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->file = file;
|
if (last_mod_found && buf.st_mtime <= last_mod) {
|
||||||
stream->body_left = buf.st_size;
|
close(file);
|
||||||
|
prepare_status_response(stream, hd, 304);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_ent = sessions->cache_fd(
|
||||||
|
path, FileEntry(path, buf.st_size, buf.st_mtime, file));
|
||||||
|
} else if (last_mod_found && file_ent->mtime <= last_mod) {
|
||||||
|
sessions->release_fd(file_ent->path);
|
||||||
|
prepare_status_response(stream, hd, 304);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->file_ent = file_ent;
|
||||||
|
stream->body_length = file_ent->length;
|
||||||
|
|
||||||
nghttp2_data_provider data_prd;
|
nghttp2_data_provider data_prd;
|
||||||
|
|
||||||
data_prd.source.fd = file;
|
data_prd.source.fd = file_ent->fd;
|
||||||
data_prd.read_callback = file_read_callback;
|
data_prd.read_callback = file_read_callback;
|
||||||
|
|
||||||
if (last_mod_found && buf.st_mtime <= last_mod) {
|
hd->submit_file_response("200", stream, file_ent->mtime, file_ent->length,
|
||||||
prepare_status_response(stream, hd, STATUS_304);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hd->submit_file_response(STATUS_200, stream, buf.st_mtime, buf.st_size,
|
|
||||||
&data_prd);
|
&data_prd);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -1210,6 +1227,58 @@ int hd_on_frame_send_callback(nghttp2_session *session,
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int send_data_callback(nghttp2_session *session, nghttp2_frame *frame,
|
||||||
|
const uint8_t *framehd, size_t length,
|
||||||
|
nghttp2_data_source *source, void *user_data) {
|
||||||
|
auto hd = static_cast<Http2Handler *>(user_data);
|
||||||
|
auto wb = hd->get_wb();
|
||||||
|
auto padlen = frame->data.padlen;
|
||||||
|
auto stream = hd->get_stream(frame->hd.stream_id);
|
||||||
|
|
||||||
|
if (wb->wleft() < 9 + length + padlen) {
|
||||||
|
return NGHTTP2_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = source->fd;
|
||||||
|
|
||||||
|
auto p = wb->last;
|
||||||
|
|
||||||
|
p = std::copy_n(framehd, 9, p);
|
||||||
|
|
||||||
|
if (padlen) {
|
||||||
|
*p++ = padlen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length) {
|
||||||
|
ssize_t nread;
|
||||||
|
while ((nread = pread(fd, p, length, stream->body_offset)) == -1 &&
|
||||||
|
errno == EINTR)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (nread == -1) {
|
||||||
|
remove_stream_read_timeout(stream);
|
||||||
|
remove_stream_write_timeout(stream);
|
||||||
|
|
||||||
|
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->body_offset += nread;
|
||||||
|
length -= nread;
|
||||||
|
p += nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (padlen) {
|
||||||
|
std::fill(p, p + padlen - 1, 0);
|
||||||
|
p += padlen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wb->last = p;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
ssize_t select_padding_callback(nghttp2_session *session,
|
ssize_t select_padding_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame, size_t max_payload,
|
const nghttp2_frame *frame, size_t max_payload,
|
||||||
@@ -1278,6 +1347,9 @@ void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config) {
|
|||||||
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||||
callbacks, on_begin_headers_callback);
|
callbacks, on_begin_headers_callback);
|
||||||
|
|
||||||
|
nghttp2_session_callbacks_set_send_data_callback(callbacks,
|
||||||
|
send_data_callback);
|
||||||
|
|
||||||
if (config->padding) {
|
if (config->padding) {
|
||||||
nghttp2_session_callbacks_set_select_padding_callback(
|
nghttp2_session_callbacks_set_select_padding_callback(
|
||||||
callbacks, select_padding_callback);
|
callbacks, select_padding_callback);
|
||||||
@@ -1324,7 +1396,7 @@ void run_worker(Worker *worker) {
|
|||||||
|
|
||||||
class AcceptHandler {
|
class AcceptHandler {
|
||||||
public:
|
public:
|
||||||
AcceptHandler(Sessions *sessions, const Config *config)
|
AcceptHandler(HttpServer *sv, Sessions *sessions, const Config *config)
|
||||||
: sessions_(sessions), config_(config), next_worker_(0) {
|
: sessions_(sessions), config_(config), next_worker_(0) {
|
||||||
if (config_->num_worker == 1) {
|
if (config_->num_worker == 1) {
|
||||||
return;
|
return;
|
||||||
@@ -1336,7 +1408,7 @@ public:
|
|||||||
auto worker = make_unique<Worker>();
|
auto worker = make_unique<Worker>();
|
||||||
auto loop = ev_loop_new(0);
|
auto loop = ev_loop_new(0);
|
||||||
worker->sessions =
|
worker->sessions =
|
||||||
make_unique<Sessions>(loop, config_, sessions_->get_ssl_ctx());
|
make_unique<Sessions>(sv, loop, config_, sessions_->get_ssl_ctx());
|
||||||
ev_async_init(&worker->w, worker_acceptcb);
|
ev_async_init(&worker->w, worker_acceptcb);
|
||||||
worker->w.data = worker.get();
|
worker->w.data = worker.get();
|
||||||
ev_async_start(loop, &worker->w);
|
ev_async_start(loop, &worker->w);
|
||||||
@@ -1420,7 +1492,61 @@ void acceptcb(struct ev_loop *loop, ev_io *w, int revents) {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
HttpServer::HttpServer(const Config *config) : config_(config) {}
|
namespace {
|
||||||
|
FileEntry make_status_body(int status, uint16_t port) {
|
||||||
|
std::string body;
|
||||||
|
body = "<html><head><title>";
|
||||||
|
body += http2::get_status_string(status);
|
||||||
|
body += "</title></head><body><h1>";
|
||||||
|
body += http2::get_status_string(status);
|
||||||
|
body += "</h1><hr><address>";
|
||||||
|
body += NGHTTPD_SERVER;
|
||||||
|
body += " at port ";
|
||||||
|
body += util::utos(port);
|
||||||
|
body += "</address>";
|
||||||
|
body += "</body></html>";
|
||||||
|
|
||||||
|
char tempfn[] = "/tmp/nghttpd.temp.XXXXXX";
|
||||||
|
int fd = mkstemp(tempfn);
|
||||||
|
if (fd == -1) {
|
||||||
|
auto error = errno;
|
||||||
|
std::cerr << "Could not open status response body file: errno=" << error;
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
unlink(tempfn);
|
||||||
|
ssize_t nwrite;
|
||||||
|
while ((nwrite = write(fd, body.c_str(), body.size())) == -1 &&
|
||||||
|
errno == EINTR)
|
||||||
|
;
|
||||||
|
if (nwrite == -1) {
|
||||||
|
auto error = errno;
|
||||||
|
std::cerr << "Could not write status response body into file: errno="
|
||||||
|
<< error;
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileEntry(util::utos(status), nwrite, 0, fd);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// index into HttpServer::status_pages_
|
||||||
|
enum {
|
||||||
|
IDX_200,
|
||||||
|
IDX_301,
|
||||||
|
IDX_304,
|
||||||
|
IDX_400,
|
||||||
|
IDX_404,
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpServer::HttpServer(const Config *config) : config_(config) {
|
||||||
|
status_pages_ = std::vector<StatusPage>{
|
||||||
|
{"200", make_status_body(200, config_->port)},
|
||||||
|
{"301", make_status_body(301, config_->port)},
|
||||||
|
{"304", make_status_body(304, config_->port)},
|
||||||
|
{"400", make_status_body(400, config_->port)},
|
||||||
|
{"404", make_status_body(404, config_->port)},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
|
int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
|
||||||
@@ -1441,14 +1567,14 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int start_listen(struct ev_loop *loop, Sessions *sessions,
|
int start_listen(HttpServer *sv, struct ev_loop *loop, Sessions *sessions,
|
||||||
const Config *config) {
|
const Config *config) {
|
||||||
addrinfo hints;
|
addrinfo hints;
|
||||||
int r;
|
int r;
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
const char *addr = nullptr;
|
const char *addr = nullptr;
|
||||||
|
|
||||||
auto acceptor = std::make_shared<AcceptHandler>(sessions, config);
|
auto acceptor = std::make_shared<AcceptHandler>(sv, sessions, config);
|
||||||
auto service = util::utos(config->port);
|
auto service = util::utos(config->port);
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(addrinfo));
|
memset(&hints, 0, sizeof(addrinfo));
|
||||||
@@ -1643,8 +1769,8 @@ int HttpServer::run() {
|
|||||||
|
|
||||||
auto loop = EV_DEFAULT;
|
auto loop = EV_DEFAULT;
|
||||||
|
|
||||||
Sessions sessions(loop, config_, ssl_ctx);
|
Sessions sessions(this, loop, config_, ssl_ctx);
|
||||||
if (start_listen(loop, &sessions, config_) != 0) {
|
if (start_listen(this, loop, &sessions, config_) != 0) {
|
||||||
std::cerr << "Could not listen" << std::endl;
|
std::cerr << "Could not listen" << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1655,4 +1781,22 @@ int HttpServer::run() {
|
|||||||
|
|
||||||
const Config *HttpServer::get_config() const { return config_; }
|
const Config *HttpServer::get_config() const { return config_; }
|
||||||
|
|
||||||
|
const StatusPage *HttpServer::get_status_page(int status) const {
|
||||||
|
switch (status) {
|
||||||
|
case 200:
|
||||||
|
return &status_pages_[IDX_200];
|
||||||
|
case 301:
|
||||||
|
return &status_pages_[IDX_301];
|
||||||
|
case 304:
|
||||||
|
return &status_pages_[IDX_304];
|
||||||
|
case 400:
|
||||||
|
return &status_pages_[IDX_400];
|
||||||
|
case 404:
|
||||||
|
return &status_pages_[IDX_404];
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user