mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-07 02:28:53 +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
|
||||
depcomp
|
||||
*.lo
|
||||
*.m4
|
||||
*.o
|
||||
.deps/
|
||||
.libs/
|
||||
INSTALL
|
||||
Makefile
|
||||
Makefile.in
|
||||
libtool
|
||||
missing
|
||||
autom4te.cache/
|
||||
compile
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
@@ -16,36 +20,14 @@ config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
.deps/
|
||||
.libs
|
||||
lib/includes/nghttp2/nghttp2ver.h
|
||||
lib/libnghttp2.pc
|
||||
src/libnghttp2_asio.pc
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
stamp-h1
|
||||
.deps/
|
||||
INSTALL
|
||||
.DS_STORE
|
||||
compile
|
||||
test-driver
|
||||
.dirstamp
|
||||
doc/index.rst
|
||||
doc/nghttp2.h.rst
|
||||
doc/nghttp2ver.h.rst
|
||||
doc/package_README.rst
|
||||
doc/tutorial-client.rst
|
||||
doc/tutorial-server.rst
|
||||
doc/nghttpx-howto.rst
|
||||
doc/h2load-howto.rst
|
||||
doc/tutorial-hpack.rst
|
||||
doc/python-apiref.rst
|
||||
doc/building-android-binary.rst
|
||||
doc/asio_http2.h.rst
|
||||
doc/asio_http2_server.h.rst
|
||||
doc/asio_http2_client.h.rst
|
||||
doc/libnghttp2_asio.rst
|
||||
doc/contribute.rst
|
||||
python/setup.py
|
||||
python/dist
|
||||
python/MANIFEST
|
||||
|
||||
# test logs generated by `make check`
|
||||
*.log
|
||||
*.trs
|
||||
|
||||
46
.travis.yml
46
.travis.yml
@@ -1,31 +1,31 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- clang
|
||||
#Disable gcc build for the moment...
|
||||
# - gcc
|
||||
- gcc
|
||||
sudo: false
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.9
|
||||
- libstdc++-4.9-dev
|
||||
- autoconf
|
||||
- automake
|
||||
- autotools-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
- zlib1g-dev
|
||||
- libcunit1-dev
|
||||
- libssl-dev
|
||||
- libxml2-dev
|
||||
- libev-dev
|
||||
- libevent-dev
|
||||
- libjansson-dev
|
||||
- libjemalloc-dev
|
||||
before_install:
|
||||
- $CC --version
|
||||
- sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
|
||||
- sudo apt-get update -qq
|
||||
#Install and use gcc-4.8 (don't build with gcc-4.6)
|
||||
#libstdc++-4.8 is needed by Clang to build too
|
||||
- sudo apt-get -qq install g++-4.8 libstdc++-4.8-dev
|
||||
- >
|
||||
sudo apt-get install --no-install-recommends -qq
|
||||
autoconf
|
||||
automake
|
||||
autotools-dev
|
||||
libtool
|
||||
pkg-config
|
||||
zlib1g-dev
|
||||
libcunit1-dev
|
||||
libssl-dev
|
||||
libxml2-dev
|
||||
libev-dev
|
||||
libevent-dev
|
||||
libjansson-dev
|
||||
libjemalloc-dev
|
||||
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
|
||||
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
|
||||
- $CC --version
|
||||
before_script:
|
||||
- autoreconf -i
|
||||
|
||||
18
CONTRIBUTION
Normal file
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
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
[The text below was composed based on 1.2. License section of
|
||||
curl/libcurl project.]
|
||||
|
||||
When contributing with code, you agree to put your changes and new
|
||||
code under the same license nghttp2 is already using unless stated and
|
||||
agreed otherwise.
|
||||
|
||||
When changing existing source code, you do not alter the copyright of
|
||||
the original file(s). The copyright will still be owned by the
|
||||
original creator(s) or those who have been assigned copyright by the
|
||||
original author(s).
|
||||
|
||||
By submitting a patch to the nghttp2 project, you are assumed to have
|
||||
the right to the code and to be allowed by your employer or whatever
|
||||
to hand over that patch/code to us. We will credit you for your
|
||||
changes as far as possible, to give credit but also to keep a trace
|
||||
back to who made what changes. Please always provide us with your
|
||||
full real name when contributing!
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# vim: ft=dockerfile:
|
||||
# Dockerfile to build nghttp2 android binary
|
||||
#
|
||||
# $ sudo docker build -t nghttp2-android - < Dockerfile.android
|
||||
@@ -9,7 +10,7 @@
|
||||
#
|
||||
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
|
||||
|
||||
FROM ubuntu
|
||||
FROM ubuntu:trusty
|
||||
|
||||
MAINTAINER Tatsuhiro Tsujikawa
|
||||
|
||||
@@ -29,9 +30,10 @@ RUN apt-get install -y make binutils autoconf automake autotools-dev libtool \
|
||||
genisoimage libc6-i386 lib32stdc++6
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin
|
||||
RUN chmod a+x android-ndk-r10c-linux-x86_64.bin
|
||||
RUN ./android-ndk-r10c-linux-x86_64.bin
|
||||
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin && \
|
||||
chmod a+x android-ndk-r10c-linux-x86_64.bin && \
|
||||
./android-ndk-r10c-linux-x86_64.bin && \
|
||||
rm android-ndk-r10c-linux-x86_64.bin
|
||||
|
||||
WORKDIR /root/build/android-ndk-r10c
|
||||
RUN /bin/bash build/tools/make-standalone-toolchain.sh \
|
||||
@@ -57,20 +59,24 @@ RUN autoreconf -i && \
|
||||
make install
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.1j.tar.gz
|
||||
RUN tar xf openssl-1.0.1j.tar.gz
|
||||
WORKDIR /root/build/openssl-1.0.1j
|
||||
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.2a.tar.gz && \
|
||||
tar xf openssl-1.0.2a.tar.gz && \
|
||||
rm openssl-1.0.2a.tar.gz
|
||||
|
||||
WORKDIR /root/build/openssl-1.0.2a
|
||||
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
|
||||
./Configure --prefix=$PREFIX android && \
|
||||
make && make install_sw
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN curl -L -O http://dist.schmorp.de/libev/libev-4.19.tar.gz
|
||||
RUN curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch
|
||||
RUN tar xf libev-4.19.tar.gz
|
||||
RUN curl -L -O http://dist.schmorp.de/libev/libev-4.19.tar.gz && \
|
||||
curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch && \
|
||||
tar xf libev-4.19.tar.gz && \
|
||||
rm libev-4.19.tar.gz
|
||||
|
||||
WORKDIR /root/build/libev-4.19
|
||||
RUN patch -p1 < ../libev-4.19-android.patch
|
||||
RUN ./configure \
|
||||
RUN patch -p1 < ../libev-4.19-android.patch && \
|
||||
./configure \
|
||||
--host=arm-linux-androideabi \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
@@ -95,9 +101,9 @@ RUN autoreconf -i && \
|
||||
--disable-threads \
|
||||
LIBSPDYLAY_CFLAGS=-I$PREFIX/usr/local/include \
|
||||
LIBSPDYLAY_LIBS="-L$PREFIX/usr/local/lib -lspdylay" \
|
||||
CPPFLAGS="-I$PREFIX/include" \
|
||||
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||
CXXFLAGS="-fno-strict-aliasing" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||
LDFLAGS="-L$PREFIX/lib" && \
|
||||
LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
|
||||
make && \
|
||||
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp
|
||||
|
||||
280
README.rst
280
README.rst
@@ -1,30 +1,30 @@
|
||||
nghttp2 - HTTP/2 C Library
|
||||
==========================
|
||||
|
||||
This is an implementation of Hypertext Transfer Protocol version 2
|
||||
This is an implementation of the Hypertext Transfer Protocol version 2
|
||||
in C.
|
||||
|
||||
The framing layer of HTTP/2 is implemented as a form of reusable C
|
||||
library. On top of that, we have implemented HTTP/2 client, server
|
||||
and proxy. We have also developed load test and benchmarking tool for
|
||||
The framing layer of HTTP/2 is implemented as a reusable C
|
||||
library. On top of that, we have implemented an HTTP/2 client, server
|
||||
and proxy. We have also developed load test and benchmarking tools for
|
||||
HTTP/2 and SPDY.
|
||||
|
||||
HPACK encoder and decoder are available as public API.
|
||||
An HPACK encoder and decoder are available as a public API.
|
||||
|
||||
The experimental high level C++ library is also available.
|
||||
An experimental high level C++ library is also available.
|
||||
|
||||
We have Python binding of this libary, but we have not covered
|
||||
everything yet.
|
||||
We have Python bindings of this libary, but we do not have full
|
||||
code coverage yet.
|
||||
|
||||
Development Status
|
||||
------------------
|
||||
|
||||
We started to implement h2-14
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), the header
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), and header
|
||||
compression
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09).
|
||||
|
||||
The nghttp2 code base was forked from spdylay project.
|
||||
The nghttp2 code base was forked from the spdylay project.
|
||||
|
||||
=========================== =======
|
||||
HTTP/2 Features Support
|
||||
@@ -37,7 +37,7 @@ Large header (CONTINUATION) Yes
|
||||
Public Test Server
|
||||
------------------
|
||||
|
||||
The following endpoints are available to try out nghttp2
|
||||
The following endpoints are available to try out our nghttp2
|
||||
implementation.
|
||||
|
||||
* https://nghttp2.org/ (TLS + ALPN/NPN)
|
||||
@@ -67,16 +67,16 @@ To build the documentation, you need to install:
|
||||
* sphinx (http://sphinx-doc.org/)
|
||||
|
||||
To build and run the application programs (``nghttp``, ``nghttpd`` and
|
||||
``nghttpx``) in ``src`` directory, the following packages are
|
||||
``nghttpx``) in the ``src`` directory, the following packages are
|
||||
required:
|
||||
|
||||
* OpenSSL >= 1.0.1
|
||||
* libev >= 4.15
|
||||
* zlib >= 1.2.3
|
||||
|
||||
ALPN support requires unreleased version OpenSSL >= 1.0.2.
|
||||
ALPN support requires OpenSSL >= 1.0.2 (released 22 January 2015).
|
||||
|
||||
To enable SPDY protocol in the application program ``nghttpx`` and
|
||||
To enable the SPDY protocol in the application program ``nghttpx`` and
|
||||
``h2load``, the following package is required:
|
||||
|
||||
* spdylay >= 1.3.0
|
||||
@@ -90,7 +90,7 @@ The HPACK tools require the following package:
|
||||
|
||||
* jansson >= 2.5
|
||||
|
||||
To build sources under examples directory, libevent is required:
|
||||
To build sources under the examples directory, libevent is required:
|
||||
|
||||
* libevent-openssl >= 2.0.8
|
||||
|
||||
@@ -109,16 +109,17 @@ The Python bindings require the following packages:
|
||||
* cython >= 0.19
|
||||
* python >= 2.7
|
||||
|
||||
If you are using Ubuntu 14.04 LTS, you need the following packages
|
||||
installed::
|
||||
If you are using Ubuntu 14.04 LTS (trusty), run the following to install the needed packages::
|
||||
|
||||
apt-get install make binutils autoconf automake autotools-dev libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev libjemalloc-dev cython python3.4-dev
|
||||
sudo apt-get install make binutils autoconf automake autotools-dev libtool pkg-config \
|
||||
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \
|
||||
libjemalloc-dev cython python3.4-dev
|
||||
|
||||
spdylay is not packaged in Ubuntu, so you need to build it yourself:
|
||||
http://tatsuhiro-t.github.io/spdylay/
|
||||
|
||||
Build from git
|
||||
--------------
|
||||
Building from git
|
||||
-----------------
|
||||
|
||||
Building from git is easy, but please be sure that at least autoconf 2.68 is
|
||||
used::
|
||||
@@ -129,23 +130,50 @@ used::
|
||||
$ ./configure
|
||||
$ make
|
||||
|
||||
To compile source code, gcc >= 4.8.3 or clang >= 3.4 is required.
|
||||
To compile the source code, gcc >= 4.8.3 or clang >= 3.4 is required.
|
||||
|
||||
.. note::
|
||||
|
||||
Mac OS X users may need ``--disable-threads`` configure option to
|
||||
disable multi threading in nghttpd, nghttpx and h2load to prevent
|
||||
them from crashing. Patch is welcome to make multi threading work
|
||||
Mac OS X users may need the ``--disable-threads`` configure option to
|
||||
disable multi-threading in nghttpd, nghttpx and h2load to prevent
|
||||
them from crashing. A patch is welcome to make multi threading work
|
||||
on Mac OS X platform.
|
||||
|
||||
Building documentation
|
||||
----------------------
|
||||
Notes for building on Windows (Mingw/Cygwin)
|
||||
--------------------------------------------
|
||||
|
||||
Under Mingw environment, you can only compile the library, it's
|
||||
``libnghttp2-X.dll`` and ``libnghttp2.a``.
|
||||
|
||||
If you want to compile the applications(``h2load``, ``nghttp``,
|
||||
``nghttpx``, ``nghttpd``), you need to use the Cygwin environment.
|
||||
|
||||
Under Cygwin environment, to compile the applications you need to
|
||||
compile and install the libev first.
|
||||
|
||||
Secondly, you need to undefine the macro ``__STRICT_ANSI__``, if you
|
||||
not, the functions ``fdopen``, ``fileno`` and ``strptime`` will not
|
||||
available.
|
||||
|
||||
the sample command like this::
|
||||
|
||||
$ export CFLAGS="-U__STRICT_ANSI__ -I$libev_PREFIX/include -L$libev_PREFIX/lib"
|
||||
$ export CXXFLAGS=$CFLAGS
|
||||
$ ./configure
|
||||
$ make
|
||||
|
||||
If you want to compile the applications under ``examples/``, you need
|
||||
to remove or rename the ``event.h`` from libev's installation, because
|
||||
it conflicts with libevent's installation.
|
||||
|
||||
Building the documentation
|
||||
--------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
Documentation is still incomplete.
|
||||
|
||||
To build documentation, run::
|
||||
To build the documentation, run::
|
||||
|
||||
$ make html
|
||||
|
||||
@@ -159,13 +187,13 @@ https://nghttp2.org/documentation/
|
||||
Unit tests
|
||||
----------
|
||||
|
||||
Unit tests are done by simply running `make check`.
|
||||
Unit tests are done by simply running ``make check``.
|
||||
|
||||
Integration tests
|
||||
-----------------
|
||||
|
||||
We have the integration tests for nghttpx proxy server. The tests are
|
||||
written in `Go programming language <http://golang.org/>`_ and uses
|
||||
We have the integration tests for the nghttpx proxy server. The tests are
|
||||
written in the `Go programming language <http://golang.org/>`_ and uses
|
||||
its testing framework. We depend on the following libraries:
|
||||
|
||||
* https://github.com/bradfitz/http2
|
||||
@@ -182,12 +210,12 @@ To run the tests, run the following command under
|
||||
|
||||
$ make it
|
||||
|
||||
Inside the tests, we use port 3009 to run test subject server.
|
||||
Inside the tests, we use port 3009 to run the test subject server.
|
||||
|
||||
Client, Server and Proxy programs
|
||||
---------------------------------
|
||||
|
||||
The src directory contains HTTP/2 client, server and proxy programs.
|
||||
The ``src`` directory contains the HTTP/2 client, server and proxy programs.
|
||||
|
||||
nghttp - client
|
||||
+++++++++++++++
|
||||
@@ -334,7 +362,7 @@ The HTTP Upgrade is performed like this::
|
||||
[ 0.038] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
||||
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
|
||||
|
||||
With ``-s`` option, ``nghttp`` prints out some timing information for
|
||||
Using the ``-s`` option, ``nghttp`` prints out some timing information for
|
||||
requests, sorted by completion time::
|
||||
|
||||
$ nghttp -nas https://nghttp2.org/
|
||||
@@ -360,8 +388,8 @@ requests, sorted by completion time::
|
||||
+76.14ms +11.17ms 64.97ms 200 171K /images/posts/with-pri-blog.png
|
||||
+88.52ms +11.17ms 77.36ms 200 174K /images/posts/without-pri-blog.png
|
||||
|
||||
With ``-r`` option, ``nghttp`` writes more detailed timing data to
|
||||
given file in HAR format.
|
||||
Using the ``-r`` option, ``nghttp`` writes more detailed timing data to
|
||||
the given file in HAR format.
|
||||
|
||||
nghttpd - server
|
||||
++++++++++++++++
|
||||
@@ -371,13 +399,13 @@ nghttpd - server
|
||||
By default, it uses SSL/TLS connection. Use ``--no-tls`` option to
|
||||
disable it.
|
||||
|
||||
``nghttpd`` only accepts the HTTP/2 connection via NPN/ALPN or direct
|
||||
HTTP/2 connection. No HTTP Upgrade is supported.
|
||||
``nghttpd`` only accepts HTTP/2 connections via NPN/ALPN or direct
|
||||
HTTP/2 connections. No HTTP Upgrade is supported.
|
||||
|
||||
``-p`` option allows users to configure server push.
|
||||
The ``-p`` option allows users to configure server push.
|
||||
|
||||
Just like ``nghttp``, it has verbose output mode for framing
|
||||
information. Here is sample output from ``nghttpd`` server::
|
||||
Just like ``nghttp``, it has a verbose output mode for framing
|
||||
information. Here is sample output from ``nghttpd``::
|
||||
|
||||
$ nghttpd --no-tls -v 8080
|
||||
IPv4: listen on port 8080
|
||||
@@ -431,8 +459,15 @@ nghttpx - proxy
|
||||
+++++++++++++++
|
||||
|
||||
``nghttpx`` is a multi-threaded reverse proxy for ``h2-14``, SPDY and
|
||||
HTTP/1.1 and powers nghttp2.org site and supports HTTP/2 server push.
|
||||
It has several operation modes:
|
||||
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server push.
|
||||
|
||||
``nghttpx`` implements `important performance-oriented features
|
||||
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
|
||||
session IDs, session tickets (with automatic key rotation), OCSP
|
||||
stapling, dynamic record sizing, ALPN/NPN, forward secrecy and SPDY &
|
||||
HTTP/2.
|
||||
|
||||
``nghttpx`` has several operational modes:
|
||||
|
||||
================== ============================ ============== =============
|
||||
Mode option Frontend Backend Note
|
||||
@@ -446,19 +481,19 @@ default mode HTTP/2, SPDY, HTTP/1.1 (TLS) HTTP/1.1 Reverse proxy
|
||||
|
||||
The interesting mode at the moment is the default mode. It works like
|
||||
a reverse proxy and listens for ``h2-14``, SPDY and HTTP/1.1 and can
|
||||
be deployed SSL/TLS terminator for existing web server.
|
||||
be deployed as a SSL/TLS terminator for existing web server.
|
||||
|
||||
The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
|
||||
SSL/TLS in the frontend connection by default. To disable SSL/TLS,
|
||||
use ``--frontend-no-tls`` option. If that option is used, SPDY is
|
||||
disabled in the frontend and incoming HTTP/1.1 connection can be
|
||||
use the ``--frontend-no-tls`` option. If that option is used, SPDY is
|
||||
disabled in the frontend and incoming HTTP/1.1 connections can be
|
||||
upgraded to HTTP/2 through HTTP Upgrade.
|
||||
|
||||
The ``--http2-bridge``, ``--client`` and ``--client-proxy`` modes use
|
||||
SSL/TLS in the backend connection by deafult. To disable SSL/TLS, use
|
||||
``--backend-no-tls`` option.
|
||||
the ``--backend-no-tls`` option.
|
||||
|
||||
``nghttpx`` supports configuration file. See ``--conf`` option and
|
||||
``nghttpx`` supports a configuration file. See the ``--conf`` option and
|
||||
sample configuration file ``nghttpx.conf.sample``.
|
||||
|
||||
In the default mode, (without any of ``--http2-proxy``,
|
||||
@@ -468,18 +503,18 @@ In the default mode, (without any of ``--http2-proxy``,
|
||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Web Server
|
||||
[reverse proxy]
|
||||
|
||||
With ``--http2-proxy`` option, it works as so called secure proxy (aka
|
||||
With the ``--http2-proxy`` option, it works as a so called secure proxy (aka
|
||||
SPDY proxy)::
|
||||
|
||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
|
||||
[secure proxy] (e.g., Squid, ATS)
|
||||
|
||||
The ``Client`` in the above needs to be configured to use
|
||||
The ``Client`` in the above example needs to be configured to use
|
||||
``nghttpx`` as secure proxy.
|
||||
|
||||
At the time of this writing, Chrome is the only browser which supports
|
||||
secure proxy. The one way to configure Chrome to use secure proxy is
|
||||
create proxy.pac script like this:
|
||||
secure proxy. One way to configure Chrome to use a secure proxy is
|
||||
to create a proxy.pac script like this:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
@@ -488,7 +523,7 @@ create proxy.pac script like this:
|
||||
}
|
||||
|
||||
``SERVERADDR`` and ``PORT`` is the hostname/address and port of the
|
||||
machine nghttpx is running. Please note that Chrome requires valid
|
||||
machine nghttpx is running on. Please note that Chrome requires a valid
|
||||
certificate for secure proxy.
|
||||
|
||||
Then run Chrome with the following arguments::
|
||||
@@ -496,24 +531,24 @@ Then run Chrome with the following arguments::
|
||||
$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
|
||||
|
||||
With ``--http2-bridge``, it accepts HTTP/2, SPDY and HTTP/1.1
|
||||
connections and communicates with backend in HTTP/2::
|
||||
connections and communicates with the backend in HTTP/2::
|
||||
|
||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> Web or HTTP/2 Proxy etc
|
||||
(e.g., nghttpx -s)
|
||||
|
||||
With ``--client-proxy`` option, it works as forward proxy and expects
|
||||
that the backend is HTTP/2 proxy::
|
||||
With ``--client-proxy``, it works as a forward proxy and expects
|
||||
that the backend is an HTTP/2 proxy::
|
||||
|
||||
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> HTTP/2 Proxy
|
||||
[forward proxy] (e.g., nghttpx -s)
|
||||
|
||||
The ``Client`` needs to be configured to use nghttpx as forward
|
||||
The ``Client`` needs to be configured to use nghttpx as a forward
|
||||
proxy. The frontend HTTP/1.1 connection can be upgraded to HTTP/2
|
||||
through HTTP Upgrade. With the above configuration, one can use
|
||||
HTTP/1.1 client to access and test their HTTP/2 servers.
|
||||
|
||||
With ``--client`` option, it works as reverse proxy and expects that
|
||||
the backend is HTTP/2 Web server::
|
||||
With ``--client``, it works as a reverse proxy and expects that
|
||||
the backend is an HTTP/2 Web server::
|
||||
|
||||
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --> Web Server
|
||||
[reverse proxy]
|
||||
@@ -522,11 +557,11 @@ The frontend HTTP/1.1 connection can be upgraded to HTTP/2
|
||||
through HTTP Upgrade.
|
||||
|
||||
For the operation modes which talk to the backend in HTTP/2 over
|
||||
SSL/TLS, the backend connections can be tunneled through HTTP proxy.
|
||||
The proxy is specified using ``--backend-http-proxy-uri`` option. The
|
||||
following figure illustrates the example of ``--http2-bridge`` and
|
||||
SSL/TLS, the backend connections can be tunneled through an HTTP proxy.
|
||||
The proxy is specified using ``--backend-http-proxy-uri``. The
|
||||
following figure illustrates the example of the ``--http2-bridge`` and
|
||||
``--backend-http-proxy-uri`` options to talk to the outside HTTP/2
|
||||
proxy through HTTP proxy::
|
||||
proxy through an HTTP proxy::
|
||||
|
||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
|
||||
|
||||
@@ -537,7 +572,7 @@ Benchmarking tool
|
||||
-----------------
|
||||
|
||||
The ``h2load`` program is a benchmarking tool for HTTP/2 and SPDY.
|
||||
The SPDY support is enabled if the program was built with spdylay
|
||||
The SPDY support is enabled if the program was built with the spdylay
|
||||
library. The UI of ``h2load`` is heavily inspired by ``weighttp``
|
||||
(https://github.com/lighttpd/weighttp). The typical usage is as
|
||||
follows::
|
||||
@@ -565,38 +600,38 @@ follows::
|
||||
min max mean sd +/- sd
|
||||
time for request: 283.86ms 1.46s 659.70ms 150.87ms 84.68%
|
||||
|
||||
The above example issued total 100000 requests, using 100 concurrent
|
||||
clients (in other words, 100 HTTP/2 sessions), and maximum 100 streams
|
||||
per client. With ``-t`` option, ``h2load`` will use multiple native
|
||||
threads to avoid saturating single core on client side.
|
||||
The above example issued total 100,000 requests, using 100 concurrent
|
||||
clients (in other words, 100 HTTP/2 sessions), and a maximum of 100 streams
|
||||
per client. With the ``-t`` option, ``h2load`` will use multiple native
|
||||
threads to avoid saturating a single core on client side.
|
||||
|
||||
.. warning::
|
||||
|
||||
**Don't use this tool against publicly available servers.** That is
|
||||
considered a DOS attack. Please only use against your private
|
||||
considered a DOS attack. Please only use it against your private
|
||||
servers.
|
||||
|
||||
HPACK tools
|
||||
-----------
|
||||
|
||||
The ``src`` directory contains HPACK tools. The ``deflatehd`` is a
|
||||
command-line header compression tool. The ``inflatehd`` is
|
||||
The ``src`` directory contains the HPACK tools. The ``deflatehd`` program is a
|
||||
command-line header compression tool. The ``inflatehd`` program is a
|
||||
command-line header decompression tool. Both tools read input from
|
||||
stdin and write output to stdout. The errors are written to stderr.
|
||||
They take JSON as input and output. We use (mostly) same JSON data
|
||||
format described at https://github.com/http2jp/hpack-test-case
|
||||
stdin and write output to stdout. Errors are written to stderr.
|
||||
They take JSON as input and output. We (mostly) use the same JSON data
|
||||
format described at https://github.com/http2jp/hpack-test-case.
|
||||
|
||||
deflatehd - header compressor
|
||||
+++++++++++++++++++++++++++++
|
||||
|
||||
The ``deflatehd`` reads JSON data or HTTP/1-style header fields from
|
||||
The ``deflatehd`` program reads JSON data or HTTP/1-style header fields from
|
||||
stdin and outputs compressed header block in JSON.
|
||||
|
||||
For the JSON input, the root JSON object must include ``cases`` key.
|
||||
For the JSON input, the root JSON object must include a ``cases`` key.
|
||||
Its value has to include the sequence of input header set. They share
|
||||
the same compression context and are processed in the order they
|
||||
appear. Each item in the sequence is a JSON object and it must
|
||||
include ``headers`` key. Its value is an array of a JSON object,
|
||||
include a ``headers`` key. Its value is an array of JSON objects,
|
||||
which includes exactly one name/value pair.
|
||||
|
||||
Example:
|
||||
@@ -622,8 +657,8 @@ Example:
|
||||
}
|
||||
|
||||
|
||||
With ``-t`` option, the program can accept more familiar HTTP/1 style
|
||||
header field block. Each header set is delimited by empty line:
|
||||
With the ``-t`` option, the program can accept more familiar HTTP/1 style
|
||||
header field blocks. Each header set is delimited by an empty line:
|
||||
|
||||
Example::
|
||||
|
||||
@@ -634,29 +669,29 @@ Example::
|
||||
:method: POST
|
||||
user-agent: nghttp2
|
||||
|
||||
The output is JSON object. It should include ``cases`` key and its
|
||||
value is an array of JSON object, which has at least following keys:
|
||||
The output is in JSON object. It should include a ``cases`` key and its
|
||||
value is an array of JSON objects, which has at least the following keys:
|
||||
|
||||
seq
|
||||
The index of header set in the input.
|
||||
|
||||
input_length
|
||||
The sum of length of name/value pair in the input.
|
||||
The sum of the length of the name/value pairs in the input.
|
||||
|
||||
output_length
|
||||
The length of compressed header block.
|
||||
The length of the compressed header block.
|
||||
|
||||
percentage_of_original_size
|
||||
``input_length`` / ``output_length`` * 100
|
||||
|
||||
wire
|
||||
The compressed header block in hex string.
|
||||
The compressed header block as a hex string.
|
||||
|
||||
headers
|
||||
The input header set.
|
||||
|
||||
header_table_size
|
||||
The header table size adjusted before deflating header set.
|
||||
The header table size adjusted before deflating the header set.
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -723,7 +758,7 @@ Examples:
|
||||
The output can be used as the input for ``inflatehd`` and
|
||||
``deflatehd``.
|
||||
|
||||
With ``-d`` option, the extra ``header_table`` key is added and its
|
||||
With the ``-d`` option, the extra ``header_table`` key is added and its
|
||||
associated value includes the state of dynamic header table after the
|
||||
corresponding header set was processed. The value includes at least
|
||||
the following keys:
|
||||
@@ -747,8 +782,8 @@ deflate_size
|
||||
``max_deflate_size``.
|
||||
|
||||
max_deflate_size
|
||||
The maximum header table size encoder uses. This can be smaller
|
||||
than ``max_size``. In this case, encoder only uses up to first
|
||||
The maximum header table size the encoder uses. This can be smaller
|
||||
than ``max_size``. In this case, the encoder only uses up to first
|
||||
``max_deflate_size`` buffer. Since the header table size is still
|
||||
``max_size``, the encoder has to keep track of entries ouside the
|
||||
``max_deflate_size`` but inside the ``max_size`` and make sure
|
||||
@@ -911,14 +946,14 @@ Example:
|
||||
inflatehd - header decompressor
|
||||
+++++++++++++++++++++++++++++++
|
||||
|
||||
The ``inflatehd`` reads JSON data from stdin and outputs decompressed
|
||||
The ``inflatehd`` program reads JSON data from stdin and outputs decompressed
|
||||
name/value pairs in JSON.
|
||||
|
||||
The root JSON object must include ``cases`` key. Its value has to
|
||||
include the sequence of compressed header block. They share the same
|
||||
The root JSON object must include the ``cases`` key. Its value has to
|
||||
include the sequence of compressed header blocks. They share the same
|
||||
compression context and are processed in the order they appear. Each
|
||||
item in the sequence is a JSON object and it must have at least
|
||||
``wire`` key. Its value is a compressed header block in hex string.
|
||||
item in the sequence is a JSON object and it must have at least a
|
||||
``wire`` key. Its value is a compressed header block as a hex string.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -932,17 +967,17 @@ Example:
|
||||
]
|
||||
}
|
||||
|
||||
The output is JSON object. It should include ``cases`` key and its
|
||||
value is an array of JSON object, which has at least following keys:
|
||||
The output is a JSON object. It should include a ``cases`` key and its
|
||||
value is an array of JSON objects, which has at least following keys:
|
||||
|
||||
seq
|
||||
The index of header set in the input.
|
||||
The index of the header set in the input.
|
||||
|
||||
headers
|
||||
The JSON array includes decompressed name/value pairs.
|
||||
A JSON array that includes decompressed name/value pairs.
|
||||
|
||||
wire
|
||||
The compressed header block in hex string.
|
||||
The compressed header block as a hex string.
|
||||
|
||||
header_table_size
|
||||
The header table size adjusted before inflating compressed header
|
||||
@@ -1006,8 +1041,8 @@ Example:
|
||||
The output can be used as the input for ``deflatehd`` and
|
||||
``inflatehd``.
|
||||
|
||||
With ``-d`` option, the extra ``header_table`` key is added and its
|
||||
associated value includes the state of dynamic header table after the
|
||||
With the ``-d`` option, the extra ``header_table`` key is added and its
|
||||
associated value includes the state of the dynamic header table after the
|
||||
corresponding header set was processed. The format is the same as
|
||||
``deflatehd``.
|
||||
|
||||
@@ -1016,10 +1051,10 @@ libnghttp2_asio: High level HTTP/2 C++ library
|
||||
|
||||
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
|
||||
high level abstraction API to build HTTP/2 applications. It depends
|
||||
on Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
|
||||
provides client and server API.
|
||||
on the Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
|
||||
provides both client and server APIs.
|
||||
|
||||
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
|
||||
libnghttp2_asio is not built by default. Use the ``--enable-asio-lib``
|
||||
configure flag to build libnghttp2_asio. The required Boost libraries
|
||||
are:
|
||||
|
||||
@@ -1027,9 +1062,9 @@ are:
|
||||
* Boost::System
|
||||
* Boost::Thread
|
||||
|
||||
Server API is designed to build HTTP/2 server very easily to utilize
|
||||
C++11 anonymous function and closure. The bare minimum example of
|
||||
HTTP/2 server looks like this:
|
||||
The server API is designed to build an HTTP/2 server very easily to utilize
|
||||
C++11 anonymous functions and closures. The bare minimum example of
|
||||
an HTTP/2 server looks like this:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -1052,7 +1087,7 @@ HTTP/2 server looks like this:
|
||||
}
|
||||
}
|
||||
|
||||
Here is the sample code for client API use:
|
||||
Here is sample code to use the client API:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -1109,19 +1144,19 @@ For more details, see the documentation of libnghttp2_asio.
|
||||
Python bindings
|
||||
---------------
|
||||
|
||||
This ``python`` directory contains nghttp2 Python bindings. The
|
||||
The ``python`` directory contains nghttp2 Python bindings. The
|
||||
bindings currently provide HPACK compressor and decompressor classes
|
||||
and HTTP/2 server.
|
||||
and an HTTP/2 server.
|
||||
|
||||
The extension module is called ``nghttp2``.
|
||||
|
||||
``make`` will build the bindings and target Python version is
|
||||
determined by configure script. If the detected Python version is not
|
||||
what you expect, specify a path to Python executable in ``PYTHON``
|
||||
determined by the ``configure`` script. If the detected Python version is not
|
||||
what you expect, specify a path to Python executable in a ``PYTHON``
|
||||
variable as an argument to configure script (e.g., ``./configure
|
||||
PYTHON=/usr/bin/python3.4``).
|
||||
|
||||
The following example code illustrates basic usage of HPACK compressor
|
||||
The following example code illustrates basic usage of the HPACK compressor
|
||||
and decompressor in Python:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -1148,21 +1183,21 @@ By default, it does nothing. It must be subclassed to handle each
|
||||
event callback method.
|
||||
|
||||
The first callback method invoked is ``on_headers()``. It is called
|
||||
when HEADERS frame, which includes request header fields, has arrived.
|
||||
when HEADERS frame, which includes the request header fields, has arrived.
|
||||
|
||||
If request has request body, ``on_data(data)`` is invoked for each
|
||||
If the request has a request body, ``on_data(data)`` is invoked for each
|
||||
chunk of received data.
|
||||
|
||||
When whole request is received, ``on_request_done()`` is invoked.
|
||||
Once the entire request is received, ``on_request_done()`` is invoked.
|
||||
|
||||
When stream is closed, ``on_close(error_code)`` is called.
|
||||
When the stream is closed, ``on_close(error_code)`` is called.
|
||||
|
||||
The application can send response using ``send_response()`` method.
|
||||
The application can send a response using ``send_response()`` method.
|
||||
It can be used in ``on_headers()``, ``on_data()`` or
|
||||
``on_request_done()``.
|
||||
|
||||
The application can push resource using ``push()`` method. It must be
|
||||
used before ``send_response()`` call.
|
||||
The application can push resources using the ``push()`` method. It must be
|
||||
used before the ``send_response()`` call.
|
||||
|
||||
The following instance variables are available:
|
||||
|
||||
@@ -1232,14 +1267,15 @@ When contributing with code, you agree to put your changes and new
|
||||
code under the same license nghttp2 is already using unless stated and
|
||||
agreed otherwise.
|
||||
|
||||
When changing existing source code, you do not alter the copyright of
|
||||
When changing existing source code, do not alter the copyright of
|
||||
the original file(s). The copyright will still be owned by the
|
||||
original creator(s) or those who have been assigned copyright by the
|
||||
original author(s).
|
||||
|
||||
By submitting a patch to the nghttp2 project, you are assumed to have
|
||||
the right to the code and to be allowed by your employer or whatever
|
||||
to hand over that patch/code to us. We will credit you for your
|
||||
By submitting a patch to the nghttp2 project, you (or your employer, as
|
||||
the case may be) agree to assign the copyright of your submission to us.
|
||||
.. the above really needs to be reworded to pass legal muster.
|
||||
We will credit you for your
|
||||
changes as far as possible, to give credit but also to keep a trace
|
||||
back to who made what changes. Please always provide us with your
|
||||
full real name when contributing!
|
||||
|
||||
@@ -42,6 +42,6 @@ PATH=$TOOLCHAIN/bin:$PATH
|
||||
--enable-werror \
|
||||
CC=clang \
|
||||
CXX=clang++ \
|
||||
CPPFLAGS="-I$PREFIX/include" \
|
||||
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||
LDFLAGS="-L$PREFIX/lib"
|
||||
LDFLAGS="-fPIE -pie -L$PREFIX/lib"
|
||||
|
||||
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
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([nghttp2], [0.7.6], [t-tujikawa@users.sourceforge.net])
|
||||
AC_INIT([nghttp2], [0.7.14], [t-tujikawa@users.sourceforge.net])
|
||||
LT_PREREQ([2.2.6])
|
||||
LT_INIT()
|
||||
dnl See versioning rule:
|
||||
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
AC_SUBST(LT_CURRENT, 12)
|
||||
AC_SUBST(LT_REVISION, 0)
|
||||
AC_SUBST(LT_AGE, 7)
|
||||
AC_SUBST(LT_CURRENT, 13)
|
||||
AC_SUBST(LT_REVISION, 3)
|
||||
AC_SUBST(LT_AGE, 8)
|
||||
|
||||
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
|
||||
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
|
||||
@@ -508,13 +508,6 @@ AC_CHECK_HEADERS([ \
|
||||
unistd.h \
|
||||
])
|
||||
|
||||
case "${host}" in
|
||||
*mingw*)
|
||||
# For ntohl, ntohs in Windows
|
||||
AC_CHECK_HEADERS([winsock2.h])
|
||||
;;
|
||||
esac
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
@@ -564,13 +557,6 @@ AM_CONDITIONAL([ENABLE_TINY_NGHTTPD],
|
||||
[ test "x${have_epoll}" = "xyes" &&
|
||||
test "x${have_timerfd_create}" = "xyes"])
|
||||
|
||||
dnl Windows library for winsock2
|
||||
case "${host}" in
|
||||
*mingw*)
|
||||
LIBS="$LIBS -lws2_32"
|
||||
;;
|
||||
esac
|
||||
|
||||
ac_save_CFLAGS=$CFLAGS
|
||||
CFLAGS=
|
||||
|
||||
|
||||
2
contrib/.gitignore
vendored
2
contrib/.gitignore
vendored
@@ -1 +1,3 @@
|
||||
nghttpx-init
|
||||
nghttpx.service
|
||||
nghttpx-upstart.conf
|
||||
|
||||
@@ -21,19 +21,24 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
EXTRA_DIST = nghttpx-init.in nghttpx-logrotate
|
||||
configfiles = nghttpx-init nghttpx.service nghttpx-upstart.conf
|
||||
|
||||
EXTRA_DIST = $(configfiles:%=%.in) nghttpx-logrotate
|
||||
|
||||
edit = sed -e 's|@bindir[@]|$(bindir)|g'
|
||||
|
||||
nghttpx-init: Makefile
|
||||
nghttpx-init: %: $(srcdir)/%.in
|
||||
rm -f $@ $@.tmp
|
||||
$(edit) $(srcdir)/$@.in > $@.tmp
|
||||
$(edit) $< > $@.tmp
|
||||
chmod +x $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
nghttpx-init: $(srcdir)/nghttpx-init.in
|
||||
nghttpx.service nghttpx-upstart.conf: %: $(srcdir)/%.in
|
||||
$(edit) $< > $@
|
||||
|
||||
all-local: nghttpx-init
|
||||
$(configfiles): Makefile
|
||||
|
||||
all-local: $(configfiles)
|
||||
|
||||
clean-local:
|
||||
-rm -f nghttpx-init nghttpx-init.tmp
|
||||
-rm -f nghttpx-init.tmp $(configfiles)
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
/var/log/nghttpx/*.log {
|
||||
weekly
|
||||
missingok
|
||||
rotate 52
|
||||
missingok
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 0640 www-data adm
|
||||
sharedscripts
|
||||
prerotate
|
||||
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
|
||||
run-parts /etc/logrotate.d/httpd-prerotate; \
|
||||
fi \
|
||||
endscript
|
||||
postrotate
|
||||
[ -s /run/nghttpx.pid ] && kill -USR1 `cat /run/nghttpx.pid`
|
||||
killall -USR1 nghttpx 2> /dev/null || true
|
||||
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
|
||||
asio_http2.h.rst
|
||||
asio_http2_client.h.rst
|
||||
asio_http2_server.h.rst
|
||||
building-android-binary.rst
|
||||
conf.py
|
||||
manual
|
||||
contribute.rst
|
||||
enums.rst
|
||||
h2load-howto.rst
|
||||
index.rst
|
||||
libnghttp2_asio.rst
|
||||
macros.rst
|
||||
manual/
|
||||
nghttp2.h.rst
|
||||
nghttp2_*.rst
|
||||
nghttp2ver.h.rst
|
||||
nghttpx-howto.rst
|
||||
package_README.rst
|
||||
python-apiref.rst
|
||||
tutorial-client.rst
|
||||
tutorial-hpack.rst
|
||||
tutorial-server.rst
|
||||
types.rst
|
||||
|
||||
127
doc/Makefile.am
127
doc/Makefile.am
@@ -23,10 +23,112 @@
|
||||
|
||||
man_MANS = nghttp.1 nghttpd.1 nghttpx.1 h2load.1
|
||||
|
||||
APIDOCS= \
|
||||
apiref.rst \
|
||||
macros.rst \
|
||||
enums.rst \
|
||||
types.rst \
|
||||
nghttp2_check_header_name.rst \
|
||||
nghttp2_check_header_value.rst \
|
||||
nghttp2_hd_deflate_bound.rst \
|
||||
nghttp2_hd_deflate_change_table_size.rst \
|
||||
nghttp2_hd_deflate_del.rst \
|
||||
nghttp2_hd_deflate_hd.rst \
|
||||
nghttp2_hd_deflate_new.rst \
|
||||
nghttp2_hd_deflate_new2.rst \
|
||||
nghttp2_hd_inflate_change_table_size.rst \
|
||||
nghttp2_hd_inflate_del.rst \
|
||||
nghttp2_hd_inflate_end_headers.rst \
|
||||
nghttp2_hd_inflate_hd.rst \
|
||||
nghttp2_hd_inflate_new.rst \
|
||||
nghttp2_hd_inflate_new2.rst \
|
||||
nghttp2_is_fatal.rst \
|
||||
nghttp2_nv_compare_name.rst \
|
||||
nghttp2_option_del.rst \
|
||||
nghttp2_option_new.rst \
|
||||
nghttp2_option_set_no_auto_window_update.rst \
|
||||
nghttp2_option_set_no_http_messaging.rst \
|
||||
nghttp2_option_set_peer_max_concurrent_streams.rst \
|
||||
nghttp2_option_set_recv_client_preface.rst \
|
||||
nghttp2_pack_settings_payload.rst \
|
||||
nghttp2_priority_spec_check_default.rst \
|
||||
nghttp2_priority_spec_default_init.rst \
|
||||
nghttp2_priority_spec_init.rst \
|
||||
nghttp2_select_next_protocol.rst \
|
||||
nghttp2_session_callbacks_del.rst \
|
||||
nghttp2_session_callbacks_new.rst \
|
||||
nghttp2_session_callbacks_set_before_frame_send_callback.rst \
|
||||
nghttp2_session_callbacks_set_data_source_read_length_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_begin_frame_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_frame_not_send_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_frame_send_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_header_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback.rst \
|
||||
nghttp2_session_callbacks_set_recv_callback.rst \
|
||||
nghttp2_session_callbacks_set_select_padding_callback.rst \
|
||||
nghttp2_session_callbacks_set_send_callback.rst \
|
||||
nghttp2_session_callbacks_set_send_data_callback.rst \
|
||||
nghttp2_session_client_new.rst \
|
||||
nghttp2_session_client_new2.rst \
|
||||
nghttp2_session_client_new3.rst \
|
||||
nghttp2_session_consume.rst \
|
||||
nghttp2_session_consume_connection.rst \
|
||||
nghttp2_session_consume_stream.rst \
|
||||
nghttp2_session_del.rst \
|
||||
nghttp2_session_get_effective_local_window_size.rst \
|
||||
nghttp2_session_get_effective_recv_data_length.rst \
|
||||
nghttp2_session_get_last_proc_stream_id.rst \
|
||||
nghttp2_session_get_next_stream_id.rst \
|
||||
nghttp2_session_get_outbound_queue_size.rst \
|
||||
nghttp2_session_get_remote_settings.rst \
|
||||
nghttp2_session_get_remote_window_size.rst \
|
||||
nghttp2_session_get_stream_effective_local_window_size.rst \
|
||||
nghttp2_session_get_stream_effective_recv_data_length.rst \
|
||||
nghttp2_session_get_stream_local_close.rst \
|
||||
nghttp2_session_get_stream_remote_close.rst \
|
||||
nghttp2_session_get_stream_remote_window_size.rst \
|
||||
nghttp2_session_get_stream_user_data.rst \
|
||||
nghttp2_session_mem_recv.rst \
|
||||
nghttp2_session_mem_send.rst \
|
||||
nghttp2_session_recv.rst \
|
||||
nghttp2_session_resume_data.rst \
|
||||
nghttp2_session_send.rst \
|
||||
nghttp2_session_server_new.rst \
|
||||
nghttp2_session_server_new2.rst \
|
||||
nghttp2_session_server_new3.rst \
|
||||
nghttp2_session_set_next_stream_id.rst \
|
||||
nghttp2_session_set_stream_user_data.rst \
|
||||
nghttp2_session_terminate_session.rst \
|
||||
nghttp2_session_terminate_session2.rst \
|
||||
nghttp2_session_upgrade.rst \
|
||||
nghttp2_session_want_read.rst \
|
||||
nghttp2_session_want_write.rst \
|
||||
nghttp2_strerror.rst \
|
||||
nghttp2_submit_altsvc.rst \
|
||||
nghttp2_submit_data.rst \
|
||||
nghttp2_submit_goaway.rst \
|
||||
nghttp2_submit_headers.rst \
|
||||
nghttp2_submit_ping.rst \
|
||||
nghttp2_submit_priority.rst \
|
||||
nghttp2_submit_push_promise.rst \
|
||||
nghttp2_submit_request.rst \
|
||||
nghttp2_submit_response.rst \
|
||||
nghttp2_submit_rst_stream.rst \
|
||||
nghttp2_submit_settings.rst \
|
||||
nghttp2_submit_shutdown_notice.rst \
|
||||
nghttp2_submit_trailer.rst \
|
||||
nghttp2_submit_window_update.rst \
|
||||
nghttp2_version.rst
|
||||
|
||||
EXTRA_DIST = \
|
||||
mkapiref.py \
|
||||
README.rst \
|
||||
apiref-header.rst \
|
||||
programmers-guide.rst \
|
||||
$(APIDOCS) \
|
||||
nghttp.1.rst \
|
||||
nghttpd.1.rst \
|
||||
nghttpx.1.rst \
|
||||
@@ -99,13 +201,30 @@ help:
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
apiref.rst: $(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
|
||||
apiref.rst macros.rst enums.rst types.rst: \
|
||||
$(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
|
||||
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
|
||||
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
|
||||
--header $(top_srcdir)/doc/apiref-header.rst $^ > $@
|
||||
$@ macros.rst enums.rst types.rst . $^
|
||||
|
||||
# Inspired by
|
||||
# http://www.gnu.org/savannah-checkouts/gnu/automake/manual/html_node/Multiple-Outputs.html
|
||||
apidoc.stamp: $(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
|
||||
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
|
||||
@rm -f apidoc.tmp
|
||||
@touch apidoc.tmp
|
||||
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
|
||||
$@ macros.rst enums.rst types.rst . $^
|
||||
@mv -f apidoc.tmp $@
|
||||
$(APIDOC): apidoc.stamp
|
||||
## Recover from the removal of $@
|
||||
@if test -f $@; then :; else \
|
||||
rm -f apidoc.stamp; \
|
||||
$(MAKE) $(AM_MAKEFLAGS) apidoc.stamp; \
|
||||
fi
|
||||
|
||||
clean-local:
|
||||
-rm apiref.rst
|
||||
-rm $(APIDOCS)
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html-local: apiref.rst
|
||||
|
||||
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
|
||||
|
||||
VERSION = (0, 1, 5)
|
||||
VERSION = (0, 1, 8)
|
||||
|
||||
__version__ = ".".join(str(v) for v in VERSION)
|
||||
__version_full__ = __version__
|
||||
|
||||
@@ -6,13 +6,17 @@
|
||||
{% endfor %}
|
||||
<li>{{ title }}</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
{% if pagename != "search" %}
|
||||
{% 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 %}
|
||||
<a href="https://bitbucket.org/{{ bitbucket_user }}/{{ bitbucket_repo }}/src/{{ bitbucket_version}}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-bitbucket"> Edit on Bitbucket</a>
|
||||
{% elif show_source and source_url_prefix %}
|
||||
<a href="{{ source_url_prefix }}{{ pagename }}{{ source_suffix }}">View page source</a>
|
||||
{% elif show_source and has_source and sourcename %}
|
||||
<a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow"> View page source</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
<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 %}
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
{% if next %}
|
||||
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}">Next <span class="fa fa-arrow-circle-right"></span></a>
|
||||
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
|
||||
{% endif %}
|
||||
{% if prev %}
|
||||
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}"><span class="fa fa-arrow-circle-left"></span> Previous</a>
|
||||
<a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -28,6 +28,9 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{%- if show_sphinx %}
|
||||
{% trans %}Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}.
|
||||
{%- endif %}
|
||||
|
||||
</footer>
|
||||
|
||||
|
||||
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]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
{{ metatags }}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% block htmltitle %}
|
||||
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||
@@ -23,7 +24,6 @@
|
||||
{% endif %}
|
||||
|
||||
{# CSS #}
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic|Roboto+Slab:400,700|Inconsolata:400,700&subset=latin,cyrillic' rel='stylesheet' type='text/css'>
|
||||
|
||||
{# OPENSEARCH #}
|
||||
{% if not embedded %}
|
||||
@@ -42,6 +42,10 @@
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{% endfor %}
|
||||
|
||||
{% for cssfile in extra_css_files %}
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{% endfor %}
|
||||
|
||||
{%- block linktags %}
|
||||
{%- if hasdoc('about') %}
|
||||
<link rel="author" title="{{ _('About these documents') }}"
|
||||
@@ -71,7 +75,7 @@
|
||||
{%- block extrahead %} {% endblock %}
|
||||
|
||||
{# Keep modernizr in head - http://modernizr.com/docs/#installing #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js"></script>
|
||||
<script src="_static/js/modernizr.min.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
@@ -83,14 +87,27 @@
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||
<div class="wy-side-nav-search">
|
||||
{% block sidebartitle %}
|
||||
<a href="{{ pathto(master_doc) }}" class="fa fa-home"> {{ project }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% if logo and theme_logo_only %}
|
||||
<a href="{{ pathto(master_doc) }}">
|
||||
{% else %}
|
||||
<a href="{{ pathto(master_doc) }}" class="icon icon-home"> {{ project }}
|
||||
{% endif %}
|
||||
|
||||
{% if logo %}
|
||||
{# Not strictly valid HTML, but it's the only way to display/scale it properly, without weird scripting or heaps of work #}
|
||||
<img src="{{ pathto('_static/' + logo, 1) }}" class="logo" />
|
||||
{% endif %}
|
||||
</a>
|
||||
|
||||
{% include "searchbox.html" %}
|
||||
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
{% block menu %}
|
||||
{% set toctree = toctree(maxdepth=2, collapse=False, includehidden=True) %}
|
||||
{% set toctree = toctree(maxdepth=4, collapse=False, includehidden=True) %}
|
||||
{% if toctree %}
|
||||
{{ toctree }}
|
||||
{% else %}
|
||||
|
||||
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
94
doc/_themes/sphinx_rtd_theme/static/js/theme.js
vendored
94
doc/_themes/sphinx_rtd_theme/static/js/theme.js
vendored
@@ -1,47 +1,113 @@
|
||||
$( document ).ready(function() {
|
||||
function toggleCurrent (elem) {
|
||||
var parent_li = elem.closest('li');
|
||||
parent_li.siblings('li.current').removeClass('current');
|
||||
parent_li.siblings().find('li.current').removeClass('current');
|
||||
parent_li.find('> ul li.current').removeClass('current');
|
||||
parent_li.toggleClass('current');
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
// Shift nav in mobile when clicking the menu.
|
||||
$(document).on('click', "[data-toggle='wy-nav-top']", function() {
|
||||
$("[data-toggle='wy-nav-shift']").toggleClass("shift");
|
||||
$("[data-toggle='rst-versions']").toggleClass("shift");
|
||||
});
|
||||
// Close menu when you click a link.
|
||||
// Nav menu link click operations
|
||||
$(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='rst-versions']").toggleClass("shift");
|
||||
// Handle dynamic display of l3 and l4 nav lists
|
||||
toggleCurrent(target);
|
||||
if (typeof(window.SphinxRtdTheme) != 'undefined') {
|
||||
window.SphinxRtdTheme.StickyNav.hashChange();
|
||||
}
|
||||
});
|
||||
$(document).on('click', "[data-toggle='rst-current-version']", function() {
|
||||
$("[data-toggle='rst-versions']").toggleClass("shift-up");
|
||||
});
|
||||
// Make tables responsive
|
||||
$("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>");
|
||||
|
||||
// Add expand links to all parents of nested ul
|
||||
$('.wy-menu-vertical ul').siblings('a').each(function () {
|
||||
var link = $(this);
|
||||
expand = $('<span class="toctree-expand"></span>');
|
||||
expand.on('click', function (ev) {
|
||||
toggleCurrent(link);
|
||||
ev.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
link.prepend(expand);
|
||||
});
|
||||
});
|
||||
|
||||
// Sphinx theme state
|
||||
window.SphinxRtdTheme = (function (jquery) {
|
||||
var stickyNav = (function () {
|
||||
var navBar,
|
||||
win,
|
||||
stickyNavCssClass = 'stickynav',
|
||||
applyStickNav = function () {
|
||||
if (navBar.height() <= win.height()) {
|
||||
navBar.addClass(stickyNavCssClass);
|
||||
} else {
|
||||
navBar.removeClass(stickyNavCssClass);
|
||||
}
|
||||
},
|
||||
winScroll = false,
|
||||
linkScroll = false,
|
||||
winPosition = 0,
|
||||
enable = function () {
|
||||
applyStickNav();
|
||||
win.on('resize', applyStickNav);
|
||||
init();
|
||||
reset();
|
||||
win.on('hashchange', reset);
|
||||
|
||||
// Set scrolling
|
||||
win.on('scroll', function () {
|
||||
if (!linkScroll) {
|
||||
winScroll = true;
|
||||
}
|
||||
});
|
||||
setInterval(function () {
|
||||
if (winScroll) {
|
||||
winScroll = false;
|
||||
var newWinPosition = win.scrollTop(),
|
||||
navPosition = navBar.scrollTop(),
|
||||
newNavPosition = navPosition + (newWinPosition - winPosition);
|
||||
navBar.scrollTop(newNavPosition);
|
||||
winPosition = newWinPosition;
|
||||
}
|
||||
}, 25);
|
||||
},
|
||||
init = function () {
|
||||
navBar = jquery('nav.wy-nav-side:first');
|
||||
win = jquery(window);
|
||||
},
|
||||
reset = function () {
|
||||
// Get anchor from URL and open up nested nav
|
||||
var anchor = encodeURI(window.location.hash);
|
||||
if (anchor) {
|
||||
try {
|
||||
var link = $('.wy-menu-vertical')
|
||||
.find('[href="' + anchor + '"]');
|
||||
$('.wy-menu-vertical li.toctree-l1 li.current')
|
||||
.removeClass('current');
|
||||
link.closest('li.toctree-l2').addClass('current');
|
||||
link.closest('li.toctree-l3').addClass('current');
|
||||
link.closest('li.toctree-l4').addClass('current');
|
||||
}
|
||||
catch (err) {
|
||||
console.log("Error expanding nav for anchor", err);
|
||||
}
|
||||
}
|
||||
},
|
||||
hashChange = function () {
|
||||
linkScroll = true;
|
||||
win.one('hashchange', function () {
|
||||
linkScroll = false;
|
||||
});
|
||||
};
|
||||
jquery(init);
|
||||
return {
|
||||
enable : enable
|
||||
enable: enable,
|
||||
hashChange: hashChange
|
||||
};
|
||||
}());
|
||||
return {
|
||||
StickyNav : stickyNav
|
||||
StickyNav: stickyNav
|
||||
};
|
||||
}($));
|
||||
|
||||
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
|
||||
analytics_id =
|
||||
sticky_navigation = False
|
||||
logo_only =
|
||||
|
||||
@@ -8,7 +8,7 @@ _h2load()
|
||||
_get_comp_words_by_ref cur prev
|
||||
case $cur in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W '--threads --connection-window-bits --input-file --help --requests --verbose --version --window-bits --clients --no-tls-proto --header --max-concurrent-streams ' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W '--threads --connection-window-bits --input-file --help --requests --data --verbose --version --window-bits --clients --no-tls-proto --header --max-concurrent-streams ' -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
_filedir
|
||||
|
||||
@@ -8,7 +8,7 @@ _nghttp()
|
||||
_get_comp_words_by_ref cur prev
|
||||
case $cur in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W '--verbose --no-dep --get-assets --har --header-table-size --multiply --padding --dep-idle --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --weight --help --key --null-out --window-bits --stat --header ' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --padding --hexdump --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --trailer --weight --help --key --null-out --window-bits --stat --header ' -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
_filedir
|
||||
|
||||
@@ -8,7 +8,7 @@ _nghttpd()
|
||||
_get_comp_words_by_ref cur prev
|
||||
case $cur in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W '--error-gzip --push --header-table-size --htdocs --padding --verbose --version --help --daemon --verify-client --workers --no-tls --color --early-response --dh-param-file ' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W '--error-gzip --push --header-table-size --trailer --htdocs --address --padding --verbose --version --help --hexdump --dh-param-file --daemon --verify-client --workers --no-tls --color --early-response --max-concurrent-streams ' -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
_filedir
|
||||
|
||||
@@ -8,7 +8,7 @@ _nghttpx()
|
||||
_get_comp_words_by_ref cur prev
|
||||
case $cur in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W '--frontend-http2-connection-window-bits --worker-read-rate --frontend-no-tls --frontend-http2-dump-request-header --daemon --write-rate --altsvc --frontend-http2-dump-response-header --backend-http1-connections-per-frontend --tls-ticket-key-file --ciphers --verify-client-cacert --backend-keep-alive-timeout --strip-incoming-x-forwarded-for --errorlog-file --private-key-passwd-file --version --backlog --backend-http-proxy-uri --add-response-header --backend-write-timeout --backend-request-buffer --add-x-forwarded-for --write-burst --backend-http2-connection-window-bits --insecure --rlimit-nofile --backend-http2-window-bits --tls-proto-list --no-location-rewrite --padding --accesslog-syslog --conf --http2-max-concurrent-streams --client-proxy --worker-frontend-connections --cacert --frontend-read-timeout --worker-write-burst --npn-list --syslog-facility --backend-http1-connections-per-host --no-server-push --client --http2-bridge --no-via --user --stream-write-timeout --backend-response-buffer --http2-no-cookie-crumbling --backend-read-timeout --stream-read-timeout --workers --worker-read-burst --tls-ctx-per-worker --dh-param-file --errorlog-syslog --frontend --accesslog-file --http2-proxy --read-burst --accesslog-format --frontend-http2-window-bits --backend-no-tls --client-private-key-file --pid-file --client-cert-file --no-host-rewrite --log-level --worker-write-rate --help --backend-tls-sni-field --subcert --frontend-frame-debug --frontend-write-timeout --verify-client --read-rate --frontend-http2-read-timeout --backend-ipv4 --listener-disable-timeout --backend-ipv6 --backend ' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W '--worker-read-rate --frontend-no-tls --frontend-http2-dump-response-header --backend-http1-connections-per-frontend --tls-ticket-key-file --verify-client-cacert --backend-request-buffer --backend-http2-connection-window-bits --conf --worker-write-burst --npn-list --fetch-ocsp-response-file --stream-read-timeout --accesslog-syslog --frontend-http2-read-timeout --listener-disable-timeout --frontend-http2-connection-window-bits --ciphers --strip-incoming-x-forwarded-for --daemon --backend-keep-alive-timeout --backend-http-proxy-uri --backend-http1-connections-per-host --rlimit-nofile --no-via --ocsp-update-interval --backend-write-timeout --client --http2-no-cookie-crumbling --worker-read-burst --client-proxy --http2-bridge --accesslog-format --errorlog-syslog --errorlog-file --http2-max-concurrent-streams --frontend-write-timeout --read-burst --backend-ipv4 --backend-ipv6 --backend --insecure --log-level --tls-proto-list --backend-http2-connections-per-worker --dh-param-file --worker-frontend-connections --header-field-buffer --no-server-push --no-location-rewrite --no-ocsp --backend-response-buffer --workers --frontend-http2-window-bits --no-host-rewrite --worker-write-rate --backend-tls-sni-field --subcert --help --frontend-frame-debug --pid-file --frontend-http2-dump-request-header --private-key-passwd-file --write-rate --altsvc --user --add-x-forwarded-for --syslog-facility --frontend-read-timeout --backlog --write-burst --backend-http2-window-bits --padding --stream-write-timeout --cacert --version --verify-client --backend-read-timeout --frontend --accesslog-file --http2-proxy --max-header-fields --backend-no-tls --client-private-key-file --client-cert-file --add-response-header --read-rate ' -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
_filedir
|
||||
|
||||
64
doc/h2load.1
64
doc/h2load.1
@@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "H2LOAD" "1" "February 27, 2015" "0.7.5" "nghttp2"
|
||||
.TH "H2LOAD" "1" "May 08, 2015" "0.7.14" "nghttp2"
|
||||
.SH NAME
|
||||
h2load \- HTTP/2 benchmarking tool
|
||||
.
|
||||
@@ -93,6 +93,8 @@ Default: \fBauto\fP
|
||||
.B \-w, \-\-window\-bits=<N>
|
||||
Sets the stream level initial window size to (2**<N>)\-1.
|
||||
For SPDY, 2**<N> is used instead.
|
||||
.sp
|
||||
Default: \fB30\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -101,6 +103,8 @@ Sets the connection level initial window size to
|
||||
(2**<N>)\-1. For SPDY, if <N> is strictly less than 16,
|
||||
this option is ignored. Otherwise 2**<N> is used for
|
||||
SPDY.
|
||||
.sp
|
||||
Default: \fB30\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -118,6 +122,12 @@ Default: \fBh2c\-14\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-d, \-\-data=<FILE>
|
||||
Post FILE to server. The request method is changed to
|
||||
POST.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-v, \-\-verbose
|
||||
Output debug information.
|
||||
.UNINDENT
|
||||
@@ -195,13 +205,63 @@ The maximum time taken for request and response.
|
||||
The mean time taken for request and response.
|
||||
.TP
|
||||
.B sd
|
||||
The standard deviation of the time for request and response.
|
||||
The standard deviation of the time taken for request and response.
|
||||
.TP
|
||||
.B +/\- sd
|
||||
The fraction of the number of requests within standard deviation
|
||||
range (mean +/\- sd) against total number of successful requests.
|
||||
.UNINDENT
|
||||
.TP
|
||||
.B time for connect
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
.B min
|
||||
The minimum time taken to connect to a server.
|
||||
.TP
|
||||
.B max
|
||||
The maximum time taken to connect to a server.
|
||||
.TP
|
||||
.B mean
|
||||
The mean time taken to connect to a server.
|
||||
.TP
|
||||
.B sd
|
||||
The standard deviation of the time taken to connect to a server.
|
||||
.TP
|
||||
.B +/\- sd
|
||||
The fraction of the number of connections within standard
|
||||
deviation range (mean +/\- sd) against total number of successful
|
||||
connections.
|
||||
.UNINDENT
|
||||
.TP
|
||||
.B time for 1st byte (of (decrypted in case of TLS) application data)
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
.B min
|
||||
The minimum time taken to get 1st byte from a server.
|
||||
.TP
|
||||
.B max
|
||||
The maximum time taken to get 1st byte from a server.
|
||||
.TP
|
||||
.B mean
|
||||
The mean time taken to get 1st byte from a server.
|
||||
.TP
|
||||
.B sd
|
||||
The standard deviation of the time taken to get 1st byte from a
|
||||
server.
|
||||
.TP
|
||||
.B +/\- sd
|
||||
The fraction of the number of connections within standard
|
||||
deviation range (mean +/\- sd) against total number of successful
|
||||
connections.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.SH FLOW CONTROL
|
||||
.sp
|
||||
h2load sets large flow control window by default, and effectively
|
||||
disables flow control to avoid under utilization of server
|
||||
performance. To set smaller flow control window, use \fI\%\-w\fP and
|
||||
\fI\%\-W\fP options. For example, use \fB\-w16 \-W16\fP to set default
|
||||
window size described in HTTP/2 and SPDY protocol specification.
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fInghttpx(1)\fP
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
.. program:: h2load
|
||||
|
||||
h2load(1)
|
||||
=========
|
||||
|
||||
@@ -65,6 +67,8 @@ OPTIONS
|
||||
Sets the stream level initial window size to (2\*\*<N>)-1.
|
||||
For SPDY, 2**<N> is used instead.
|
||||
|
||||
Default: ``30``
|
||||
|
||||
.. option:: -W, --connection-window-bits=<N>
|
||||
|
||||
Sets the connection level initial window size to
|
||||
@@ -72,6 +76,8 @@ OPTIONS
|
||||
this option is ignored. Otherwise 2\*\*<N> is used for
|
||||
SPDY.
|
||||
|
||||
Default: ``30``
|
||||
|
||||
.. option:: -H, --header=<HEADER>
|
||||
|
||||
Add/Override a header to the requests.
|
||||
@@ -84,6 +90,11 @@ OPTIONS
|
||||
|
||||
Default: ``h2c-14``
|
||||
|
||||
.. option:: -d, --data=<FILE>
|
||||
|
||||
Post FILE to server. The request method is changed to
|
||||
POST.
|
||||
|
||||
.. option:: -v, --verbose
|
||||
|
||||
Output debug information.
|
||||
@@ -142,11 +153,49 @@ time for request
|
||||
mean
|
||||
The mean time taken for request and response.
|
||||
sd
|
||||
The standard deviation of the time for request and response.
|
||||
The standard deviation of the time taken for request and response.
|
||||
+/- sd
|
||||
The fraction of the number of requests within standard deviation
|
||||
range (mean +/- sd) against total number of successful requests.
|
||||
|
||||
time for connect
|
||||
min
|
||||
The minimum time taken to connect to a server.
|
||||
max
|
||||
The maximum time taken to connect to a server.
|
||||
mean
|
||||
The mean time taken to connect to a server.
|
||||
sd
|
||||
The standard deviation of the time taken to connect to a server.
|
||||
+/- sd
|
||||
The fraction of the number of connections within standard
|
||||
deviation range (mean +/- sd) against total number of successful
|
||||
connections.
|
||||
|
||||
time for 1st byte (of (decrypted in case of TLS) application data)
|
||||
min
|
||||
The minimum time taken to get 1st byte from a server.
|
||||
max
|
||||
The maximum time taken to get 1st byte from a server.
|
||||
mean
|
||||
The mean time taken to get 1st byte from a server.
|
||||
sd
|
||||
The standard deviation of the time taken to get 1st byte from a
|
||||
server.
|
||||
+/- sd
|
||||
The fraction of the number of connections within standard
|
||||
deviation range (mean +/- sd) against total number of successful
|
||||
connections.
|
||||
|
||||
FLOW CONTROL
|
||||
------------
|
||||
|
||||
h2load sets large flow control window by default, and effectively
|
||||
disables flow control to avoid under utilization of server
|
||||
performance. To set smaller flow control window, use :option:`-w` and
|
||||
:option:`-W` options. For example, use ``-w16 -W16`` to set default
|
||||
window size described in HTTP/2 and SPDY protocol specification.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
|
||||
@@ -44,11 +44,49 @@ time for request
|
||||
mean
|
||||
The mean time taken for request and response.
|
||||
sd
|
||||
The standard deviation of the time for request and response.
|
||||
The standard deviation of the time taken for request and response.
|
||||
+/- sd
|
||||
The fraction of the number of requests within standard deviation
|
||||
range (mean +/- sd) against total number of successful requests.
|
||||
|
||||
time for connect
|
||||
min
|
||||
The minimum time taken to connect to a server.
|
||||
max
|
||||
The maximum time taken to connect to a server.
|
||||
mean
|
||||
The mean time taken to connect to a server.
|
||||
sd
|
||||
The standard deviation of the time taken to connect to a server.
|
||||
+/- sd
|
||||
The fraction of the number of connections within standard
|
||||
deviation range (mean +/- sd) against total number of successful
|
||||
connections.
|
||||
|
||||
time for 1st byte (of (decrypted in case of TLS) application data)
|
||||
min
|
||||
The minimum time taken to get 1st byte from a server.
|
||||
max
|
||||
The maximum time taken to get 1st byte from a server.
|
||||
mean
|
||||
The mean time taken to get 1st byte from a server.
|
||||
sd
|
||||
The standard deviation of the time taken to get 1st byte from a
|
||||
server.
|
||||
+/- sd
|
||||
The fraction of the number of connections within standard
|
||||
deviation range (mean +/- sd) against total number of successful
|
||||
connections.
|
||||
|
||||
FLOW CONTROL
|
||||
------------
|
||||
|
||||
h2load sets large flow control window by default, and effectively
|
||||
disables flow control to avoid under utilization of server
|
||||
performance. To set smaller flow control window, use :option:`-w` and
|
||||
:option:`-W` options. For example, use ``-w16 -W16`` to set default
|
||||
window size described in HTTP/2 and SPDY protocol specification.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
|
||||
124
doc/mkapiref.py
124
doc/mkapiref.py
@@ -24,19 +24,21 @@
|
||||
|
||||
# Generates API reference from C source code.
|
||||
from __future__ import print_function # At least python 2.6 is required
|
||||
import re, sys, argparse
|
||||
import re, sys, argparse, os.path
|
||||
|
||||
class FunctionDoc:
|
||||
def __init__(self, name, content, domain):
|
||||
self.name = name
|
||||
self.content = content
|
||||
self.domain = domain
|
||||
if self.domain == 'function':
|
||||
self.funcname = re.search(r'(nghttp2_[^ )]+)\(', self.name).group(1)
|
||||
|
||||
def write(self, out):
|
||||
print('''.. {}:: {}'''.format(self.domain, self.name))
|
||||
print('')
|
||||
out.write('.. {}:: {}\n'.format(self.domain, self.name))
|
||||
out.write('\n')
|
||||
for line in self.content:
|
||||
print(' {}'.format(line))
|
||||
out.write(' {}\n'.format(line))
|
||||
|
||||
class StructDoc:
|
||||
def __init__(self, name, content, members, member_domain):
|
||||
@@ -47,17 +49,17 @@ class StructDoc:
|
||||
|
||||
def write(self, out):
|
||||
if self.name:
|
||||
print('''.. type:: {}'''.format(self.name))
|
||||
print('')
|
||||
out.write('.. type:: {}\n'.format(self.name))
|
||||
out.write('\n')
|
||||
for line in self.content:
|
||||
print(' {}'.format(line))
|
||||
print('')
|
||||
out.write(' {}\n'.format(line))
|
||||
out.write('\n')
|
||||
for name, content in self.members:
|
||||
print(''' .. {}:: {}'''.format(self.member_domain, name))
|
||||
print('')
|
||||
out.write(' .. {}:: {}\n'.format(self.member_domain, name))
|
||||
out.write('\n')
|
||||
for line in content:
|
||||
print(''' {}'''.format(line))
|
||||
print('')
|
||||
out.write(' {}\n'.format(line))
|
||||
out.write('\n')
|
||||
|
||||
class MacroDoc:
|
||||
def __init__(self, name, content):
|
||||
@@ -65,10 +67,10 @@ class MacroDoc:
|
||||
self.content = content
|
||||
|
||||
def write(self, out):
|
||||
print('''.. macro:: {}'''.format(self.name))
|
||||
print('')
|
||||
out.write('''.. macro:: {}\n'''.format(self.name))
|
||||
out.write('\n')
|
||||
for line in self.content:
|
||||
print(' {}'.format(line))
|
||||
out.write(' {}\n'.format(line))
|
||||
|
||||
def make_api_ref(infiles):
|
||||
macros = []
|
||||
@@ -93,19 +95,65 @@ def make_api_ref(infiles):
|
||||
enums.append(process_enum(infile))
|
||||
elif doctype == '@macro':
|
||||
macros.append(process_macro(infile))
|
||||
return macros, enums, types, functions
|
||||
|
||||
alldocs = [('Macros', macros),
|
||||
('Enums', enums),
|
||||
('Types (structs, unions and typedefs)', types),
|
||||
('Functions', functions)]
|
||||
for title, docs in alldocs:
|
||||
if not docs:
|
||||
continue
|
||||
print(title)
|
||||
print('-'*len(title))
|
||||
for doc in docs:
|
||||
doc.write(sys.stdout)
|
||||
print('')
|
||||
print('')
|
||||
|
||||
def output(
|
||||
indexfile, macrosfile, enumsfile, typesfile, funcsdir,
|
||||
macros, enums, types, functions):
|
||||
indexfile.write('''
|
||||
API Reference
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
macros
|
||||
enums
|
||||
types
|
||||
''')
|
||||
|
||||
for doc in functions:
|
||||
indexfile.write(' {}\n'.format(doc.funcname))
|
||||
|
||||
macrosfile.write('''
|
||||
Macros
|
||||
======
|
||||
''')
|
||||
for doc in macros:
|
||||
doc.write(macrosfile)
|
||||
|
||||
enumsfile.write('''
|
||||
Enums
|
||||
=====
|
||||
''')
|
||||
for doc in enums:
|
||||
doc.write(enumsfile)
|
||||
|
||||
typesfile.write('''
|
||||
Types (structs, unions and typedefs)
|
||||
====================================
|
||||
''')
|
||||
for doc in types:
|
||||
doc.write(typesfile)
|
||||
|
||||
for doc in functions:
|
||||
with open(os.path.join(funcsdir, doc.funcname + '.rst'), 'w') as f:
|
||||
f.write('''
|
||||
{funcname}
|
||||
{secul}
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
*#include <nghttp2/nghttp2.h>*
|
||||
|
||||
'''.format(funcname=doc.funcname, secul='='*len(doc.funcname)))
|
||||
doc.write(f)
|
||||
|
||||
def process_macro(infile):
|
||||
content = read_content(infile)
|
||||
@@ -199,12 +247,30 @@ def transform_content(content):
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Generate API reference")
|
||||
parser.add_argument('--header', type=argparse.FileType('r'),
|
||||
help='header inserted at the top of the page')
|
||||
parser.add_argument('index', type=argparse.FileType('w'),
|
||||
help='index output file')
|
||||
parser.add_argument('macros', type=argparse.FileType('w'),
|
||||
help='macros section output file. The filename should be macros.rst')
|
||||
parser.add_argument('enums', type=argparse.FileType('w'),
|
||||
help='enums section output file. The filename should be enums.rst')
|
||||
parser.add_argument('types', type=argparse.FileType('w'),
|
||||
help='types section output file. The filename should be types.rst')
|
||||
parser.add_argument('funcsdir',
|
||||
help='functions doc output dir')
|
||||
parser.add_argument('files', nargs='+', type=argparse.FileType('r'),
|
||||
help='source file')
|
||||
args = parser.parse_args()
|
||||
if args.header:
|
||||
print(args.header.read())
|
||||
macros = []
|
||||
enums = []
|
||||
types = []
|
||||
funcs = []
|
||||
for infile in args.files:
|
||||
make_api_ref(args.files)
|
||||
m, e, t, f = make_api_ref(args.files)
|
||||
macros.extend(m)
|
||||
enums.extend(e)
|
||||
types.extend(t)
|
||||
funcs.extend(f)
|
||||
funcs.sort(key=lambda x: x.funcname)
|
||||
output(
|
||||
args.index, args.macros, args.enums, args.types, args.funcsdir,
|
||||
macros, enums, types, funcs)
|
||||
|
||||
90
doc/nghttp.1
90
doc/nghttp.1
@@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "NGHTTP" "1" "February 27, 2015" "0.7.5" "nghttp2"
|
||||
.TH "NGHTTP" "1" "May 08, 2015" "0.7.14" "nghttp2"
|
||||
.SH NAME
|
||||
nghttp \- HTTP/2 experimental client
|
||||
.
|
||||
@@ -64,8 +64,9 @@ yet.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-t, \-\-timeout=<SEC>
|
||||
Timeout each request after <SEC> seconds.
|
||||
.B \-t, \-\-timeout=<DURATION>
|
||||
Timeout each request after <DURATION>. Set 0 to disable
|
||||
timeout.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -101,6 +102,14 @@ Add a header to the requests. Example: \fI\%\-H\fP\(aq:method: PUT\(aq
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-trailer=<HEADER>
|
||||
Add a trailer header to the requests. <HEADER> must not
|
||||
include pseudo header field (header field name starting
|
||||
with \(aq:\(aq). To send trailer, one must use \fI\%\-d\fP option to
|
||||
send request body. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-cert=<CERT>
|
||||
Use the specified client certificate file. The file
|
||||
must be in PEM format.
|
||||
@@ -127,7 +136,7 @@ requested twice. This option disables it too.
|
||||
.TP
|
||||
.B \-u, \-\-upgrade
|
||||
Perform HTTP Upgrade for HTTP/2. This option is ignored
|
||||
if the request URI has https scheme. If \fI\-d\fP is used, the
|
||||
if the request URI has https scheme. If \fI\%\-d\fP is used, the
|
||||
HTTP upgrade request is performed with OPTIONS method.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
@@ -184,8 +193,15 @@ Don\(aqt send dependency based priority hint to server.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-dep\-idle
|
||||
Use idle streams as anchor nodes to express priority.
|
||||
.B \-\-hexdump
|
||||
Display the incoming traffic in hexadecimal (Canonical
|
||||
hex+ASCII display). If SSL/TLS is used, decrypted data
|
||||
are used.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-no\-push
|
||||
Disable server push.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -200,6 +216,68 @@ Display this help and exit.
|
||||
.sp
|
||||
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||
10 * 1024). Units are K, M and G (powers of 1024).
|
||||
.sp
|
||||
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
||||
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
|
||||
(hours, minutes, seconds and milliseconds, respectively). If a unit
|
||||
is omitted, a second is used as unit.
|
||||
.SH DEPENDENCY BASED PRIORITY
|
||||
.sp
|
||||
nghttp sends priority hints to server by default unless
|
||||
\fI\%\-\-no\-dep\fP is used. nghttp mimics the way Firefox employs to
|
||||
manages dependency using idle streams. We follows the behaviour of
|
||||
Firefox Nightly as of April, 2015, and nghttp\(aqs behaviour is very
|
||||
static and could be different from Firefox in detail. But reproducing
|
||||
the same behaviour of Firefox is not our goal. The goal is provide
|
||||
the easy way to test out the dependency priority in server
|
||||
implementation.
|
||||
.sp
|
||||
When connection is established, nghttp sends 5 PRIORITY frames to idle
|
||||
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
|
||||
tree:
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
+\-\-\-\-\-+
|
||||
|id=0 |
|
||||
+\-\-\-\-\-+
|
||||
^ ^ ^
|
||||
w=201 / | \e w=1
|
||||
/ | \e
|
||||
/ w=101| \e
|
||||
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
|
||||
|id=3 | |id=5 | |id=7 |
|
||||
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
|
||||
^ ^
|
||||
w=1 | w=1 |
|
||||
| |
|
||||
+\-\-\-\-\-+ +\-\-\-\-\-+
|
||||
|id=11| |id=9 |
|
||||
+\-\-\-\-\-+ +\-\-\-\-\-+
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
In the above figure, \fBid\fP means stream ID, and \fBw\fP means weight.
|
||||
The stream 0 is non\-existence stream, and forms the root of the tree.
|
||||
The stream 7 and 9 are not used for now.
|
||||
.sp
|
||||
The URIs given in the command\-line depend on stream 11 with the weight
|
||||
given in \fI\%\-p\fP option, which defaults to 16.
|
||||
.sp
|
||||
If \fI\%\-a\fP option is used, nghttp parses the resource pointed by
|
||||
URI given in command\-line as html, and extracts resource links from
|
||||
it. When requesting those resources, nghttp uses dependency according
|
||||
to its resource type.
|
||||
.sp
|
||||
For CSS, and Javascript files inside "head" element, they depend on
|
||||
stream 3 with the weight 2. The Javascript files outside "head"
|
||||
element depend on stream 5 with the weight 2. The mages depend on
|
||||
stream 11 with the weight 12. The other resources (e.g., icon) depend
|
||||
on stream 11 with the weight 2.
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
\fInghttpd(1)\fP, \fInghttpx(1)\fP, \fIh2load(1)\fP
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
.. program:: nghttp
|
||||
|
||||
nghttp(1)
|
||||
=========
|
||||
|
||||
@@ -36,9 +38,10 @@ OPTIONS
|
||||
'index.html' is used as a filename. Not implemented
|
||||
yet.
|
||||
|
||||
.. option:: -t, --timeout=<SEC>
|
||||
.. option:: -t, --timeout=<DURATION>
|
||||
|
||||
Timeout each request after <SEC> seconds.
|
||||
Timeout each request after <DURATION>. Set 0 to disable
|
||||
timeout.
|
||||
|
||||
.. option:: -w, --window-bits=<N>
|
||||
|
||||
@@ -67,6 +70,13 @@ OPTIONS
|
||||
|
||||
Add a header to the requests. Example: :option:`-H`\':method: PUT'
|
||||
|
||||
.. option:: --trailer=<HEADER>
|
||||
|
||||
Add a trailer header to the requests. <HEADER> must not
|
||||
include pseudo header field (header field name starting
|
||||
with ':'). To send trailer, one must use :option:`-d` option to
|
||||
send request body. Example: :option:`--trailer` 'foo: bar'.
|
||||
|
||||
.. option:: --cert=<CERT>
|
||||
|
||||
Use the specified client certificate file. The file
|
||||
@@ -136,9 +146,15 @@ OPTIONS
|
||||
|
||||
Don't send dependency based priority hint to server.
|
||||
|
||||
.. option:: --dep-idle
|
||||
.. option:: --hexdump
|
||||
|
||||
Use idle streams as anchor nodes to express priority.
|
||||
Display the incoming traffic in hexadecimal (Canonical
|
||||
hex+ASCII display). If SSL/TLS is used, decrypted data
|
||||
are used.
|
||||
|
||||
.. option:: --no-push
|
||||
|
||||
Disable server push.
|
||||
|
||||
.. option:: --version
|
||||
|
||||
@@ -149,9 +165,66 @@ OPTIONS
|
||||
Display this help and exit.
|
||||
|
||||
|
||||
|
||||
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||
10 * 1024). Units are K, M and G (powers of 1024).
|
||||
|
||||
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
||||
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
|
||||
(hours, minutes, seconds and milliseconds, respectively). If a unit
|
||||
is omitted, a second is used as unit.
|
||||
|
||||
DEPENDENCY BASED PRIORITY
|
||||
-------------------------
|
||||
|
||||
nghttp sends priority hints to server by default unless
|
||||
:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
|
||||
manages dependency using idle streams. We follows the behaviour of
|
||||
Firefox Nightly as of April, 2015, and nghttp's behaviour is very
|
||||
static and could be different from Firefox in detail. But reproducing
|
||||
the same behaviour of Firefox is not our goal. The goal is provide
|
||||
the easy way to test out the dependency priority in server
|
||||
implementation.
|
||||
|
||||
When connection is established, nghttp sends 5 PRIORITY frames to idle
|
||||
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
|
||||
tree::
|
||||
|
||||
+-----+
|
||||
|id=0 |
|
||||
+-----+
|
||||
^ ^ ^
|
||||
w=201 / | \ w=1
|
||||
/ | \
|
||||
/ w=101| \
|
||||
+-----+ +-----+ +-----+
|
||||
|id=3 | |id=5 | |id=7 |
|
||||
+-----+ +-----+ +-----+
|
||||
^ ^
|
||||
w=1 | w=1 |
|
||||
| |
|
||||
+-----+ +-----+
|
||||
|id=11| |id=9 |
|
||||
+-----+ +-----+
|
||||
|
||||
In the above figure, ``id`` means stream ID, and ``w`` means weight.
|
||||
The stream 0 is non-existence stream, and forms the root of the tree.
|
||||
The stream 7 and 9 are not used for now.
|
||||
|
||||
The URIs given in the command-line depend on stream 11 with the weight
|
||||
given in :option:`-p` option, which defaults to 16.
|
||||
|
||||
If :option:`-a` option is used, nghttp parses the resource pointed by
|
||||
URI given in command-line as html, and extracts resource links from
|
||||
it. When requesting those resources, nghttp uses dependency according
|
||||
to its resource type.
|
||||
|
||||
For CSS, and Javascript files inside "head" element, they depend on
|
||||
stream 3 with the weight 2. The Javascript files outside "head"
|
||||
element depend on stream 5 with the weight 2. The mages depend on
|
||||
stream 11 with the weight 12. The other resources (e.g., icon) depend
|
||||
on stream 11 with the weight 2.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
|
||||
@@ -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
|
||||
--------
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "NGHTTPD" "1" "February 27, 2015" "0.7.5" "nghttp2"
|
||||
.TH "NGHTTPD" "1" "May 08, 2015" "0.7.14" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpd \- HTTP/2 experimental server
|
||||
.
|
||||
@@ -63,7 +63,7 @@ address determined by getaddrinfo is used.
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-D, \-\-daemon
|
||||
Run in a background. If \fI\-D\fP is used, the current working
|
||||
Run in a background. If \fI\%\-D\fP is used, the current working
|
||||
directory is changed to \(aq\fI/\fP\(aq. Therefore if this option
|
||||
is used, \fI\%\-d\fP option must be specified.
|
||||
.UNINDENT
|
||||
@@ -109,7 +109,7 @@ Push resources <PUSH_PATH>s when <PATH> is requested.
|
||||
This option can be used repeatedly to specify multiple
|
||||
push configurations. <PATH> and <PUSH_PATH>s are
|
||||
relative to document root. See \fI\%\-\-htdocs\fP option.
|
||||
Example: \fI\-p\fP/=/foo.png \fI\-p\fP/doc=/bar.css
|
||||
Example: \fI\%\-p\fP/=/foo.png \fI\%\-p\fP/doc=/bar.css
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -119,6 +119,14 @@ Specify 0 to disable padding.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-m, \-\-max\-concurrent\-streams=<N>
|
||||
Set the maximum number of the concurrent streams in one
|
||||
HTTP/2 session.
|
||||
.sp
|
||||
Default: \fB100\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-n, \-\-workers=<N>
|
||||
Set the number of worker threads.
|
||||
.sp
|
||||
@@ -144,6 +152,21 @@ rather than complete request is received.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-trailer=<HEADER>
|
||||
Add a trailer header to a response. <HEADER> must not
|
||||
include pseudo header field (header field name starting
|
||||
with \(aq:\(aq). The trailer is sent only if a response has
|
||||
body part. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-hexdump
|
||||
Display the incoming traffic in hexadecimal (Canonical
|
||||
hex+ASCII display). If SSL/TLS is used, decrypted data
|
||||
are used.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-version
|
||||
Display version information and exit.
|
||||
.UNINDENT
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
.. program:: nghttpd
|
||||
|
||||
nghttpd(1)
|
||||
==========
|
||||
|
||||
@@ -83,6 +85,13 @@ OPTIONS
|
||||
Add at most <N> bytes to a frame payload as padding.
|
||||
Specify 0 to disable padding.
|
||||
|
||||
.. option:: -m, --max-concurrent-streams=<N>
|
||||
|
||||
Set the maximum number of the concurrent streams in one
|
||||
HTTP/2 session.
|
||||
|
||||
Default: ``100``
|
||||
|
||||
.. option:: -n, --workers=<N>
|
||||
|
||||
Set the number of worker threads.
|
||||
@@ -104,6 +113,19 @@ OPTIONS
|
||||
Start sending response when request HEADERS is received,
|
||||
rather than complete request is received.
|
||||
|
||||
.. option:: --trailer=<HEADER>
|
||||
|
||||
Add a trailer header to a response. <HEADER> must not
|
||||
include pseudo header field (header field name starting
|
||||
with ':'). The trailer is sent only if a response has
|
||||
body part. Example: :option:`--trailer` 'foo: bar'.
|
||||
|
||||
.. option:: --hexdump
|
||||
|
||||
Display the incoming traffic in hexadecimal (Canonical
|
||||
hex+ASCII display). If SSL/TLS is used, decrypted data
|
||||
are used.
|
||||
|
||||
.. option:: --version
|
||||
|
||||
Display version information and exit.
|
||||
@@ -113,6 +135,7 @@ OPTIONS
|
||||
Display this help and exit.
|
||||
|
||||
|
||||
|
||||
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||
10 * 1024). Units are K, M and G (powers of 1024).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "NGHTTPX" "1" "February 27, 2015" "0.7.5" "nghttp2"
|
||||
.TH "NGHTTPX" "1" "May 08, 2015" "0.7.14" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpx \- HTTP/2 experimental proxy
|
||||
.
|
||||
@@ -46,7 +46,8 @@ Set path to server\(aqs private key. Required unless \fI\%\-p\fP,
|
||||
.TP
|
||||
.B <CERT>
|
||||
Set path to server\(aqs certificate. Required unless \fI\%\-p\fP,
|
||||
\fI\%\-\-client\fP or \fI\%\-\-frontend\-no\-tls\fP are given.
|
||||
\fI\%\-\-client\fP or \fI\%\-\-frontend\-no\-tls\fP are given. To make OCSP
|
||||
stapling work, this must be absolute path.
|
||||
.UNINDENT
|
||||
.SH OPTIONS
|
||||
.sp
|
||||
@@ -55,13 +56,10 @@ The options are categorized into several groups.
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-b, \-\-backend=<HOST,PORT>
|
||||
Set backend host and port. For HTTP/1 backend, multiple
|
||||
backend addresses are accepted by repeating this option.
|
||||
HTTP/2 backend does not support multiple backend
|
||||
addresses and the first occurrence of this option is
|
||||
used. UNIX domain socket can be specified by prefixing
|
||||
path name with "unix:" (e.g.,
|
||||
unix:/var/run/backend.sock)
|
||||
Set backend host and port. The multiple backend
|
||||
addresses are accepted by repeating this option. UNIX
|
||||
domain socket can be specified by prefixing path name
|
||||
with "unix:" (e.g., unix:/var/run/backend.sock)
|
||||
.sp
|
||||
Default: \fB127.0.0.1,80\fP
|
||||
.UNINDENT
|
||||
@@ -196,6 +194,13 @@ Default: \fB0\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-backend\-http2\-connections\-per\-worker=<N>
|
||||
Set maximum number of HTTP/2 connections per worker.
|
||||
The default value is 0, which means the number of
|
||||
backend addresses specified by \fI\%\-b\fP option.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-backend\-http1\-connections\-per\-host=<N>
|
||||
Set maximum number of backend concurrent HTTP/1
|
||||
connections per host. This option is meaningful when \fI\%\-s\fP
|
||||
@@ -245,14 +250,14 @@ Default: \fB16K\fP
|
||||
Specify read timeout for HTTP/2 and SPDY frontend
|
||||
connection.
|
||||
.sp
|
||||
Default: \fB180s\fP
|
||||
Default: \fB3m\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-frontend\-read\-timeout=<DURATION>
|
||||
Specify read timeout for HTTP/1.1 frontend connection.
|
||||
.sp
|
||||
Default: \fB180s\fP
|
||||
Default: \fB3m\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -282,7 +287,7 @@ Default: \fB0\fP
|
||||
.B \-\-backend\-read\-timeout=<DURATION>
|
||||
Specify read timeout for backend connection.
|
||||
.sp
|
||||
Default: \fB180s\fP
|
||||
Default: \fB3m\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -344,7 +349,8 @@ password protected it\(aqll be requested interactively.
|
||||
Specify additional certificate and private key file.
|
||||
nghttpx will choose certificates based on the hostname
|
||||
indicated by client using TLS SNI extension. This
|
||||
option can be used multiple times.
|
||||
option can be used multiple times. To make OCSP
|
||||
stapling work, <CERTPATH> must be absolute path.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -429,14 +435,23 @@ are stored in memory.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-ctx\-per\-worker
|
||||
Create OpenSSL\(aqs SSL_CTX per worker, so that no internal
|
||||
locking is required. This may improve scalability with
|
||||
multi threaded configuration. If this option is
|
||||
enabled, session ID is no longer shared accross SSL_CTX
|
||||
objects, which means session ID generated by one worker
|
||||
is not acceptable by another worker. On the other hand,
|
||||
session ticket key is shared across all worker threads.
|
||||
.B \-\-fetch\-ocsp\-response\-file=<PATH>
|
||||
Path to fetch\-ocsp\-response script file. It should be
|
||||
absolute path.
|
||||
.sp
|
||||
Default: \fB/usr/local/share/nghttp2/fetch\-ocsp\-response\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-ocsp\-update\-interval=<DURATION>
|
||||
Set interval to update OCSP response cache.
|
||||
.sp
|
||||
Default: \fB4h\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-no\-ocsp
|
||||
Disable OCSP stapling.
|
||||
.UNINDENT
|
||||
.SS HTTP/2 and SPDY
|
||||
.INDENT 0.0
|
||||
@@ -617,7 +632,8 @@ Default: \fB$remote_addr \- \- [$time_local] "$request" $status $body_bytes_sent
|
||||
.TP
|
||||
.B \-\-errorlog\-file=<PATH>
|
||||
Set path to write error log. To reopen file, send USR1
|
||||
signal to nghttpx.
|
||||
signal to nghttpx. stderr will be redirected to the
|
||||
error log file unless \fI\%\-\-errorlog\-syslog\fP is used.
|
||||
.sp
|
||||
Default: \fB/dev/stderr\fP
|
||||
.UNINDENT
|
||||
@@ -688,6 +704,23 @@ won\(aqt replace anything already set. This option can be
|
||||
used several times to specify multiple header fields.
|
||||
Example: \fI\%\-\-add\-response\-header\fP="foo: bar"
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-header\-field\-buffer=<SIZE>
|
||||
Set maximum buffer size for incoming HTTP header field
|
||||
list. This is the sum of header name and value in
|
||||
bytes.
|
||||
.sp
|
||||
Default: \fB64K\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-max\-header\-fields=<N>
|
||||
Set maximum number of incoming HTTP header fields, which
|
||||
appear in one request or response header field list.
|
||||
.sp
|
||||
Default: \fB100\fP
|
||||
.UNINDENT
|
||||
.SS Debug
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -755,8 +788,9 @@ The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||
10 * 1024). Units are K, M and G (powers of 1024).
|
||||
.sp
|
||||
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
||||
is 1 second and 500ms is 500 milliseconds). Units are s or ms. If
|
||||
a unit is omitted, a second is used as unit.
|
||||
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
|
||||
(hours, minutes, seconds and milliseconds, respectively). If a unit
|
||||
is omitted, a second is used as unit.
|
||||
.SH FILES
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -845,6 +879,15 @@ specified socket already exists in the file system, nghttpx first
|
||||
deletes it. However, if SIGUSR2 is used to execute new binary and
|
||||
both old and new configurations use same filename, new binary does not
|
||||
delete the socket and continues to use it.
|
||||
.SH OCSP STAPLING
|
||||
.sp
|
||||
OCSP query is done using external perl script \fBfetch\-ocsp\-response\fP,
|
||||
which has been developed as part of h2o project
|
||||
(\fI\%https://github.com/h2o/h2o\fP).
|
||||
.sp
|
||||
The script file is usually installed under
|
||||
\fB$(prefix)/share/nghttp2/\fP directory. The actual path to script can
|
||||
be customized using \fI\%\-\-fetch\-ocsp\-response\-file\fP option.
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
\fInghttp(1)\fP, \fInghttpd(1)\fP, \fIh2load(1)\fP
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
.. program:: nghttpx
|
||||
|
||||
nghttpx(1)
|
||||
==========
|
||||
|
||||
@@ -21,7 +23,8 @@ A reverse proxy for HTTP/2, HTTP/1 and SPDY.
|
||||
.. describe:: <CERT>
|
||||
|
||||
Set path to server's certificate. Required unless :option:`-p`\,
|
||||
:option:`--client` or :option:`\--frontend-no-tls` are given.
|
||||
:option:`--client` or :option:`\--frontend-no-tls` are given. To make OCSP
|
||||
stapling work, this must be absolute path.
|
||||
|
||||
|
||||
OPTIONS
|
||||
@@ -34,13 +37,10 @@ Connections
|
||||
|
||||
.. option:: -b, --backend=<HOST,PORT>
|
||||
|
||||
Set backend host and port. For HTTP/1 backend, multiple
|
||||
backend addresses are accepted by repeating this option.
|
||||
HTTP/2 backend does not support multiple backend
|
||||
addresses and the first occurrence of this option is
|
||||
used. UNIX domain socket can be specified by prefixing
|
||||
path name with "unix:" (e.g.,
|
||||
unix:/var/run/backend.sock)
|
||||
Set backend host and port. The multiple backend
|
||||
addresses are accepted by repeating this option. UNIX
|
||||
domain socket can be specified by prefixing path name
|
||||
with "unix:" (e.g., unix:/var/run/backend.sock)
|
||||
|
||||
Default: ``127.0.0.1,80``
|
||||
|
||||
@@ -161,6 +161,12 @@ Performance
|
||||
|
||||
Default: ``0``
|
||||
|
||||
.. option:: --backend-http2-connections-per-worker=<N>
|
||||
|
||||
Set maximum number of HTTP/2 connections per worker.
|
||||
The default value is 0, which means the number of
|
||||
backend addresses specified by :option:`-b` option.
|
||||
|
||||
.. option:: --backend-http1-connections-per-host=<N>
|
||||
|
||||
Set maximum number of backend concurrent HTTP/1
|
||||
@@ -209,13 +215,13 @@ Timeout
|
||||
Specify read timeout for HTTP/2 and SPDY frontend
|
||||
connection.
|
||||
|
||||
Default: ``180s``
|
||||
Default: ``3m``
|
||||
|
||||
.. option:: --frontend-read-timeout=<DURATION>
|
||||
|
||||
Specify read timeout for HTTP/1.1 frontend connection.
|
||||
|
||||
Default: ``180s``
|
||||
Default: ``3m``
|
||||
|
||||
.. option:: --frontend-write-timeout=<DURATION>
|
||||
|
||||
@@ -241,7 +247,7 @@ Timeout
|
||||
|
||||
Specify read timeout for backend connection.
|
||||
|
||||
Default: ``180s``
|
||||
Default: ``3m``
|
||||
|
||||
.. option:: --backend-write-timeout=<DURATION>
|
||||
|
||||
@@ -298,7 +304,8 @@ SSL/TLS
|
||||
Specify additional certificate and private key file.
|
||||
nghttpx will choose certificates based on the hostname
|
||||
indicated by client using TLS SNI extension. This
|
||||
option can be used multiple times.
|
||||
option can be used multiple times. To make OCSP
|
||||
stapling work, <CERTPATH> must be absolute path.
|
||||
|
||||
.. option:: --backend-tls-sni-field=<HOST>
|
||||
|
||||
@@ -372,15 +379,22 @@ SSL/TLS
|
||||
automatically and renewed every 12hrs. At most 2 keys
|
||||
are stored in memory.
|
||||
|
||||
.. option:: --tls-ctx-per-worker
|
||||
.. option:: --fetch-ocsp-response-file=<PATH>
|
||||
|
||||
Create OpenSSL's SSL_CTX per worker, so that no internal
|
||||
locking is required. This may improve scalability with
|
||||
multi threaded configuration. If this option is
|
||||
enabled, session ID is no longer shared accross SSL_CTX
|
||||
objects, which means session ID generated by one worker
|
||||
is not acceptable by another worker. On the other hand,
|
||||
session ticket key is shared across all worker threads.
|
||||
Path to fetch-ocsp-response script file. It should be
|
||||
absolute path.
|
||||
|
||||
Default: ``/usr/local/share/nghttp2/fetch-ocsp-response``
|
||||
|
||||
.. option:: --ocsp-update-interval=<DURATION>
|
||||
|
||||
Set interval to update OCSP response cache.
|
||||
|
||||
Default: ``4h``
|
||||
|
||||
.. option:: --no-ocsp
|
||||
|
||||
Disable OCSP stapling.
|
||||
|
||||
|
||||
HTTP/2 and SPDY
|
||||
@@ -539,7 +553,8 @@ Logging
|
||||
.. option:: --errorlog-file=<PATH>
|
||||
|
||||
Set path to write error log. To reopen file, send USR1
|
||||
signal to nghttpx.
|
||||
signal to nghttpx. stderr will be redirected to the
|
||||
error log file unless :option:`--errorlog-syslog` is used.
|
||||
|
||||
Default: ``/dev/stderr``
|
||||
|
||||
@@ -604,6 +619,21 @@ HTTP
|
||||
used several times to specify multiple header fields.
|
||||
Example: :option:`--add-response-header`\="foo: bar"
|
||||
|
||||
.. option:: --header-field-buffer=<SIZE>
|
||||
|
||||
Set maximum buffer size for incoming HTTP header field
|
||||
list. This is the sum of header name and value in
|
||||
bytes.
|
||||
|
||||
Default: ``64K``
|
||||
|
||||
.. option:: --max-header-fields=<N>
|
||||
|
||||
Set maximum number of incoming HTTP header fields, which
|
||||
appear in one request or response header field list.
|
||||
|
||||
Default: ``100``
|
||||
|
||||
|
||||
Debug
|
||||
~~~~~
|
||||
@@ -667,12 +697,14 @@ Misc
|
||||
Print this help and exit.
|
||||
|
||||
|
||||
|
||||
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||
10 * 1024). Units are K, M and G (powers of 1024).
|
||||
|
||||
The <DURATION> argument is an integer and an optional unit (e.g., 1s
|
||||
is 1 second and 500ms is 500 milliseconds). Units are s or ms. If
|
||||
a unit is omitted, a second is used as unit.
|
||||
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
|
||||
(hours, minutes, seconds and milliseconds, respectively). If a unit
|
||||
is omitted, a second is used as unit.
|
||||
|
||||
FILES
|
||||
-----
|
||||
@@ -760,6 +792,17 @@ deletes it. However, if SIGUSR2 is used to execute new binary and
|
||||
both old and new configurations use same filename, new binary does not
|
||||
delete the socket and continues to use it.
|
||||
|
||||
OCSP STAPLING
|
||||
-------------
|
||||
|
||||
OCSP query is done using external perl script ``fetch-ocsp-response``,
|
||||
which has been developed as part of h2o project
|
||||
(https://github.com/h2o/h2o).
|
||||
|
||||
The script file is usually installed under
|
||||
``$(prefix)/share/nghttp2/`` directory. The actual path to script can
|
||||
be customized using :option:`--fetch-ocsp-response-file` option.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
|
||||
@@ -84,6 +84,17 @@ deletes it. However, if SIGUSR2 is used to execute new binary and
|
||||
both old and new configurations use same filename, new binary does not
|
||||
delete the socket and continues to use it.
|
||||
|
||||
OCSP STAPLING
|
||||
-------------
|
||||
|
||||
OCSP query is done using external perl script ``fetch-ocsp-response``,
|
||||
which has been developed as part of h2o project
|
||||
(https://github.com/h2o/h2o).
|
||||
|
||||
The script file is usually installed under
|
||||
``$(prefix)/share/nghttp2/`` directory. The actual path to script can
|
||||
be customized using :option:`--fetch-ocsp-response-file` option.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
API Reference
|
||||
=============
|
||||
Programmers' Guide
|
||||
==================
|
||||
|
||||
Includes
|
||||
--------
|
||||
@@ -32,6 +32,8 @@ value. The applications are responsible to receive it before calling
|
||||
these functions if :type:`nghttp2_session` is configured as server and
|
||||
`nghttp2_option_set_recv_client_preface()` is not used.
|
||||
|
||||
.. _http-messaging:
|
||||
|
||||
HTTP Messaging
|
||||
--------------
|
||||
|
||||
@@ -84,6 +86,11 @@ are floating around in existing internet and resetting stream just
|
||||
because of this may break many web sites. This is especially true if
|
||||
we forward to or translate from HTTP/1 traffic.
|
||||
|
||||
For "http" or "https" URIs, ":path" pseudo header fields must start
|
||||
with "/". The only exception is OPTIONS request, in that case, "*" is
|
||||
allowed in ":path" pseudo header field to represent system-wide
|
||||
OPTIONS request.
|
||||
|
||||
With the above validations, nghttp2 library guarantees that header
|
||||
field name passed to `nghttp2_on_header_callback()` is not empty.
|
||||
Also required pseudo headers are all present and not empty.
|
||||
@@ -50,8 +50,9 @@ Flow Control
|
||||
------------
|
||||
|
||||
HTTP/2 and SPDY/3 or later employ flow control and it may affect
|
||||
benchmarking results. To adjust receiver flow control window size,
|
||||
there is following options:
|
||||
benchmarking results. By default, h2load uses large enough flow
|
||||
control window, which effectively disables flow control. To adjust
|
||||
receiver flow control window size, there are following options:
|
||||
|
||||
``-w``
|
||||
Sets the stream level initial window size to
|
||||
|
||||
@@ -28,6 +28,7 @@ Contents:
|
||||
h2load.1
|
||||
nghttpx-howto
|
||||
h2load-howto
|
||||
programmers-guide
|
||||
apiref
|
||||
libnghttp2_asio
|
||||
python-apiref
|
||||
|
||||
@@ -220,6 +220,10 @@ HTTP/2 servers
|
||||
|
||||
This is a value of ``:path`` header field.
|
||||
|
||||
.. py:attribute:: headers
|
||||
|
||||
Request header fields.
|
||||
|
||||
A :py:class:`BaseRequestHandler` has the following methods:
|
||||
|
||||
.. py:method:: on_headers()
|
||||
@@ -250,9 +254,27 @@ HTTP/2 servers
|
||||
is additional response headers. The *:status* header field will
|
||||
be appended by the library. The *body* is the response body.
|
||||
It could be ``None`` if response body is empty. Or it must be
|
||||
instance of either ``str``, ``bytes`` or :py:class:`io.IOBase`.
|
||||
If instance of ``str`` is specified, it will be encoded using
|
||||
UTF-8.
|
||||
instance of either ``str``, ``bytes``, :py:class:`io.IOBase` or
|
||||
callable, called body generator, which takes one parameter,
|
||||
size. The body generator generates response body. It can pause
|
||||
generation of response so that it can wait for slow backend data
|
||||
generation. When invoked, it should return tuple, byte string
|
||||
at most size length and flag. The flag is either
|
||||
:py:data:`DATA_OK`, :py:data:`DATA_EOF` or
|
||||
:py:data:`DATA_DEFERRED`. For non-empty byte string and it is
|
||||
not the last chunk of response, :py:data:`DATA_OK` must be
|
||||
returned as flag. If this is the last chunk of the response
|
||||
(byte string could be ``None``), :py:data:`DATA_EOF` must be
|
||||
returned as flag. If there is no data available right now, but
|
||||
additional data are anticipated, return tuple (``None``,
|
||||
:py:data:`DATA_DEFERRD`). When data arrived, call
|
||||
:py:meth:`resume()` and restart response body transmission.
|
||||
|
||||
Only the body generator can pause response body generation;
|
||||
instance of :py:class:`io.IOBase` must not block.
|
||||
|
||||
If instance of ``str`` is specified as *body*, it will be
|
||||
encoded using UTF-8.
|
||||
|
||||
The *headers* is a list of tuple of the form ``(name,
|
||||
value)``. The ``name`` and ``value`` can be either byte string
|
||||
@@ -273,10 +295,8 @@ HTTP/2 servers
|
||||
|
||||
The *status* is HTTP status code. The *headers* is additional
|
||||
response headers. The ``:status`` header field is appended by
|
||||
the library. The *body* is the response body. It could be
|
||||
``None`` if response body is empty. Or it must be instance of
|
||||
either ``str``, ``bytes`` or ``io.IOBase``. If instance of
|
||||
``str`` is specified, it is encoded using UTF-8.
|
||||
the library. The *body* is the response body. It has the same
|
||||
semantics of *body* parameter of :py:meth:`send_response()`.
|
||||
|
||||
The headers and request_headers are a list of tuple of the form
|
||||
``(name, value)``. The ``name`` and ``value`` can be either byte
|
||||
@@ -288,6 +308,27 @@ HTTP/2 servers
|
||||
|
||||
Raises the exception if any error occurs.
|
||||
|
||||
.. py:method:: resume()
|
||||
|
||||
Signals the restarting of response body transmission paused by
|
||||
``DATA_DEFERRED`` from the body generator (see
|
||||
:py:meth:`send_response()` about the body generator). It is not
|
||||
an error calling this method while response body transmission is
|
||||
not paused.
|
||||
|
||||
.. py:data:: DATA_OK
|
||||
|
||||
``DATA_OK`` indicates non empty data is generated from body generator.
|
||||
|
||||
.. py:data:: DATA_EOF
|
||||
|
||||
``DATA_EOF`` indicates the end of response body.
|
||||
|
||||
.. py:data:: DATA_DEFERRED
|
||||
|
||||
``DATA_DEFERRED`` indicates that data are not available right now
|
||||
and response should be paused.
|
||||
|
||||
The following example illustrates :py:class:`HTTP2Server` and
|
||||
:py:class:`BaseRequestHandler` usage:
|
||||
|
||||
@@ -296,6 +337,7 @@ The following example illustrates :py:class:`HTTP2Server` and
|
||||
#!/usr/bin/env python
|
||||
|
||||
import io, ssl
|
||||
|
||||
import nghttp2
|
||||
|
||||
class Handler(nghttp2.BaseRequestHandler):
|
||||
@@ -311,9 +353,85 @@ The following example illustrates :py:class:`HTTP2Server` and
|
||||
body=io.BytesIO(b'nghttp2-python FTW'))
|
||||
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2
|
||||
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
|
||||
ctx.load_cert_chain('server.crt', 'server.key')
|
||||
|
||||
# give None to ssl to make the server non-SSL/TLS
|
||||
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
|
||||
server.serve_forever()
|
||||
|
||||
The following example illustrates HTTP/2 server using asynchronous
|
||||
response body generation. This is simplified reverse proxy:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
import ssl
|
||||
import os
|
||||
import urllib
|
||||
import asyncio
|
||||
import io
|
||||
|
||||
import nghttp2
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_http_header(handler, url):
|
||||
url = urllib.parse.urlsplit(url)
|
||||
ssl = url.scheme == 'https'
|
||||
if url.port == None:
|
||||
if url.scheme == 'https':
|
||||
port = 443
|
||||
else:
|
||||
port = 80
|
||||
else:
|
||||
port = url.port
|
||||
|
||||
connect = asyncio.open_connection(url.hostname, port, ssl=ssl)
|
||||
reader, writer = yield from connect
|
||||
req = 'GET {path} HTTP/1.0\r\n\r\n'.format(path=url.path or '/')
|
||||
writer.write(req.encode('utf-8'))
|
||||
# skip response header fields
|
||||
while True:
|
||||
line = yield from reader.readline()
|
||||
line = line.rstrip()
|
||||
if not line:
|
||||
break
|
||||
# read body
|
||||
while True:
|
||||
b = yield from reader.read(4096)
|
||||
if not b:
|
||||
break
|
||||
handler.buf.write(b)
|
||||
writer.close()
|
||||
handler.buf.seek(0)
|
||||
handler.eof = True
|
||||
handler.resume()
|
||||
|
||||
class Body:
|
||||
def __init__(self, handler):
|
||||
self.handler = handler
|
||||
self.handler.eof = False
|
||||
self.handler.buf = io.BytesIO()
|
||||
|
||||
def generate(self, n):
|
||||
buf = self.handler.buf
|
||||
data = buf.read1(n)
|
||||
if not data and not self.handler.eof:
|
||||
return None, nghttp2.DATA_DEFERRED
|
||||
return data, nghttp2.DATA_EOF if self.handler.eof else nghttp2.DATA_OK
|
||||
|
||||
class Handler(nghttp2.BaseRequestHandler):
|
||||
|
||||
def on_headers(self):
|
||||
body = Body(self)
|
||||
asyncio.async(get_http_header(
|
||||
self, 'http://localhost' + self.path.decode('utf-8')))
|
||||
self.send_response(status=200, body=body.generate)
|
||||
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
|
||||
ctx.load_cert_chain('server.crt', 'server.key')
|
||||
|
||||
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
|
||||
server.serve_forever()
|
||||
|
||||
@@ -60,7 +60,10 @@ if ENABLE_ASIO_LIB
|
||||
|
||||
noinst_PROGRAMS += asio-sv asio-sv2 asio-cl asio-cl2
|
||||
|
||||
ASIOCPPFLAGS = ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
# AM_CPPFLAGS must be placed first, so that header file (e.g.,
|
||||
# nghttp2/nghttp2.h) in this package is used rather than installed
|
||||
# one.
|
||||
ASIOCPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
|
||||
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
|
||||
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
|
||||
$(top_builddir)/third-party/libhttp-parser.la \
|
||||
|
||||
@@ -258,8 +258,7 @@ static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
|
||||
stream), if it is closed, we send GOAWAY and tear down the
|
||||
session */
|
||||
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code,
|
||||
void *user_data) {
|
||||
uint32_t error_code, void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
int rv;
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ typedef enum {
|
||||
NGHTTP2_TOKEN__METHOD,
|
||||
NGHTTP2_TOKEN__PATH,
|
||||
NGHTTP2_TOKEN__SCHEME,
|
||||
NGHTTP2_TOKEN_HOST,
|
||||
NGHTTP2_TOKEN_HOST
|
||||
} nghttp2_token;
|
||||
|
||||
/* Inspired by h2o header lookup. https://github.com/h2o/h2o */
|
||||
@@ -658,19 +658,52 @@ static void stream_error(connection *conn, int32_t stream_id,
|
||||
error_code);
|
||||
}
|
||||
|
||||
static ssize_t fd_read_callback(nghttp2_session *session _U_,
|
||||
int32_t stream_id _U_, uint8_t *buf,
|
||||
size_t length, uint32_t *data_flags,
|
||||
nghttp2_data_source *source,
|
||||
void *user_data _U_) {
|
||||
static int send_data_callback(nghttp2_session *session _U_,
|
||||
nghttp2_frame *frame, const uint8_t *framehd,
|
||||
size_t length, nghttp2_data_source *source,
|
||||
void *user_data) {
|
||||
connection *conn = user_data;
|
||||
uint8_t *p = conn->buf.last;
|
||||
stream *strm = source->ptr;
|
||||
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) {
|
||||
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;
|
||||
if (nread == 0 || strm->fileleft == 0) {
|
||||
if (strm->fileleft != 0) {
|
||||
@@ -1274,6 +1307,8 @@ int main(int argc, char **argv) {
|
||||
shared_callbacks, on_stream_close_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||
shared_callbacks, on_frame_not_send_callback);
|
||||
nghttp2_session_callbacks_set_send_data_callback(shared_callbacks,
|
||||
send_data_callback);
|
||||
|
||||
rv = nghttp2_option_new(&shared_option);
|
||||
if (rv != 0) {
|
||||
|
||||
@@ -77,7 +77,7 @@ int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
print '''\
|
||||
case {}:'''.format(size)
|
||||
print '''\
|
||||
switch (name[namelen - 1]) {'''
|
||||
switch (name[{}]) {{'''.format(size - 1)
|
||||
for c in sorted(ents.keys()):
|
||||
headers = sorted(ents[c])
|
||||
print '''\
|
||||
|
||||
@@ -1,19 +1,72 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
HEADERS = [
|
||||
':authority',
|
||||
':method',
|
||||
':path',
|
||||
':scheme',
|
||||
':status',
|
||||
"content-length",
|
||||
"host",
|
||||
"te",
|
||||
'connection',
|
||||
'keep-alive',
|
||||
'proxy-connection',
|
||||
'transfer-encoding',
|
||||
'upgrade'
|
||||
(':authority', 0),
|
||||
(':method', 1),
|
||||
(':method', 2),
|
||||
(':path', 3),
|
||||
(':path', 4),
|
||||
(':scheme', 5),
|
||||
(':scheme', 6),
|
||||
(':status', 7),
|
||||
(':status', 8),
|
||||
(':status', 9),
|
||||
(':status', 10),
|
||||
(':status', 11),
|
||||
(':status', 12),
|
||||
(':status', 13),
|
||||
('accept-charset', 14),
|
||||
('accept-encoding', 15),
|
||||
('accept-language', 16),
|
||||
('accept-ranges', 17),
|
||||
('accept', 18),
|
||||
('access-control-allow-origin', 19),
|
||||
('age', 20),
|
||||
('allow', 21),
|
||||
('authorization', 22),
|
||||
('cache-control', 23),
|
||||
('content-disposition', 24),
|
||||
('content-encoding', 25),
|
||||
('content-language', 26),
|
||||
('content-length', 27),
|
||||
('content-location', 28),
|
||||
('content-range', 29),
|
||||
('content-type', 30),
|
||||
('cookie', 31),
|
||||
('date', 32),
|
||||
('etag', 33),
|
||||
('expect', 34),
|
||||
('expires', 35),
|
||||
('from', 36),
|
||||
('host', 37),
|
||||
('if-match', 38),
|
||||
('if-modified-since', 39),
|
||||
('if-none-match', 40),
|
||||
('if-range', 41),
|
||||
('if-unmodified-since', 42),
|
||||
('last-modified', 43),
|
||||
('link', 44),
|
||||
('location', 45),
|
||||
('max-forwards', 46),
|
||||
('proxy-authenticate', 47),
|
||||
('proxy-authorization', 48),
|
||||
('range', 49),
|
||||
('referer', 50),
|
||||
('refresh', 51),
|
||||
('retry-after', 52),
|
||||
('server', 53),
|
||||
('set-cookie', 54),
|
||||
('strict-transport-security', 55),
|
||||
('transfer-encoding', 56),
|
||||
('user-agent', 57),
|
||||
('vary', 58),
|
||||
('via', 59),
|
||||
('www-authenticate', 60),
|
||||
('te', None),
|
||||
('connection', None),
|
||||
('keep-alive',None),
|
||||
('proxy-connection', None),
|
||||
('upgrade', None),
|
||||
]
|
||||
|
||||
def to_enum_hd(k):
|
||||
@@ -27,7 +80,7 @@ def to_enum_hd(k):
|
||||
|
||||
def build_header(headers):
|
||||
res = {}
|
||||
for k in headers:
|
||||
for k, _ in headers:
|
||||
size = len(k)
|
||||
if size not in res:
|
||||
res[size] = {}
|
||||
@@ -40,18 +93,20 @@ def build_header(headers):
|
||||
return res
|
||||
|
||||
def gen_enum():
|
||||
print '''\
|
||||
typedef enum {'''
|
||||
for k in sorted(HEADERS):
|
||||
print '''\
|
||||
{},'''.format(to_enum_hd(k))
|
||||
print '''\
|
||||
NGHTTP2_TOKEN_MAXIDX,
|
||||
} nghttp2_token;'''
|
||||
name = ''
|
||||
print 'typedef enum {'
|
||||
for k, token in HEADERS:
|
||||
if token is None:
|
||||
print ' {},'.format(to_enum_hd(k))
|
||||
else:
|
||||
if name != k:
|
||||
name = k
|
||||
print ' {} = {},'.format(to_enum_hd(k), token)
|
||||
print '} nghttp2_token;'
|
||||
|
||||
def gen_index_header():
|
||||
print '''\
|
||||
static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
static inline int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
switch (namelen) {'''
|
||||
b = build_header(HEADERS)
|
||||
for size in sorted(b.keys()):
|
||||
@@ -59,14 +114,14 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
print '''\
|
||||
case {}:'''.format(size)
|
||||
print '''\
|
||||
switch (name[namelen - 1]) {'''
|
||||
switch (name[{}]) {{'''.format(size - 1)
|
||||
for c in sorted(ents.keys()):
|
||||
headers = sorted(ents[c])
|
||||
print '''\
|
||||
case '{}':'''.format(c)
|
||||
for k in headers:
|
||||
print '''\
|
||||
if (streq("{}", name, {})) {{
|
||||
if (lstreq("{}", name, {})) {{
|
||||
return {};
|
||||
}}'''.format(k[:-1], size - 1, to_enum_hd(k))
|
||||
print '''\
|
||||
|
||||
11
help2rst.py
11
help2rst.py
@@ -61,6 +61,8 @@ def help2man(infile):
|
||||
description.append(line)
|
||||
|
||||
print '''
|
||||
.. program:: {cmdname}
|
||||
|
||||
{cmdname}(1)
|
||||
{cmdnameunderline}
|
||||
|
||||
@@ -78,6 +80,7 @@ DESCRIPTION
|
||||
synopsis=synopsis, description=format_text('\n'.join(description)))
|
||||
|
||||
in_arg = False
|
||||
in_footer = False
|
||||
|
||||
for line in infile:
|
||||
line = line.rstrip()
|
||||
@@ -95,6 +98,14 @@ DESCRIPTION
|
||||
print ''
|
||||
in_arg = False
|
||||
|
||||
if line == '--':
|
||||
in_footer = True
|
||||
continue
|
||||
|
||||
if in_footer:
|
||||
print line.strip()
|
||||
continue
|
||||
|
||||
if line == 'Options:':
|
||||
print 'OPTIONS'
|
||||
print '-------'
|
||||
|
||||
2
integration-tests/.gitignore
vendored
Normal file
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
|
||||
// connection attempt to HTTP/2 backend failed.
|
||||
func TestH1H2ConnectFailure(t *testing.T) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
@@ -494,7 +495,9 @@ func TestH2H1SNI(t *testing.T) {
|
||||
func TestH2H1ServerPush(t *testing.T) {
|
||||
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
||||
// only resources marked as rel=preload are pushed
|
||||
if !strings.HasPrefix(r.URL.Path, "/css/") {
|
||||
w.Header().Add("Link", "</css/main.css>; rel=preload, </foo>, </css/theme.css>; rel=preload")
|
||||
}
|
||||
})
|
||||
defer st.Close()
|
||||
|
||||
@@ -555,6 +558,79 @@ func TestH2H1RequestTrailer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestH2H1HeaderFieldBuffer tests that request with header fields
|
||||
// larger than configured buffer size is rejected.
|
||||
func TestH2H1HeaderFieldBuffer(t *testing.T) {
|
||||
st := newServerTester([]string{"--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Fatal("execution path should not be here")
|
||||
})
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http2(requestParam{
|
||||
name: "TestH2H1HeaderFieldBuffer",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http2() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 431; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH2H1HeaderFields tests that request with header fields more
|
||||
// than configured number is rejected.
|
||||
func TestH2H1HeaderFields(t *testing.T) {
|
||||
st := newServerTester([]string{"--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Fatal("execution path should not be here")
|
||||
})
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http2(requestParam{
|
||||
name: "TestH2H1HeaderFields",
|
||||
// we have at least 4 pseudo-header fields sent, and
|
||||
// that ensures that buffer limit exceeds.
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http2() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 431; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH2H1Upgrade tests HTTP Upgrade to HTTP/2
|
||||
func TestH2H1Upgrade(t *testing.T) {
|
||||
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {})
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http1(requestParam{
|
||||
name: "TestH2H1Upgrade",
|
||||
header: []hpack.HeaderField{
|
||||
pair("Connection", "Upgrade, HTTP2-Settings"),
|
||||
pair("Upgrade", "h2c-14"),
|
||||
pair("HTTP2-Settings", "AAMAAABkAAQAAP__"),
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 101; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
|
||||
res, err = st.http2(requestParam{
|
||||
httpUpgrade: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http2() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH2H1GracefulShutdown tests graceful shutdown.
|
||||
func TestH2H1GracefulShutdown(t *testing.T) {
|
||||
st := newServerTester(nil, t, noopHandler)
|
||||
|
||||
@@ -170,6 +170,46 @@ func TestS3H1NoVia(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestS3H1HeaderFieldBuffer tests that request with header fields
|
||||
// larger than configured buffer size is rejected.
|
||||
func TestS3H1HeaderFieldBuffer(t *testing.T) {
|
||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Fatal("execution path should not be here")
|
||||
})
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.spdy(requestParam{
|
||||
name: "TestS3H1HeaderFieldBuffer",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.spdy() = %v", err)
|
||||
}
|
||||
if got, want := res.spdyRstErrCode, spdy.InternalError; got != want {
|
||||
t.Errorf("res.spdyRstErrCode: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestS3H1HeaderFields tests that request with header fields more
|
||||
// than configured number is rejected.
|
||||
func TestS3H1HeaderFields(t *testing.T) {
|
||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Fatal("execution path should not be here")
|
||||
})
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.spdy(requestParam{
|
||||
name: "TestS3H1HeaderFields",
|
||||
// we have at least 5 pseudo-header fields sent, and
|
||||
// that ensures that buffer limit exceeds.
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.spdy() = %v", err)
|
||||
}
|
||||
if got, want := res.spdyRstErrCode, spdy.InternalError; got != want {
|
||||
t.Errorf("res.spdyRstErrCode: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestS3H2ConnectFailure tests that server handles the situation that
|
||||
// connection attempt to HTTP/2 backend failed.
|
||||
func TestS3H2ConnectFailure(t *testing.T) {
|
||||
|
||||
@@ -256,6 +256,7 @@ type requestParam struct {
|
||||
header []hpack.HeaderField // additional request header fields
|
||||
body []byte // request body
|
||||
trailer []hpack.HeaderField // trailer part
|
||||
httpUpgrade bool // true if upgraded to HTTP/2 through HTTP Upgrade
|
||||
}
|
||||
|
||||
// wrapper for request body to set trailer part
|
||||
@@ -296,7 +297,19 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
|
||||
body = cbr
|
||||
}
|
||||
}
|
||||
req, err := http.NewRequest(method, st.url, body)
|
||||
|
||||
reqURL := st.url
|
||||
|
||||
if rp.path != "" {
|
||||
u, err := url.Parse(st.url)
|
||||
if err != nil {
|
||||
st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err)
|
||||
}
|
||||
u.Path = rp.path
|
||||
reqURL = u.String()
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, reqURL, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -478,6 +491,7 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
|
||||
streams := make(map[uint32]*serverResponse)
|
||||
streams[id] = res
|
||||
|
||||
if !rp.httpUpgrade {
|
||||
method := "GET"
|
||||
if rp.method != "" {
|
||||
method = rp.method
|
||||
@@ -540,7 +554,7 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
loop:
|
||||
for {
|
||||
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.
|
||||
#
|
||||
# By G. Vanem <gvanem@yahoo.no> 2013
|
||||
# Updated 3/2015 by Remo Eichenberger @remoe
|
||||
# The MIT License apply.
|
||||
#
|
||||
|
||||
#
|
||||
# Choose your weapons:
|
||||
# Set 'ZLIB_ROOT' to the root of zlib.
|
||||
# Set 'USE_CYTHON=1' to build and install the 'nghttp2.pyd' Python extension.
|
||||
#
|
||||
ZLIB_ROOT = g:/MingW32/src/Compression/zlib-1.2.8
|
||||
USE_CYTHON = 1
|
||||
|
||||
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV], //g')
|
||||
@@ -38,7 +37,7 @@ INSTALL_HDR = $(VC_ROOT)/include
|
||||
TARGETS = nghttp2.lib nghttp2.dll nghttp2_imp.lib \
|
||||
nghttp2d.lib nghttp2d.dll nghttp2d_imp.lib
|
||||
|
||||
EXT_LIBS = $(ZLIB_ROOT)/zlib.lib ws2_32.lib
|
||||
EXT_LIBS =
|
||||
|
||||
OBJ_DIR = MSVC_obj
|
||||
|
||||
@@ -46,32 +45,34 @@ NGHTTP2_PDB_R = $(OBJ_DIR)/nghttp2.pdb
|
||||
NGHTTP2_PDB_D = $(OBJ_DIR)/nghttp2d.pdb
|
||||
|
||||
CC = cl
|
||||
CFLAGS = -I./includes -I$(ZLIB_ROOT) -DHAVE_WINSOCK2_H -Dssize_t=long
|
||||
CFLAGS = -I./includes -Dssize_t=long -D_U_=""
|
||||
|
||||
CFLAGS_R = -nologo -MD -W3 -Zi -Fd./$(NGHTTP2_PDB_R)
|
||||
CFLAGS_D = -nologo -MDd -W3 -Zi -Fd./$(NGHTTP2_PDB_D) \
|
||||
-Ot -D_DEBUG -GF -RTCs -RTCu # -RTCc -GS
|
||||
|
||||
LDFLAGS = -nologo -machine:i386 -map -debug -incremental:no # -verbose
|
||||
LDFLAGS = -nologo -machine:x64 -map -debug -incremental:no # -verbose
|
||||
|
||||
NGHTTP2_SRC = nghttp2_buf.c \
|
||||
nghttp2_callbacks.c \
|
||||
NGHTTP2_SRC = nghttp2_pq.c \
|
||||
nghttp2_map.c \
|
||||
nghttp2_queue.c \
|
||||
nghttp2_frame.c \
|
||||
nghttp2_buf.c \
|
||||
nghttp2_stream.c \
|
||||
nghttp2_outbound_item.c \
|
||||
nghttp2_session.c \
|
||||
nghttp2_submit.c \
|
||||
nghttp2_helper.c \
|
||||
nghttp2_npn.c \
|
||||
nghttp2_hd.c \
|
||||
nghttp2_hd_huffman.c \
|
||||
nghttp2_hd_huffman_data.c \
|
||||
nghttp2_map.c \
|
||||
nghttp2_npn.c \
|
||||
nghttp2_option.c \
|
||||
nghttp2_outbound_item.c \
|
||||
nghttp2_version.c \
|
||||
nghttp2_priority_spec.c \
|
||||
nghttp2_pq.c \
|
||||
nghttp2_queue.c \
|
||||
nghttp2_session.c \
|
||||
nghttp2_stream.c \
|
||||
nghttp2_submit.c \
|
||||
nghttp2_version.c
|
||||
nghttp2_option.c \
|
||||
nghttp2_callbacks.c \
|
||||
nghttp2_mem.c \
|
||||
nghttp2_http.c
|
||||
|
||||
NGHTTP2_OBJ_R = $(addprefix $(OBJ_DIR)/r_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
||||
NGHTTP2_OBJ_D = $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
||||
@@ -116,13 +117,13 @@ nghttp2d.lib: $(NGHTTP2_OBJ_D)
|
||||
lib -nologo -out:$@ $^
|
||||
@echo
|
||||
|
||||
nghttp2.dll nghttp2_imp.lib: $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(OBJ_DIR)/r_nghttp2.def
|
||||
link $(LDFLAGS) -dll -out:nghttp2.dll -implib:nghttp2_imp.lib -def:$(OBJ_DIR)/r_nghttp2.def \
|
||||
nghttp2.dll nghttp2_imp.lib: $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res
|
||||
link $(LDFLAGS) -dll -out:nghttp2.dll -implib:nghttp2_imp.lib \
|
||||
$(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(EXT_LIBS)
|
||||
@echo
|
||||
|
||||
nghttp2d.dll nghttp2d_imp.lib: $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(OBJ_DIR)/d_nghttp2.def
|
||||
link $(LDFLAGS) -dll -out:nghttp2d.dll -implib:nghttp2d_imp.lib -def:$(OBJ_DIR)/d_nghttp2.def \
|
||||
nghttp2d.dll nghttp2d_imp.lib: $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res
|
||||
link $(LDFLAGS) -dll -out:nghttp2d.dll -implib:nghttp2d_imp.lib \
|
||||
$(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(EXT_LIBS)
|
||||
@echo
|
||||
|
||||
@@ -219,24 +220,6 @@ nghttp2.rc: Makefile.MSVC
|
||||
@echo ' */' >> $@
|
||||
@echo "$$RES_FILE" >> $@
|
||||
|
||||
$(OBJ_DIR)/r_nghttp2.def: Makefile.MSVC
|
||||
@echo 'Generating $@...'
|
||||
@echo '; $(GENERATED). DO NOT EDIT.' > $@
|
||||
@echo ';' >> $@
|
||||
@echo 'LIBRARY nghttp2.dll' >> $@
|
||||
@echo 'EXPORTS' >> $@
|
||||
nm $(NGHTTP2_OBJ_R) | grep ' T .*_nghttp2' | sed 's/^.* _/ /' >> $@
|
||||
@echo 'NGHTTP2_STATIC_TABLE_LENGTH DATA' >> $@
|
||||
|
||||
$(OBJ_DIR)/d_nghttp2.def: Makefile.MSVC
|
||||
@echo 'Generating $@...'
|
||||
@echo '; $(GENERATED). DO NOT EDIT.' > $@
|
||||
@echo ';' >> $@
|
||||
@echo 'LIBRARY nghttp2d.dll' >> $@
|
||||
@echo 'EXPORTS' >> $@
|
||||
nm $(NGHTTP2_OBJ_D) | grep ' T .*_nghttp2' | sed 's/^.* _/ /' >> $@
|
||||
@echo 'NGHTTP2_STATIC_TABLE_LENGTH DATA' >> $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ_DIR)/* nghttp2_imp.exp nghttp2_imp.exp \
|
||||
nghttp2.map nghttp2d.map nghttp2.rc includes/nghttp2/nghttp2ver.h
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
if (len == 0) {
|
||||
res = NULL;
|
||||
} else {
|
||||
res = nghttp2_mem_malloc(bufs->mem, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = nghttp2_mem_malloc(bufs->mem, len);
|
||||
if (res == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_buf_wrap_init(&resbuf, res, len);
|
||||
|
||||
for (chain = bufs->head; chain; chain = chain->next) {
|
||||
buf = &chain->buf;
|
||||
|
||||
if (resbuf.last) {
|
||||
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
|
||||
}
|
||||
|
||||
nghttp2_buf_reset(buf);
|
||||
nghttp2_buf_shift_right(&chain->buf, bufs->offset);
|
||||
}
|
||||
|
||||
bufs->cur = bufs->head;
|
||||
|
||||
*out = res;
|
||||
|
||||
return (ssize_t)len;
|
||||
}
|
||||
|
||||
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) {
|
||||
size_t len;
|
||||
nghttp2_buf_chain *chain;
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_buf resbuf;
|
||||
|
||||
len = nghttp2_bufs_len(bufs);
|
||||
|
||||
nghttp2_buf_wrap_init(&resbuf, out, len);
|
||||
|
||||
for (chain = bufs->head; chain; chain = chain->next) {
|
||||
buf = &chain->buf;
|
||||
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *chain, *ci;
|
||||
size_t k;
|
||||
|
||||
@@ -313,9 +313,8 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
|
||||
* function allocates the contagious memory to store all data in
|
||||
* |bufs| and assigns it to |*out|.
|
||||
*
|
||||
* On successful return, nghttp2_bufs_len(bufs) returns 0, just like
|
||||
* after calling nghttp2_bufs_reset().
|
||||
|
||||
* The contents of |bufs| is left unchanged.
|
||||
*
|
||||
* This function returns the length of copied data and assigns the
|
||||
* pointer to copied data to |*out| if it succeeds, or one of the
|
||||
* following negative error codes:
|
||||
@@ -325,6 +324,17 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
|
||||
*/
|
||||
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
|
||||
|
||||
/*
|
||||
* Copies all data stored in |bufs| to |out|. This function assumes
|
||||
* that the buffer space pointed by |out| has at least
|
||||
* nghttp2_bufs(bufs) bytes.
|
||||
*
|
||||
* The contents of |bufs| is left unchanged.
|
||||
*
|
||||
* This function returns the length of copied data.
|
||||
*/
|
||||
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out);
|
||||
|
||||
/*
|
||||
* Resets |bufs| and makes the buffers empty.
|
||||
*/
|
||||
|
||||
@@ -121,3 +121,9 @@ void nghttp2_session_callbacks_set_on_begin_frame_callback(
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback) {
|
||||
cbs->on_begin_frame_callback = on_begin_frame_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_send_data_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_send_data_callback send_data_callback) {
|
||||
cbs->send_data_callback = send_data_callback;
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ struct nghttp2_session_callbacks {
|
||||
* Sets callback function invoked when a frame header is received.
|
||||
*/
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback;
|
||||
nghttp2_send_data_callback send_data_callback;
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_CALLBACKS_H */
|
||||
|
||||
@@ -739,7 +739,8 @@ int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
|
||||
nghttp2_nv *p;
|
||||
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
buflen += nva[i].namelen + nva[i].valuelen;
|
||||
/* + 2 for null-termination */
|
||||
buflen += nva[i].namelen + nva[i].valuelen + 2;
|
||||
}
|
||||
|
||||
if (nvlen == 0) {
|
||||
@@ -765,12 +766,14 @@ int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
|
||||
memcpy(data, nva[i].name, nva[i].namelen);
|
||||
p->name = data;
|
||||
p->namelen = nva[i].namelen;
|
||||
data[p->namelen] = '\0';
|
||||
nghttp2_downcase(p->name, p->namelen);
|
||||
data += nva[i].namelen;
|
||||
data += nva[i].namelen + 1;
|
||||
memcpy(data, nva[i].value, nva[i].valuelen);
|
||||
p->value = data;
|
||||
p->valuelen = nva[i].valuelen;
|
||||
data += nva[i].valuelen;
|
||||
data[p->valuelen] = '\0';
|
||||
data += nva[i].valuelen + 1;
|
||||
++p;
|
||||
}
|
||||
return 0;
|
||||
@@ -810,7 +813,7 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
|
||||
static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) {
|
||||
size_t trail_padlen;
|
||||
size_t newlen;
|
||||
|
||||
@@ -825,6 +828,10 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
|
||||
newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen;
|
||||
nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3]));
|
||||
|
||||
if (framehd_only) {
|
||||
return;
|
||||
}
|
||||
|
||||
trail_padlen = padlen - 1;
|
||||
buf->pos[NGHTTP2_FRAME_HDLEN] = trail_padlen;
|
||||
|
||||
@@ -833,12 +840,10 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
|
||||
/* extend buffers trail_padlen bytes, since we ate previous padlen -
|
||||
trail_padlen byte(s) */
|
||||
buf->last += trail_padlen;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
size_t padlen) {
|
||||
size_t padlen, int framehd_only) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
if (padlen == 0) {
|
||||
@@ -871,7 +876,7 @@ int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
|
||||
assert(nghttp2_buf_avail(buf) >= (ssize_t)padlen - 1);
|
||||
|
||||
frame_set_pad(buf, padlen);
|
||||
frame_set_pad(buf, padlen, framehd_only);
|
||||
|
||||
hd->length += padlen;
|
||||
hd->flags |= NGHTTP2_FLAG_PADDED;
|
||||
|
||||
@@ -471,7 +471,9 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
|
||||
/*
|
||||
* Copies name/value pairs from |nva|, which contains |nvlen| pairs,
|
||||
* to |*nva_ptr|, which is dynamically allocated so that all items can
|
||||
* be stored.
|
||||
* be stored. The resultant name and value in nghttp2_nv are
|
||||
* guaranteed to be NULL-terminated even if the input is not
|
||||
* null-terminated.
|
||||
*
|
||||
* The |*nva_ptr| must be freed using nghttp2_nv_array_del().
|
||||
*
|
||||
@@ -508,7 +510,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
|
||||
* Sets Pad Length field and flags and adjusts frame header position
|
||||
* of each buffers in |bufs|. The number of padding is given in the
|
||||
* |padlen| including Pad Length field. The |hd| is the frame header
|
||||
* for the serialized data.
|
||||
* for the serialized data. This function fills zeros padding region
|
||||
* unless framehd_only is nonzero.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
@@ -519,6 +522,6 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
|
||||
* The length of the resulting frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
size_t padlen);
|
||||
size_t padlen, int framehd_only);
|
||||
|
||||
#endif /* NGHTTP2_FRAME_H */
|
||||
|
||||
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)
|
||||
|
||||
/* Exported for unit test */
|
||||
extern const size_t NGHTTP2_STATIC_TABLE_LENGTH;
|
||||
#define NGHTTP2_STATIC_TABLE_LENGTH 61
|
||||
|
||||
/* Generated by genlibtokenlookup.py */
|
||||
typedef enum {
|
||||
NGHTTP2_TOKEN__AUTHORITY = 0,
|
||||
NGHTTP2_TOKEN__METHOD = 1,
|
||||
NGHTTP2_TOKEN__PATH = 3,
|
||||
NGHTTP2_TOKEN__SCHEME = 5,
|
||||
NGHTTP2_TOKEN__STATUS = 7,
|
||||
NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
|
||||
NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
|
||||
NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
|
||||
NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
|
||||
NGHTTP2_TOKEN_ACCEPT = 18,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
|
||||
NGHTTP2_TOKEN_AGE = 20,
|
||||
NGHTTP2_TOKEN_ALLOW = 21,
|
||||
NGHTTP2_TOKEN_AUTHORIZATION = 22,
|
||||
NGHTTP2_TOKEN_CACHE_CONTROL = 23,
|
||||
NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
|
||||
NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
|
||||
NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
|
||||
NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
|
||||
NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
|
||||
NGHTTP2_TOKEN_CONTENT_RANGE = 29,
|
||||
NGHTTP2_TOKEN_CONTENT_TYPE = 30,
|
||||
NGHTTP2_TOKEN_COOKIE = 31,
|
||||
NGHTTP2_TOKEN_DATE = 32,
|
||||
NGHTTP2_TOKEN_ETAG = 33,
|
||||
NGHTTP2_TOKEN_EXPECT = 34,
|
||||
NGHTTP2_TOKEN_EXPIRES = 35,
|
||||
NGHTTP2_TOKEN_FROM = 36,
|
||||
NGHTTP2_TOKEN_HOST = 37,
|
||||
NGHTTP2_TOKEN_IF_MATCH = 38,
|
||||
NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
|
||||
NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
|
||||
NGHTTP2_TOKEN_IF_RANGE = 41,
|
||||
NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
|
||||
NGHTTP2_TOKEN_LAST_MODIFIED = 43,
|
||||
NGHTTP2_TOKEN_LINK = 44,
|
||||
NGHTTP2_TOKEN_LOCATION = 45,
|
||||
NGHTTP2_TOKEN_MAX_FORWARDS = 46,
|
||||
NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
|
||||
NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
|
||||
NGHTTP2_TOKEN_RANGE = 49,
|
||||
NGHTTP2_TOKEN_REFERER = 50,
|
||||
NGHTTP2_TOKEN_REFRESH = 51,
|
||||
NGHTTP2_TOKEN_RETRY_AFTER = 52,
|
||||
NGHTTP2_TOKEN_SERVER = 53,
|
||||
NGHTTP2_TOKEN_SET_COOKIE = 54,
|
||||
NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
|
||||
NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
|
||||
NGHTTP2_TOKEN_USER_AGENT = 57,
|
||||
NGHTTP2_TOKEN_VARY = 58,
|
||||
NGHTTP2_TOKEN_VIA = 59,
|
||||
NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
|
||||
NGHTTP2_TOKEN_TE,
|
||||
NGHTTP2_TOKEN_CONNECTION,
|
||||
NGHTTP2_TOKEN_KEEP_ALIVE,
|
||||
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
||||
NGHTTP2_TOKEN_UPGRADE
|
||||
} nghttp2_token;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_FLAG_NONE = 0,
|
||||
@@ -67,18 +128,14 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
nghttp2_nv nv;
|
||||
uint32_t name_hash;
|
||||
uint32_t value_hash;
|
||||
/* nghttp2_token value for nv.name. It could be -1 if we have no
|
||||
token for that header field name. */
|
||||
int token;
|
||||
/* Reference count */
|
||||
uint8_t ref;
|
||||
uint8_t flags;
|
||||
} nghttp2_hd_entry;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_hd_entry ent;
|
||||
size_t index;
|
||||
} nghttp2_hd_static_entry;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_hd_entry **buffer;
|
||||
size_t mask;
|
||||
@@ -107,6 +164,12 @@ typedef enum {
|
||||
NGHTTP2_HD_STATE_READ_VALUE
|
||||
} nghttp2_hd_inflate_state;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_WITH_INDEXING,
|
||||
NGHTTP2_HD_WITHOUT_INDEXING,
|
||||
NGHTTP2_HD_NEVER_INDEXING
|
||||
} nghttp2_hd_indexing_mode;
|
||||
|
||||
typedef struct {
|
||||
/* dynamic header table */
|
||||
nghttp2_hd_ringbuf hd_table;
|
||||
@@ -176,9 +239,8 @@ struct nghttp2_hd_inflater {
|
||||
* set in the |flags|, the content pointed by the |name| with length
|
||||
* |namelen| is copied. Likewise, if NGHTTP2_HD_FLAG_VALUE_ALLOC bit
|
||||
* set in the |flags|, the content pointed by the |value| with length
|
||||
* |valuelen| is copied. The |name_hash| and |value_hash| are hash
|
||||
* value for |name| and |value| respectively. The hash function is
|
||||
* defined in nghttp2_hd.c.
|
||||
* |valuelen| is copied. The |token| is enum number looked up by
|
||||
* |name|. It could be -1 if we don't have that enum value.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
@@ -188,8 +250,7 @@ struct nghttp2_hd_inflater {
|
||||
*/
|
||||
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
|
||||
size_t namelen, uint8_t *value, size_t valuelen,
|
||||
uint32_t name_hash, uint32_t value_hash,
|
||||
nghttp2_mem *mem);
|
||||
int token, nghttp2_mem *mem);
|
||||
|
||||
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent, nghttp2_mem *mem);
|
||||
|
||||
@@ -271,13 +332,25 @@ int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
|
||||
*/
|
||||
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
|
||||
|
||||
/*
|
||||
* Similar to nghttp2_hd_inflate_hd(), but this takes additional
|
||||
* output parameter |token|. On successful header emission, it
|
||||
* contains nghttp2_token value for nv_out->name. It could be -1 if
|
||||
* we don't have enum value for the name. Other than that return
|
||||
* values and semantics are the same as nghttp2_hd_inflate_hd().
|
||||
*/
|
||||
ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_nv *nv_out, int *inflate_flags,
|
||||
int *token, uint8_t *in, size_t inlen,
|
||||
int in_final);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
|
||||
nghttp2_nv *nv, int inc_indexing);
|
||||
nghttp2_nv *nv, int indexing_mode);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
||||
int inc_indexing);
|
||||
int indexing_mode);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
|
||||
@@ -324,8 +397,7 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
|
||||
* be initialized by nghttp2_hd_huff_decode_context_init(). The result
|
||||
* will be added to |dest|. This function may expand |dest| as
|
||||
* needed. The caller is responsible to release the memory of |dest|
|
||||
* by calling nghttp2_bufs_free() or export its content using
|
||||
* nghttp2_bufs_remove().
|
||||
* by calling nghttp2_bufs_free().
|
||||
*
|
||||
* The caller must set the |final| to nonzero if the given input is
|
||||
* the final block.
|
||||
|
||||
@@ -168,10 +168,27 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
|
||||
ctx->accept = 1;
|
||||
}
|
||||
|
||||
/* Use macro to make the code simpler..., but error case is tricky.
|
||||
We spent most of the CPU in decoding, so we are doing this
|
||||
thing. */
|
||||
#define hd_huff_decode_sym_emit(bufs, sym, avail) \
|
||||
do { \
|
||||
if ((avail)) { \
|
||||
nghttp2_bufs_fast_addb((bufs), (sym)); \
|
||||
--(avail); \
|
||||
} else { \
|
||||
rv = nghttp2_bufs_addb((bufs), (sym)); \
|
||||
if (rv != 0) { \
|
||||
return rv; \
|
||||
} \
|
||||
(avail) = nghttp2_bufs_cur_avail((bufs)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
nghttp2_bufs *bufs, const uint8_t *src,
|
||||
size_t srclen, int final) {
|
||||
size_t i, j;
|
||||
size_t i;
|
||||
int rv;
|
||||
size_t avail;
|
||||
|
||||
@@ -180,30 +197,28 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
/* We use the decoding algorithm described in
|
||||
http://graphics.ics.uci.edu/pub/Prefix.pdf */
|
||||
for (i = 0; i < srclen; ++i) {
|
||||
uint8_t in = src[i] >> 4;
|
||||
for (j = 0; j < 2; ++j) {
|
||||
const nghttp2_huff_decode *t;
|
||||
|
||||
t = &huff_decode_table[ctx->state][in];
|
||||
t = &huff_decode_table[ctx->state][src[i] >> 4];
|
||||
if (t->flags & NGHTTP2_HUFF_FAIL) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
if (t->flags & NGHTTP2_HUFF_SYM) {
|
||||
if (avail) {
|
||||
nghttp2_bufs_fast_addb(bufs, t->sym);
|
||||
--avail;
|
||||
} else {
|
||||
rv = nghttp2_bufs_addb(bufs, t->sym);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
/* this is macro, and may return from this function on error */
|
||||
hd_huff_decode_sym_emit(bufs, t->sym, avail);
|
||||
}
|
||||
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->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
|
||||
in = src[i] & 0xf;
|
||||
}
|
||||
}
|
||||
if (final && !ctx->accept) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
|
||||
@@ -29,12 +29,16 @@
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
|
||||
|
||||
#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
|
||||
|
||||
/*
|
||||
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
|
||||
* network byte order.
|
||||
|
||||
@@ -28,11 +28,8 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int memeq(const void *a, const void *b, size_t n) {
|
||||
return memcmp(a, b, n) == 0;
|
||||
}
|
||||
|
||||
#define streq(A, B, N) ((sizeof((A)) - 1) == (N) && memeq((A), (B), (N)))
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
static char downcase(char c) {
|
||||
return 'A' <= c && c <= 'Z' ? (c - 'A' + 'a') : c;
|
||||
@@ -50,129 +47,7 @@ static int memieq(const void *a, const void *b, size_t n) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define strieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_TOKEN__AUTHORITY,
|
||||
NGHTTP2_TOKEN__METHOD,
|
||||
NGHTTP2_TOKEN__PATH,
|
||||
NGHTTP2_TOKEN__SCHEME,
|
||||
NGHTTP2_TOKEN__STATUS,
|
||||
NGHTTP2_TOKEN_CONNECTION,
|
||||
NGHTTP2_TOKEN_CONTENT_LENGTH,
|
||||
NGHTTP2_TOKEN_HOST,
|
||||
NGHTTP2_TOKEN_KEEP_ALIVE,
|
||||
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
||||
NGHTTP2_TOKEN_TE,
|
||||
NGHTTP2_TOKEN_TRANSFER_ENCODING,
|
||||
NGHTTP2_TOKEN_UPGRADE,
|
||||
NGHTTP2_TOKEN_MAXIDX,
|
||||
} nghttp2_token;
|
||||
|
||||
/*
|
||||
* This function was generated by genlibtokenlookup.py. Inspired by
|
||||
* h2o header lookup. https://github.com/h2o/h2o
|
||||
*/
|
||||
static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
switch (namelen) {
|
||||
case 2:
|
||||
switch (name[namelen - 1]) {
|
||||
case 'e':
|
||||
if (streq("t", name, 1)) {
|
||||
return NGHTTP2_TOKEN_TE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (name[namelen - 1]) {
|
||||
case 't':
|
||||
if (streq("hos", name, 3)) {
|
||||
return NGHTTP2_TOKEN_HOST;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch (name[namelen - 1]) {
|
||||
case 'h':
|
||||
if (streq(":pat", name, 4)) {
|
||||
return NGHTTP2_TOKEN__PATH;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
switch (name[namelen - 1]) {
|
||||
case 'd':
|
||||
if (streq(":metho", name, 6)) {
|
||||
return NGHTTP2_TOKEN__METHOD;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if (streq(":schem", name, 6)) {
|
||||
return NGHTTP2_TOKEN__SCHEME;
|
||||
}
|
||||
if (streq("upgrad", name, 6)) {
|
||||
return NGHTTP2_TOKEN_UPGRADE;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (streq(":statu", name, 6)) {
|
||||
return NGHTTP2_TOKEN__STATUS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
switch (name[namelen - 1]) {
|
||||
case 'e':
|
||||
if (streq("keep-aliv", name, 9)) {
|
||||
return NGHTTP2_TOKEN_KEEP_ALIVE;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (streq("connectio", name, 9)) {
|
||||
return NGHTTP2_TOKEN_CONNECTION;
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (streq(":authorit", name, 9)) {
|
||||
return NGHTTP2_TOKEN__AUTHORITY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 14:
|
||||
switch (name[namelen - 1]) {
|
||||
case 'h':
|
||||
if (streq("content-lengt", name, 13)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_LENGTH;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
switch (name[namelen - 1]) {
|
||||
case 'n':
|
||||
if (streq("proxy-connectio", name, 15)) {
|
||||
return NGHTTP2_TOKEN_PROXY_CONNECTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 17:
|
||||
switch (name[namelen - 1]) {
|
||||
case 'g':
|
||||
if (streq("transfer-encodin", name, 16)) {
|
||||
return NGHTTP2_TOKEN_TRANSFER_ENCODING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
|
||||
|
||||
static int64_t parse_uint(const uint8_t *s, size_t len) {
|
||||
int64_t n = 0;
|
||||
@@ -225,10 +100,20 @@ static int expect_response_body(nghttp2_stream *stream) {
|
||||
stream->status_code != 204;
|
||||
}
|
||||
|
||||
static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
int trailer) {
|
||||
int token;
|
||||
/* For "http" or "https" URIs, OPTIONS request may have "*" in :path
|
||||
header field to represent system-wide OPTIONS request. Otherwise,
|
||||
:path header field value must start with "/". This function must
|
||||
be called after ":method" header field was received. This function
|
||||
returns nonzero if path is valid.*/
|
||||
static int check_path(nghttp2_stream *stream) {
|
||||
return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 ||
|
||||
((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) ||
|
||||
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) &&
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK)));
|
||||
}
|
||||
|
||||
static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
int token, int trailer) {
|
||||
if (nv->name[0] == ':') {
|
||||
if (trailer ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||
@@ -236,8 +121,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
}
|
||||
}
|
||||
|
||||
token = lookup_token(nv->name, nv->namelen);
|
||||
|
||||
switch (token) {
|
||||
case NGHTTP2_TOKEN__AUTHORITY:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
|
||||
@@ -248,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)) {
|
||||
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;
|
||||
} 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) {
|
||||
/* we won't allow CONNECT for push */
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
@@ -262,6 +152,15 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
}
|
||||
}
|
||||
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:
|
||||
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
|
||||
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)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if (nv->value[0] == '/') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR;
|
||||
} else if (nv->valuelen == 1 && nv->value[0] == '*') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN__SCHEME:
|
||||
if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
|
||||
@@ -277,6 +181,10 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if ((nv->valuelen == 4 && memieq("http", nv->value, 4)) ||
|
||||
(nv->valuelen == 5 && memieq("https", nv->value, 5))) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN_HOST:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
|
||||
@@ -301,7 +209,7 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
case NGHTTP2_TOKEN_UPGRADE:
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
case NGHTTP2_TOKEN_TE:
|
||||
if (!strieq("trailers", nv->value, nv->valuelen)) {
|
||||
if (!lstrieq("trailers", nv->value, nv->valuelen)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
@@ -319,9 +227,7 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
}
|
||||
|
||||
static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
int trailer) {
|
||||
int token;
|
||||
|
||||
int token, int trailer) {
|
||||
if (nv->name[0] == ':') {
|
||||
if (trailer ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||
@@ -329,8 +235,6 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
}
|
||||
}
|
||||
|
||||
token = lookup_token(nv->name, nv->namelen);
|
||||
|
||||
switch (token) {
|
||||
case NGHTTP2_TOKEN__STATUS: {
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
|
||||
@@ -363,7 +267,7 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
case NGHTTP2_TOKEN_UPGRADE:
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
case NGHTTP2_TOKEN_TE:
|
||||
if (!strieq("trailers", nv->value, nv->valuelen)) {
|
||||
if (!lstrieq("trailers", nv->value, nv->valuelen)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
@@ -381,7 +285,8 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_nv *nv,
|
||||
}
|
||||
|
||||
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||
nghttp2_frame *frame, nghttp2_nv *nv, int trailer) {
|
||||
nghttp2_frame *frame, nghttp2_nv *nv, int token,
|
||||
int trailer) {
|
||||
/* We are strict for pseudo header field. One bad character should
|
||||
lead to fail. OTOH, we should be a bit forgiving for regular
|
||||
headers, since existing public internet has so much illegal
|
||||
@@ -421,10 +326,10 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||
}
|
||||
|
||||
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
||||
return http_request_on_header(stream, nv, trailer);
|
||||
return http_request_on_header(stream, nv, token, trailer);
|
||||
}
|
||||
|
||||
return http_response_on_header(stream, nv, trailer);
|
||||
return http_response_on_header(stream, nv, token, trailer);
|
||||
}
|
||||
|
||||
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
|
||||
@@ -434,12 +339,17 @@ int nghttp2_http_on_request_headers(nghttp2_stream *stream,
|
||||
return -1;
|
||||
}
|
||||
stream->content_length = -1;
|
||||
} else if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
|
||||
} else {
|
||||
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
|
||||
NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
|
||||
(stream->http_flags &
|
||||
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
if (!check_path(stream)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
||||
/* 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. */
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
const nghttp2_nv *nv = &nva[i];
|
||||
if (lookup_token(nv->name, nv->namelen) != NGHTTP2_TOKEN__METHOD) {
|
||||
if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
|
||||
memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
|
||||
continue;
|
||||
}
|
||||
if (streq("CONNECT", nv->value, nv->valuelen)) {
|
||||
if (lstreq("CONNECT", nv->value, nv->valuelen)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
|
||||
return;
|
||||
}
|
||||
if (streq("HEAD", nv->value, nv->valuelen)) {
|
||||
if (lstreq("HEAD", nv->value, nv->valuelen)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
/*
|
||||
* This function is called when HTTP header field |nv| in |frame| is
|
||||
* received for |stream|. This function will validate |nv| against
|
||||
* the current state of stream.
|
||||
* the current state of stream. The |token| is nghttp2_token value
|
||||
* for nv->name, or -1 if we don't have enum value for the name.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
@@ -48,7 +49,8 @@
|
||||
* if it was not received because of compatibility reasons.
|
||||
*/
|
||||
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||
nghttp2_frame *frame, nghttp2_nv *nv, int trailer);
|
||||
nghttp2_frame *frame, nghttp2_nv *nv, int token,
|
||||
int trailer);
|
||||
|
||||
/*
|
||||
* This function is called when request header is received. This
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
typedef int (*nghttp2_compar)(const void *lhs, const void *rhs);
|
||||
/* "less" function, return nonzero if |lhs| is less than |rhs|. */
|
||||
typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
|
||||
|
||||
/* Internal error code. They must be in the range [-499, -100],
|
||||
inclusive. */
|
||||
@@ -51,7 +52,7 @@ typedef enum {
|
||||
* Invalid HTTP header field was received but it can be treated as
|
||||
* if it was not received because of compatibility reasons.
|
||||
*/
|
||||
NGHTTP2_ERR_IGN_HTTP_HEADER = -105,
|
||||
NGHTTP2_ERR_IGN_HTTP_HEADER = -105
|
||||
} nghttp2_internal_error;
|
||||
|
||||
#endif /* NGHTTP2_INT_H */
|
||||
|
||||
@@ -37,8 +37,55 @@
|
||||
#include <netinet/in.h>
|
||||
#endif /* HAVE_NETINET_IN_H */
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
#include <winsock2.h>
|
||||
#endif /* HAVE_WINSOCK2_H */
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
/* Windows requires ws2_32 library for ntonl family functions. We
|
||||
define inline functions for those function so that we don't have
|
||||
dependeny on that lib. */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STIN static __inline
|
||||
#else
|
||||
#define STIN static inline
|
||||
#endif
|
||||
|
||||
STIN uint32_t htonl(uint32_t hostlong) {
|
||||
uint32_t res;
|
||||
unsigned char *p = (unsigned char *)&res;
|
||||
*p++ = hostlong >> 24;
|
||||
*p++ = (hostlong >> 16) & 0xffu;
|
||||
*p++ = (hostlong >> 8) & 0xffu;
|
||||
*p = hostlong & 0xffu;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint16_t htons(uint16_t hostshort) {
|
||||
uint16_t res;
|
||||
unsigned char *p = (unsigned char *)&res;
|
||||
*p++ = hostshort >> 8;
|
||||
*p = hostshort & 0xffu;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint32_t ntohl(uint32_t netlong) {
|
||||
uint32_t res;
|
||||
unsigned char *p = (unsigned char *)&netlong;
|
||||
res = *p++ << 24;
|
||||
res += *p++ << 16;
|
||||
res += *p++ << 8;
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint16_t ntohs(uint16_t netshort) {
|
||||
uint16_t res;
|
||||
unsigned char *p = (unsigned char *)&netshort;
|
||||
res = *p++ << 8;
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
#endif /* NGHTTP2_NET_H */
|
||||
|
||||
@@ -58,7 +58,7 @@ typedef enum {
|
||||
*/
|
||||
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
|
||||
NGHTTP2_OPT_RECV_CLIENT_PREFACE = 1 << 2,
|
||||
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
|
||||
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3
|
||||
} nghttp2_option_flag;
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,15 @@
|
||||
#include "nghttp2_outbound_item.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
void nghttp2_outbound_item_init(nghttp2_outbound_item *item) {
|
||||
item->cycle = 0;
|
||||
item->qnext = NULL;
|
||||
item->queued = 0;
|
||||
|
||||
memset(&item->aux_data, 0, sizeof(nghttp2_aux_data));
|
||||
}
|
||||
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
|
||||
nghttp2_frame *frame;
|
||||
@@ -65,3 +74,32 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q) {
|
||||
q->head = q->tail = NULL;
|
||||
q->n = 0;
|
||||
}
|
||||
|
||||
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
|
||||
nghttp2_outbound_item *item) {
|
||||
if (q->tail) {
|
||||
q->tail = q->tail->qnext = item;
|
||||
} else {
|
||||
q->head = q->tail = item;
|
||||
}
|
||||
++q->n;
|
||||
}
|
||||
|
||||
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q) {
|
||||
nghttp2_outbound_item *item;
|
||||
if (!q->head) {
|
||||
return;
|
||||
}
|
||||
item = q->head;
|
||||
q->head = q->head->qnext;
|
||||
item->qnext = NULL;
|
||||
if (!q->head) {
|
||||
q->tail = NULL;
|
||||
}
|
||||
--q->n;
|
||||
}
|
||||
|
||||
@@ -33,13 +33,6 @@
|
||||
#include "nghttp2_frame.h"
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
/* A bit higher weight for non-DATA frames */
|
||||
#define NGHTTP2_OB_EX_WEIGHT 300
|
||||
/* Higher weight for SETTINGS */
|
||||
#define NGHTTP2_OB_SETTINGS_WEIGHT 301
|
||||
/* Highest weight for PING */
|
||||
#define NGHTTP2_OB_PING_WEIGHT 302
|
||||
|
||||
/* struct used for HEADERS and PUSH_PROMISE frame */
|
||||
typedef struct {
|
||||
nghttp2_data_provider data_prd;
|
||||
@@ -74,6 +67,10 @@ typedef struct {
|
||||
* |eof| is 0. It becomes 1 after all data were read.
|
||||
*/
|
||||
uint8_t eof;
|
||||
/**
|
||||
* The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used.
|
||||
*/
|
||||
uint8_t no_copy;
|
||||
} nghttp2_data_aux_data;
|
||||
|
||||
typedef enum {
|
||||
@@ -84,7 +81,7 @@ typedef enum {
|
||||
/* indicates that this GOAWAY is just a notification for graceful
|
||||
shutdown. No nghttp2_session.goaway_flags should be updated on
|
||||
the reaction to this frame. */
|
||||
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2,
|
||||
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2
|
||||
} nghttp2_goaway_aux_flag;
|
||||
|
||||
/* struct used for GOAWAY frame */
|
||||
@@ -100,19 +97,31 @@ typedef union {
|
||||
nghttp2_goaway_aux_data goaway;
|
||||
} nghttp2_aux_data;
|
||||
|
||||
typedef struct {
|
||||
struct nghttp2_outbound_item;
|
||||
typedef struct nghttp2_outbound_item nghttp2_outbound_item;
|
||||
|
||||
struct nghttp2_outbound_item {
|
||||
nghttp2_frame frame;
|
||||
nghttp2_aux_data aux_data;
|
||||
int64_t seq;
|
||||
/* Reset count of weight. See comment for last_cycle in
|
||||
nghttp2_session.h */
|
||||
/* The priority used in priority comparion. Smaller is served
|
||||
ealier. For PING, SETTINGS and non-DATA frames (excluding
|
||||
response HEADERS frame) have dedicated cycle value defined above.
|
||||
For DATA frame, cycle is computed by taking into account of
|
||||
effective weight and frame payload length previously sent, so
|
||||
that the amount of transmission is distributed across streams
|
||||
proportional to effective weight (inside a tree). */
|
||||
uint64_t cycle;
|
||||
/* The priority used in priority comparion. Larger is served
|
||||
ealier. */
|
||||
int32_t weight;
|
||||
nghttp2_outbound_item *qnext;
|
||||
/* nonzero if this object is queued. */
|
||||
uint8_t queued;
|
||||
} nghttp2_outbound_item;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initializes |item|. No memory allocation is done in this function.
|
||||
* Don't call nghttp2_outbound_item_free() until frame member is
|
||||
* initialized.
|
||||
*/
|
||||
void nghttp2_outbound_item_init(nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Deallocates resource for |item|. If |item| is NULL, this function
|
||||
@@ -120,4 +129,29 @@ typedef struct {
|
||||
*/
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* queue for nghttp2_outbound_item.
|
||||
*/
|
||||
typedef struct {
|
||||
nghttp2_outbound_item *head, *tail;
|
||||
/* number of items in this queue. */
|
||||
size_t n;
|
||||
} nghttp2_outbound_queue;
|
||||
|
||||
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q);
|
||||
|
||||
/* Pushes |item| into |q| */
|
||||
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/* Pops |item| at the top from |q|. If |q| is empty, nothing
|
||||
happens. */
|
||||
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q);
|
||||
|
||||
/* Returns the top item. */
|
||||
#define nghttp2_outbound_queue_top(Q) ((Q)->head)
|
||||
|
||||
/* Returns the size of the queue */
|
||||
#define nghttp2_outbound_queue_size(Q) ((Q)->n)
|
||||
|
||||
#endif /* NGHTTP2_OUTBOUND_ITEM_H */
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
*/
|
||||
#include "nghttp2_pq.h"
|
||||
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar compar, nghttp2_mem *mem) {
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
|
||||
pq->mem = mem;
|
||||
pq->capacity = 128;
|
||||
pq->q = nghttp2_mem_malloc(mem, pq->capacity * sizeof(void *));
|
||||
@@ -32,7 +32,7 @@ int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar compar, nghttp2_mem *mem) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
pq->length = 0;
|
||||
pq->compar = compar;
|
||||
pq->less = less;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ static void bubble_up(nghttp2_pq *pq, size_t index) {
|
||||
return;
|
||||
} else {
|
||||
size_t parent = (index - 1) / 2;
|
||||
if (pq->compar(pq->q[parent], pq->q[index]) > 0) {
|
||||
if (pq->less(pq->q[index], pq->q[parent])) {
|
||||
swap(pq, parent, index);
|
||||
bubble_up(pq, parent);
|
||||
}
|
||||
@@ -93,7 +93,7 @@ static void bubble_down(nghttp2_pq *pq, size_t index) {
|
||||
if (j >= pq->length) {
|
||||
break;
|
||||
}
|
||||
if (pq->compar(pq->q[minindex], pq->q[j]) > 0) {
|
||||
if (pq->less(pq->q[j], pq->q[minindex])) {
|
||||
minindex = j;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ typedef struct {
|
||||
/* The maximum number of items this pq can store. This is
|
||||
automatically extended when length is reached to this value. */
|
||||
size_t capacity;
|
||||
/* The compare function between items */
|
||||
nghttp2_compar compar;
|
||||
/* The less function between items */
|
||||
nghttp2_less less;
|
||||
} nghttp2_pq;
|
||||
|
||||
/*
|
||||
@@ -58,7 +58,7 @@ typedef struct {
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar cmp, nghttp2_mem *mem);
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |pq|. The stored items are
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -47,12 +47,13 @@
|
||||
typedef enum {
|
||||
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
|
||||
NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE = 1 << 1,
|
||||
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
|
||||
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2
|
||||
} nghttp2_optmask;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_OB_POP_ITEM,
|
||||
NGHTTP2_OB_SEND_DATA
|
||||
NGHTTP2_OB_SEND_DATA,
|
||||
NGHTTP2_OB_SEND_NO_COPY
|
||||
} nghttp2_outbound_state;
|
||||
|
||||
typedef struct {
|
||||
@@ -83,7 +84,7 @@ typedef enum {
|
||||
NGHTTP2_IB_READ_PAD_DATA,
|
||||
NGHTTP2_IB_READ_DATA,
|
||||
NGHTTP2_IB_IGN_DATA,
|
||||
NGHTTP2_IB_IGN_ALL,
|
||||
NGHTTP2_IB_IGN_ALL
|
||||
} nghttp2_inbound_state;
|
||||
|
||||
#define NGHTTP2_INBOUND_NUM_IV 7
|
||||
@@ -135,18 +136,21 @@ typedef enum {
|
||||
/* Flag means GOAWAY was sent */
|
||||
NGHTTP2_GOAWAY_SENT = 0x4,
|
||||
/* Flag means GOAWAY was received */
|
||||
NGHTTP2_GOAWAY_RECV = 0x8,
|
||||
NGHTTP2_GOAWAY_RECV = 0x8
|
||||
} nghttp2_goaway_flag;
|
||||
|
||||
struct nghttp2_session {
|
||||
nghttp2_map /* <nghttp2_stream*> */ streams;
|
||||
nghttp2_stream_roots roots;
|
||||
/* Queue for outbound frames other than stream-creating HEADERS and
|
||||
DATA */
|
||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq;
|
||||
/* Queue for outbound stream-creating HEADERS frame */
|
||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_ss_pq;
|
||||
/* QUeue for DATA frame */
|
||||
/* Queue for outbound urgent frames (PING and SETTINGS) */
|
||||
nghttp2_outbound_queue ob_urgent;
|
||||
/* Queue for non-DATA frames */
|
||||
nghttp2_outbound_queue ob_reg;
|
||||
/* Queue for outbound stream-creating HEADERS (request or push
|
||||
response) frame, which are subject to
|
||||
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
|
||||
nghttp2_outbound_queue ob_syn;
|
||||
/* Queue for DATA frame */
|
||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_da_pq;
|
||||
nghttp2_active_outbound_item aob;
|
||||
nghttp2_inbound_frame iframe;
|
||||
@@ -155,22 +159,8 @@ struct nghttp2_session {
|
||||
nghttp2_session_callbacks callbacks;
|
||||
/* Memory allocator */
|
||||
nghttp2_mem mem;
|
||||
/* Sequence number of outbound frame to maintain the order of
|
||||
enqueue if priority is equal. */
|
||||
int64_t next_seq;
|
||||
/* Reset count of nghttp2_outbound_item's weight. We decrements
|
||||
weight each time DATA is sent to simulate resource sharing. We
|
||||
use priority queue and larger weight has the precedence. If
|
||||
weight is reached to lowest weight, it resets to its initial
|
||||
weight. If this happens, other items which have the lower weight
|
||||
currently but same initial weight cannot send DATA until item
|
||||
having large weight is decreased. To avoid this, we use this
|
||||
cycle variable. Initally, this is set to 1. If weight gets
|
||||
lowest weight, and if item's cycle == last_cycle, we increments
|
||||
last_cycle and assigns it to item's cycle. Otherwise, just
|
||||
assign last_cycle. In priority queue comparator, we first
|
||||
compare items' cycle value. Lower cycle value has the
|
||||
precedence. */
|
||||
/* Base value when we schedule next DATA frame write. This is
|
||||
updated when one frame was written. */
|
||||
uint64_t last_cycle;
|
||||
void *user_data;
|
||||
/* Points to the latest closed stream. NULL if there is no closed
|
||||
@@ -290,14 +280,6 @@ typedef struct {
|
||||
int nghttp2_session_is_my_stream_id(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
* Initializes |item|. No memory allocation is done in this function.
|
||||
* Don't call nghttp2_outbound_item_free() until frame member is
|
||||
* initialized.
|
||||
*/
|
||||
void nghttp2_session_outbound_item_init(nghttp2_session *session,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Adds |item| to the outbound queue in |session|. When this function
|
||||
* succeeds, it takes ownership of |item|. So caller must not free it
|
||||
@@ -703,13 +685,8 @@ nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
|
||||
*/
|
||||
int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
||||
size_t datamax, nghttp2_frame *frame,
|
||||
nghttp2_data_aux_data *aux_data);
|
||||
|
||||
/*
|
||||
* Returns top of outbound frame queue. This function returns NULL if
|
||||
* queue is empty.
|
||||
*/
|
||||
nghttp2_outbound_item *nghttp2_session_get_ob_pq_top(nghttp2_session *session);
|
||||
nghttp2_data_aux_data *aux_data,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Pops and returns next item to send. If there is no such item,
|
||||
|
||||
@@ -63,7 +63,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
stream->effective_weight = stream->weight;
|
||||
stream->sum_dep_weight = 0;
|
||||
stream->sum_norest_weight = 0;
|
||||
stream->sum_top_weight = 0;
|
||||
|
||||
stream->roots = roots;
|
||||
stream->root_prev = NULL;
|
||||
@@ -87,7 +86,8 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
|
||||
}
|
||||
|
||||
static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
|
||||
int rv;
|
||||
/* This is required for Android NDK r10d */
|
||||
int rv = 0;
|
||||
nghttp2_outbound_item *item;
|
||||
|
||||
assert(stream->item);
|
||||
@@ -101,33 +101,33 @@ static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (item->weight > stream->effective_weight) {
|
||||
item->weight = stream->effective_weight;
|
||||
}
|
||||
|
||||
item->cycle = session->last_cycle;
|
||||
|
||||
switch (item->frame.hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
/* Penalize item by delaying scheduling according to effective
|
||||
weight. This will delay low priority stream, which is good.
|
||||
OTOH, this may incur delay for high priority item. Will
|
||||
see. */
|
||||
item->cycle =
|
||||
session->last_cycle +
|
||||
NGHTTP2_DATA_PAYLOADLEN * NGHTTP2_MAX_WEIGHT / stream->effective_weight;
|
||||
|
||||
rv = nghttp2_pq_push(&session->ob_da_pq, item);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_HEADERS:
|
||||
if (stream->state == NGHTTP2_STREAM_RESERVED) {
|
||||
rv = nghttp2_pq_push(&session->ob_ss_pq, item);
|
||||
nghttp2_outbound_queue_push(&session->ob_syn, item);
|
||||
} else {
|
||||
rv = nghttp2_pq_push(&session->ob_pq, item);
|
||||
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
/* should not reach here */
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
item->queued = 1;
|
||||
|
||||
return 0;
|
||||
@@ -178,18 +178,6 @@ int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
|
||||
return nghttp2_max(1, weight);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
stream_dep_distributed_top_effective_weight(nghttp2_stream *stream,
|
||||
int32_t weight) {
|
||||
if (stream->sum_top_weight == 0) {
|
||||
return stream->effective_weight;
|
||||
}
|
||||
|
||||
weight = stream->effective_weight * weight / stream->sum_top_weight;
|
||||
|
||||
return nghttp2_max(1, weight);
|
||||
}
|
||||
|
||||
static void stream_update_dep_set_rest(nghttp2_stream *stream);
|
||||
|
||||
/* Updates effective_weight of descendant streams in subtree of
|
||||
@@ -199,10 +187,9 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight "
|
||||
"stream(%p)=%d, weight=%d, sum_norest_weight=%d, "
|
||||
"sum_top_weight=%d\n",
|
||||
"stream(%p)=%d, weight=%d, sum_norest_weight=%d\n",
|
||||
stream, stream->stream_id, stream->weight,
|
||||
stream->sum_norest_weight, stream->sum_top_weight));
|
||||
stream->sum_norest_weight));
|
||||
|
||||
/* stream->sum_norest_weight == 0 means there is no
|
||||
NGHTTP2_STREAM_DPRI_TOP under stream */
|
||||
@@ -211,10 +198,6 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is no direct descendant whose dpri is
|
||||
NGHTTP2_STREAM_DPRI_TOP, indirect descendants have the chance to
|
||||
send data, so recursively set weight for descendants. */
|
||||
if (stream->sum_top_weight == 0) {
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
if (si->dpri != NGHTTP2_STREAM_DPRI_REST) {
|
||||
si->effective_weight =
|
||||
@@ -223,36 +206,6 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
|
||||
|
||||
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) {
|
||||
@@ -347,25 +300,20 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates stream->sum_norest_weight and stream->sum_top_weight
|
||||
* recursively. We have to gather effective sum of weight of
|
||||
* descendants. If stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM, we
|
||||
* have to go deeper and check that any of its descendants has dpri
|
||||
* value of NGHTTP2_STREAM_DPRI_TOP. If so, we have to add weight of
|
||||
* its direct descendants to stream->sum_norest_weight. To make this
|
||||
* work, this function returns 1 if any of its descendants has dpri
|
||||
* value of NGHTTP2_STREAM_DPRI_TOP, otherwise 0.
|
||||
*
|
||||
* Calculating stream->sum_top-weight is very simple compared to
|
||||
* stream->sum_norest_weight. It just adds up the weight of direct
|
||||
* descendants whose dpri is NGHTTP2_STREAM_DPRI_TOP.
|
||||
* Updates stream->sum_norest_weight recursively. We have to gather
|
||||
* effective sum of weight of descendants. If stream->dpri ==
|
||||
* NGHTTP2_STREAM_DPRI_NO_ITEM, we have to go deeper and check that
|
||||
* any of its descendants has dpri value of NGHTTP2_STREAM_DPRI_TOP.
|
||||
* If so, we have to add weight of its direct descendants to
|
||||
* stream->sum_norest_weight. To make this work, this function
|
||||
* returns 1 if any of its descendants has dpri value of
|
||||
* NGHTTP2_STREAM_DPRI_TOP, otherwise 0.
|
||||
*/
|
||||
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
int rv;
|
||||
|
||||
stream->sum_norest_weight = 0;
|
||||
stream->sum_top_weight = 0;
|
||||
|
||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
return 1;
|
||||
@@ -383,10 +331,6 @@ static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) {
|
||||
rv = 1;
|
||||
stream->sum_norest_weight += si->weight;
|
||||
}
|
||||
|
||||
if (si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
stream->sum_top_weight += si->weight;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
||||
@@ -120,10 +120,20 @@ typedef enum {
|
||||
/* HTTP method flags */
|
||||
NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
|
||||
NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
|
||||
NGHTTP2_HTTP_FLAG_METH_ALL =
|
||||
NGHTTP2_HTTP_FLAG_METH_CONNECT | NGHTTP2_HTTP_FLAG_METH_HEAD,
|
||||
NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
|
||||
NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT |
|
||||
NGHTTP2_HTTP_FLAG_METH_HEAD |
|
||||
NGHTTP2_HTTP_FLAG_METH_OPTIONS,
|
||||
/* :path category */
|
||||
/* path starts with "/" */
|
||||
NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 10,
|
||||
/* path "*" */
|
||||
NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 11,
|
||||
/* scheme */
|
||||
/* "http" or "https" scheme */
|
||||
NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 12,
|
||||
/* set if final response is expected */
|
||||
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 9,
|
||||
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 13
|
||||
} nghttp2_http_flag;
|
||||
|
||||
typedef enum {
|
||||
@@ -144,6 +154,10 @@ typedef struct nghttp2_stream nghttp2_stream;
|
||||
struct nghttp2_stream {
|
||||
/* Intrusive Map */
|
||||
nghttp2_map_entry map_entry;
|
||||
/* Content-Length of request/response body. -1 if unknown. */
|
||||
int64_t content_length;
|
||||
/* Received body so far */
|
||||
int64_t recv_content_length;
|
||||
/* pointers to form dependency tree. If multiple streams depend on
|
||||
a stream, only one stream (left most) has non-NULL dep_prev which
|
||||
points to the stream it depends on. The remaining streams are
|
||||
@@ -203,22 +217,15 @@ struct nghttp2_stream {
|
||||
descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this
|
||||
value to calculate effective weight. */
|
||||
int32_t sum_norest_weight;
|
||||
/* sum of weight of direct descendants whose dpri value is
|
||||
NGHTTP2_STREAM_DPRI_TOP */
|
||||
int32_t sum_top_weight;
|
||||
nghttp2_stream_state state;
|
||||
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
|
||||
uint8_t flags;
|
||||
/* Bitwise OR of zero or more nghttp2_shut_flag values */
|
||||
uint8_t shut_flags;
|
||||
/* Content-Length of request/response body. -1 if unknown. */
|
||||
int64_t content_length;
|
||||
/* Received body so far */
|
||||
int64_t recv_content_length;
|
||||
/* status code from remote server */
|
||||
int16_t status_code;
|
||||
/* Bitwise OR of zero or more nghttp2_http_flag values */
|
||||
uint16_t http_flags;
|
||||
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
|
||||
uint8_t flags;
|
||||
/* Bitwise OR of zero or more nghttp2_shut_flag values */
|
||||
uint8_t shut_flags;
|
||||
};
|
||||
|
||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
|
||||
@@ -62,7 +62,7 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
if (data_prd != NULL && data_prd->read_callback != NULL) {
|
||||
item->aux_data.headers.data_prd = *data_prd;
|
||||
@@ -212,7 +212,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
@@ -299,7 +299,7 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
item->aux_data.headers.stream_user_data = promised_stream_user_data;
|
||||
|
||||
@@ -453,7 +453,7 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
frame = &item->frame;
|
||||
aux_data = &item->aux_data.data;
|
||||
|
||||
420
mkhufftbl.py
420
mkhufftbl.py
@@ -10,8 +10,271 @@
|
||||
from __future__ import unicode_literals
|
||||
import re
|
||||
import sys
|
||||
import StringIO
|
||||
|
||||
# From [1]
|
||||
HUFFMAN_CODE_TABLE = """\
|
||||
( 0) |11111111|11000 1ff8 [13]
|
||||
( 1) |11111111|11111111|1011000 7fffd8 [23]
|
||||
( 2) |11111111|11111111|11111110|0010 fffffe2 [28]
|
||||
( 3) |11111111|11111111|11111110|0011 fffffe3 [28]
|
||||
( 4) |11111111|11111111|11111110|0100 fffffe4 [28]
|
||||
( 5) |11111111|11111111|11111110|0101 fffffe5 [28]
|
||||
( 6) |11111111|11111111|11111110|0110 fffffe6 [28]
|
||||
( 7) |11111111|11111111|11111110|0111 fffffe7 [28]
|
||||
( 8) |11111111|11111111|11111110|1000 fffffe8 [28]
|
||||
( 9) |11111111|11111111|11101010 ffffea [24]
|
||||
( 10) |11111111|11111111|11111111|111100 3ffffffc [30]
|
||||
( 11) |11111111|11111111|11111110|1001 fffffe9 [28]
|
||||
( 12) |11111111|11111111|11111110|1010 fffffea [28]
|
||||
( 13) |11111111|11111111|11111111|111101 3ffffffd [30]
|
||||
( 14) |11111111|11111111|11111110|1011 fffffeb [28]
|
||||
( 15) |11111111|11111111|11111110|1100 fffffec [28]
|
||||
( 16) |11111111|11111111|11111110|1101 fffffed [28]
|
||||
( 17) |11111111|11111111|11111110|1110 fffffee [28]
|
||||
( 18) |11111111|11111111|11111110|1111 fffffef [28]
|
||||
( 19) |11111111|11111111|11111111|0000 ffffff0 [28]
|
||||
( 20) |11111111|11111111|11111111|0001 ffffff1 [28]
|
||||
( 21) |11111111|11111111|11111111|0010 ffffff2 [28]
|
||||
( 22) |11111111|11111111|11111111|111110 3ffffffe [30]
|
||||
( 23) |11111111|11111111|11111111|0011 ffffff3 [28]
|
||||
( 24) |11111111|11111111|11111111|0100 ffffff4 [28]
|
||||
( 25) |11111111|11111111|11111111|0101 ffffff5 [28]
|
||||
( 26) |11111111|11111111|11111111|0110 ffffff6 [28]
|
||||
( 27) |11111111|11111111|11111111|0111 ffffff7 [28]
|
||||
( 28) |11111111|11111111|11111111|1000 ffffff8 [28]
|
||||
( 29) |11111111|11111111|11111111|1001 ffffff9 [28]
|
||||
( 30) |11111111|11111111|11111111|1010 ffffffa [28]
|
||||
( 31) |11111111|11111111|11111111|1011 ffffffb [28]
|
||||
' ' ( 32) |010100 14 [ 6]
|
||||
'!' ( 33) |11111110|00 3f8 [10]
|
||||
'"' ( 34) |11111110|01 3f9 [10]
|
||||
'#' ( 35) |11111111|1010 ffa [12]
|
||||
'$' ( 36) |11111111|11001 1ff9 [13]
|
||||
'%' ( 37) |010101 15 [ 6]
|
||||
'&' ( 38) |11111000 f8 [ 8]
|
||||
''' ( 39) |11111111|010 7fa [11]
|
||||
'(' ( 40) |11111110|10 3fa [10]
|
||||
')' ( 41) |11111110|11 3fb [10]
|
||||
'*' ( 42) |11111001 f9 [ 8]
|
||||
'+' ( 43) |11111111|011 7fb [11]
|
||||
',' ( 44) |11111010 fa [ 8]
|
||||
'-' ( 45) |010110 16 [ 6]
|
||||
'.' ( 46) |010111 17 [ 6]
|
||||
'/' ( 47) |011000 18 [ 6]
|
||||
'0' ( 48) |00000 0 [ 5]
|
||||
'1' ( 49) |00001 1 [ 5]
|
||||
'2' ( 50) |00010 2 [ 5]
|
||||
'3' ( 51) |011001 19 [ 6]
|
||||
'4' ( 52) |011010 1a [ 6]
|
||||
'5' ( 53) |011011 1b [ 6]
|
||||
'6' ( 54) |011100 1c [ 6]
|
||||
'7' ( 55) |011101 1d [ 6]
|
||||
'8' ( 56) |011110 1e [ 6]
|
||||
'9' ( 57) |011111 1f [ 6]
|
||||
':' ( 58) |1011100 5c [ 7]
|
||||
';' ( 59) |11111011 fb [ 8]
|
||||
'<' ( 60) |11111111|1111100 7ffc [15]
|
||||
'=' ( 61) |100000 20 [ 6]
|
||||
'>' ( 62) |11111111|1011 ffb [12]
|
||||
'?' ( 63) |11111111|00 3fc [10]
|
||||
'@' ( 64) |11111111|11010 1ffa [13]
|
||||
'A' ( 65) |100001 21 [ 6]
|
||||
'B' ( 66) |1011101 5d [ 7]
|
||||
'C' ( 67) |1011110 5e [ 7]
|
||||
'D' ( 68) |1011111 5f [ 7]
|
||||
'E' ( 69) |1100000 60 [ 7]
|
||||
'F' ( 70) |1100001 61 [ 7]
|
||||
'G' ( 71) |1100010 62 [ 7]
|
||||
'H' ( 72) |1100011 63 [ 7]
|
||||
'I' ( 73) |1100100 64 [ 7]
|
||||
'J' ( 74) |1100101 65 [ 7]
|
||||
'K' ( 75) |1100110 66 [ 7]
|
||||
'L' ( 76) |1100111 67 [ 7]
|
||||
'M' ( 77) |1101000 68 [ 7]
|
||||
'N' ( 78) |1101001 69 [ 7]
|
||||
'O' ( 79) |1101010 6a [ 7]
|
||||
'P' ( 80) |1101011 6b [ 7]
|
||||
'Q' ( 81) |1101100 6c [ 7]
|
||||
'R' ( 82) |1101101 6d [ 7]
|
||||
'S' ( 83) |1101110 6e [ 7]
|
||||
'T' ( 84) |1101111 6f [ 7]
|
||||
'U' ( 85) |1110000 70 [ 7]
|
||||
'V' ( 86) |1110001 71 [ 7]
|
||||
'W' ( 87) |1110010 72 [ 7]
|
||||
'X' ( 88) |11111100 fc [ 8]
|
||||
'Y' ( 89) |1110011 73 [ 7]
|
||||
'Z' ( 90) |11111101 fd [ 8]
|
||||
'[' ( 91) |11111111|11011 1ffb [13]
|
||||
'\' ( 92) |11111111|11111110|000 7fff0 [19]
|
||||
']' ( 93) |11111111|11100 1ffc [13]
|
||||
'^' ( 94) |11111111|111100 3ffc [14]
|
||||
'_' ( 95) |100010 22 [ 6]
|
||||
'`' ( 96) |11111111|1111101 7ffd [15]
|
||||
'a' ( 97) |00011 3 [ 5]
|
||||
'b' ( 98) |100011 23 [ 6]
|
||||
'c' ( 99) |00100 4 [ 5]
|
||||
'd' (100) |100100 24 [ 6]
|
||||
'e' (101) |00101 5 [ 5]
|
||||
'f' (102) |100101 25 [ 6]
|
||||
'g' (103) |100110 26 [ 6]
|
||||
'h' (104) |100111 27 [ 6]
|
||||
'i' (105) |00110 6 [ 5]
|
||||
'j' (106) |1110100 74 [ 7]
|
||||
'k' (107) |1110101 75 [ 7]
|
||||
'l' (108) |101000 28 [ 6]
|
||||
'm' (109) |101001 29 [ 6]
|
||||
'n' (110) |101010 2a [ 6]
|
||||
'o' (111) |00111 7 [ 5]
|
||||
'p' (112) |101011 2b [ 6]
|
||||
'q' (113) |1110110 76 [ 7]
|
||||
'r' (114) |101100 2c [ 6]
|
||||
's' (115) |01000 8 [ 5]
|
||||
't' (116) |01001 9 [ 5]
|
||||
'u' (117) |101101 2d [ 6]
|
||||
'v' (118) |1110111 77 [ 7]
|
||||
'w' (119) |1111000 78 [ 7]
|
||||
'x' (120) |1111001 79 [ 7]
|
||||
'y' (121) |1111010 7a [ 7]
|
||||
'z' (122) |1111011 7b [ 7]
|
||||
'{' (123) |11111111|1111110 7ffe [15]
|
||||
'|' (124) |11111111|100 7fc [11]
|
||||
'}' (125) |11111111|111101 3ffd [14]
|
||||
'~' (126) |11111111|11101 1ffd [13]
|
||||
(127) |11111111|11111111|11111111|1100 ffffffc [28]
|
||||
(128) |11111111|11111110|0110 fffe6 [20]
|
||||
(129) |11111111|11111111|010010 3fffd2 [22]
|
||||
(130) |11111111|11111110|0111 fffe7 [20]
|
||||
(131) |11111111|11111110|1000 fffe8 [20]
|
||||
(132) |11111111|11111111|010011 3fffd3 [22]
|
||||
(133) |11111111|11111111|010100 3fffd4 [22]
|
||||
(134) |11111111|11111111|010101 3fffd5 [22]
|
||||
(135) |11111111|11111111|1011001 7fffd9 [23]
|
||||
(136) |11111111|11111111|010110 3fffd6 [22]
|
||||
(137) |11111111|11111111|1011010 7fffda [23]
|
||||
(138) |11111111|11111111|1011011 7fffdb [23]
|
||||
(139) |11111111|11111111|1011100 7fffdc [23]
|
||||
(140) |11111111|11111111|1011101 7fffdd [23]
|
||||
(141) |11111111|11111111|1011110 7fffde [23]
|
||||
(142) |11111111|11111111|11101011 ffffeb [24]
|
||||
(143) |11111111|11111111|1011111 7fffdf [23]
|
||||
(144) |11111111|11111111|11101100 ffffec [24]
|
||||
(145) |11111111|11111111|11101101 ffffed [24]
|
||||
(146) |11111111|11111111|010111 3fffd7 [22]
|
||||
(147) |11111111|11111111|1100000 7fffe0 [23]
|
||||
(148) |11111111|11111111|11101110 ffffee [24]
|
||||
(149) |11111111|11111111|1100001 7fffe1 [23]
|
||||
(150) |11111111|11111111|1100010 7fffe2 [23]
|
||||
(151) |11111111|11111111|1100011 7fffe3 [23]
|
||||
(152) |11111111|11111111|1100100 7fffe4 [23]
|
||||
(153) |11111111|11111110|11100 1fffdc [21]
|
||||
(154) |11111111|11111111|011000 3fffd8 [22]
|
||||
(155) |11111111|11111111|1100101 7fffe5 [23]
|
||||
(156) |11111111|11111111|011001 3fffd9 [22]
|
||||
(157) |11111111|11111111|1100110 7fffe6 [23]
|
||||
(158) |11111111|11111111|1100111 7fffe7 [23]
|
||||
(159) |11111111|11111111|11101111 ffffef [24]
|
||||
(160) |11111111|11111111|011010 3fffda [22]
|
||||
(161) |11111111|11111110|11101 1fffdd [21]
|
||||
(162) |11111111|11111110|1001 fffe9 [20]
|
||||
(163) |11111111|11111111|011011 3fffdb [22]
|
||||
(164) |11111111|11111111|011100 3fffdc [22]
|
||||
(165) |11111111|11111111|1101000 7fffe8 [23]
|
||||
(166) |11111111|11111111|1101001 7fffe9 [23]
|
||||
(167) |11111111|11111110|11110 1fffde [21]
|
||||
(168) |11111111|11111111|1101010 7fffea [23]
|
||||
(169) |11111111|11111111|011101 3fffdd [22]
|
||||
(170) |11111111|11111111|011110 3fffde [22]
|
||||
(171) |11111111|11111111|11110000 fffff0 [24]
|
||||
(172) |11111111|11111110|11111 1fffdf [21]
|
||||
(173) |11111111|11111111|011111 3fffdf [22]
|
||||
(174) |11111111|11111111|1101011 7fffeb [23]
|
||||
(175) |11111111|11111111|1101100 7fffec [23]
|
||||
(176) |11111111|11111111|00000 1fffe0 [21]
|
||||
(177) |11111111|11111111|00001 1fffe1 [21]
|
||||
(178) |11111111|11111111|100000 3fffe0 [22]
|
||||
(179) |11111111|11111111|00010 1fffe2 [21]
|
||||
(180) |11111111|11111111|1101101 7fffed [23]
|
||||
(181) |11111111|11111111|100001 3fffe1 [22]
|
||||
(182) |11111111|11111111|1101110 7fffee [23]
|
||||
(183) |11111111|11111111|1101111 7fffef [23]
|
||||
(184) |11111111|11111110|1010 fffea [20]
|
||||
(185) |11111111|11111111|100010 3fffe2 [22]
|
||||
(186) |11111111|11111111|100011 3fffe3 [22]
|
||||
(187) |11111111|11111111|100100 3fffe4 [22]
|
||||
(188) |11111111|11111111|1110000 7ffff0 [23]
|
||||
(189) |11111111|11111111|100101 3fffe5 [22]
|
||||
(190) |11111111|11111111|100110 3fffe6 [22]
|
||||
(191) |11111111|11111111|1110001 7ffff1 [23]
|
||||
(192) |11111111|11111111|11111000|00 3ffffe0 [26]
|
||||
(193) |11111111|11111111|11111000|01 3ffffe1 [26]
|
||||
(194) |11111111|11111110|1011 fffeb [20]
|
||||
(195) |11111111|11111110|001 7fff1 [19]
|
||||
(196) |11111111|11111111|100111 3fffe7 [22]
|
||||
(197) |11111111|11111111|1110010 7ffff2 [23]
|
||||
(198) |11111111|11111111|101000 3fffe8 [22]
|
||||
(199) |11111111|11111111|11110110|0 1ffffec [25]
|
||||
(200) |11111111|11111111|11111000|10 3ffffe2 [26]
|
||||
(201) |11111111|11111111|11111000|11 3ffffe3 [26]
|
||||
(202) |11111111|11111111|11111001|00 3ffffe4 [26]
|
||||
(203) |11111111|11111111|11111011|110 7ffffde [27]
|
||||
(204) |11111111|11111111|11111011|111 7ffffdf [27]
|
||||
(205) |11111111|11111111|11111001|01 3ffffe5 [26]
|
||||
(206) |11111111|11111111|11110001 fffff1 [24]
|
||||
(207) |11111111|11111111|11110110|1 1ffffed [25]
|
||||
(208) |11111111|11111110|010 7fff2 [19]
|
||||
(209) |11111111|11111111|00011 1fffe3 [21]
|
||||
(210) |11111111|11111111|11111001|10 3ffffe6 [26]
|
||||
(211) |11111111|11111111|11111100|000 7ffffe0 [27]
|
||||
(212) |11111111|11111111|11111100|001 7ffffe1 [27]
|
||||
(213) |11111111|11111111|11111001|11 3ffffe7 [26]
|
||||
(214) |11111111|11111111|11111100|010 7ffffe2 [27]
|
||||
(215) |11111111|11111111|11110010 fffff2 [24]
|
||||
(216) |11111111|11111111|00100 1fffe4 [21]
|
||||
(217) |11111111|11111111|00101 1fffe5 [21]
|
||||
(218) |11111111|11111111|11111010|00 3ffffe8 [26]
|
||||
(219) |11111111|11111111|11111010|01 3ffffe9 [26]
|
||||
(220) |11111111|11111111|11111111|1101 ffffffd [28]
|
||||
(221) |11111111|11111111|11111100|011 7ffffe3 [27]
|
||||
(222) |11111111|11111111|11111100|100 7ffffe4 [27]
|
||||
(223) |11111111|11111111|11111100|101 7ffffe5 [27]
|
||||
(224) |11111111|11111110|1100 fffec [20]
|
||||
(225) |11111111|11111111|11110011 fffff3 [24]
|
||||
(226) |11111111|11111110|1101 fffed [20]
|
||||
(227) |11111111|11111111|00110 1fffe6 [21]
|
||||
(228) |11111111|11111111|101001 3fffe9 [22]
|
||||
(229) |11111111|11111111|00111 1fffe7 [21]
|
||||
(230) |11111111|11111111|01000 1fffe8 [21]
|
||||
(231) |11111111|11111111|1110011 7ffff3 [23]
|
||||
(232) |11111111|11111111|101010 3fffea [22]
|
||||
(233) |11111111|11111111|101011 3fffeb [22]
|
||||
(234) |11111111|11111111|11110111|0 1ffffee [25]
|
||||
(235) |11111111|11111111|11110111|1 1ffffef [25]
|
||||
(236) |11111111|11111111|11110100 fffff4 [24]
|
||||
(237) |11111111|11111111|11110101 fffff5 [24]
|
||||
(238) |11111111|11111111|11111010|10 3ffffea [26]
|
||||
(239) |11111111|11111111|1110100 7ffff4 [23]
|
||||
(240) |11111111|11111111|11111010|11 3ffffeb [26]
|
||||
(241) |11111111|11111111|11111100|110 7ffffe6 [27]
|
||||
(242) |11111111|11111111|11111011|00 3ffffec [26]
|
||||
(243) |11111111|11111111|11111011|01 3ffffed [26]
|
||||
(244) |11111111|11111111|11111100|111 7ffffe7 [27]
|
||||
(245) |11111111|11111111|11111101|000 7ffffe8 [27]
|
||||
(246) |11111111|11111111|11111101|001 7ffffe9 [27]
|
||||
(247) |11111111|11111111|11111101|010 7ffffea [27]
|
||||
(248) |11111111|11111111|11111101|011 7ffffeb [27]
|
||||
(249) |11111111|11111111|11111111|1110 ffffffe [28]
|
||||
(250) |11111111|11111111|11111101|100 7ffffec [27]
|
||||
(251) |11111111|11111111|11111101|101 7ffffed [27]
|
||||
(252) |11111111|11111111|11111101|110 7ffffee [27]
|
||||
(253) |11111111|11111111|11111101|111 7ffffef [27]
|
||||
(254) |11111111|11111111|11111110|000 7fffff0 [27]
|
||||
(255) |11111111|11111111|11111011|10 3ffffee [26]
|
||||
EOS (256) |11111111|11111111|11111111|111111 3fffffff [30]
|
||||
"""
|
||||
|
||||
class Node:
|
||||
|
||||
def __init__(self, term = None):
|
||||
self.term = term
|
||||
self.left = None
|
||||
@@ -20,21 +283,18 @@ class Node:
|
||||
self.id = None
|
||||
self.accept = False
|
||||
|
||||
def to_bin(s):
|
||||
res = []
|
||||
for i in range(0, len(s), 8):
|
||||
x = s[i:i+8]
|
||||
x += '0'*(8 - len(x))
|
||||
a = 0
|
||||
for j in range(8):
|
||||
a *= 2
|
||||
a += ord(x[j]) - ord('0')
|
||||
res.append(a) #chr(a))
|
||||
return res
|
||||
class Context:
|
||||
|
||||
nodes = []
|
||||
def __init__(self):
|
||||
self.next_id_ = 0
|
||||
self.root = Node()
|
||||
|
||||
def insert(node, sym, bits):
|
||||
def next_id(self):
|
||||
id = self.next_id_
|
||||
self.next_id_ += 1
|
||||
return id
|
||||
|
||||
def _add(node, sym, bits):
|
||||
if len(bits) == 0:
|
||||
node.term = sym
|
||||
return
|
||||
@@ -47,67 +307,71 @@ def insert(node, sym, bits):
|
||||
if node.right is None:
|
||||
node.right = Node()
|
||||
child = node.right
|
||||
insert(child, sym, bits[1:])
|
||||
_add(child, sym, bits[1:])
|
||||
|
||||
def traverse(node, bits, syms, start_node, root, depth):
|
||||
if depth == 4:
|
||||
if 256 in syms:
|
||||
syms = []
|
||||
def huffman_tree_add(ctx, sym, bits):
|
||||
_add(ctx.root, sym, bits)
|
||||
|
||||
def _set_node_id(ctx, node, prefix):
|
||||
if node.term is not None:
|
||||
return
|
||||
if len(prefix) <= 7 and [1] * len(prefix) == prefix:
|
||||
node.accept = True
|
||||
node.id = ctx.next_id()
|
||||
_set_node_id(ctx, node.left, prefix + [0])
|
||||
_set_node_id(ctx, node.right, prefix + [1])
|
||||
|
||||
def huffman_tree_set_node_id(ctx):
|
||||
_set_node_id(ctx, ctx.root, [])
|
||||
|
||||
def _traverse(node, sym, start_node, root, left):
|
||||
if left == 0:
|
||||
if sym == 256:
|
||||
sym = None
|
||||
node = None
|
||||
start_node.trans.append((node, bits, syms))
|
||||
start_node.trans.append((node, sym))
|
||||
return
|
||||
|
||||
if node.term is not None:
|
||||
node = root
|
||||
|
||||
def go(node, bit):
|
||||
nbits = list(bits)
|
||||
nbits.append(bit)
|
||||
nsyms = list(syms)
|
||||
def go(node):
|
||||
if node.term is not None:
|
||||
nsyms.append(node.term)
|
||||
traverse(node, nbits, nsyms, start_node, root, depth + 1)
|
||||
assert sym is None
|
||||
nsym = node.term
|
||||
else:
|
||||
nsym = sym
|
||||
|
||||
go(node.left, 0)
|
||||
go(node.right, 1)
|
||||
_traverse(node, nsym, start_node, root, left - 1)
|
||||
|
||||
idseed = 0
|
||||
go(node.left)
|
||||
go(node.right)
|
||||
|
||||
def dfs_setid(node, prefix):
|
||||
if node.term is not None:
|
||||
return
|
||||
if len(prefix) <= 7 and [1] * len(prefix) == prefix:
|
||||
node.accept = True
|
||||
global idseed
|
||||
node.id = idseed
|
||||
idseed += 1
|
||||
dfs_setid(node.left, prefix + [0])
|
||||
dfs_setid(node.right, prefix + [1])
|
||||
|
||||
def dfs(node, root):
|
||||
def _build_transition_table(ctx, node):
|
||||
if node is None:
|
||||
return
|
||||
traverse(node, [], [], node, root, 0)
|
||||
dfs(node.left, root)
|
||||
dfs(node.right, root)
|
||||
_traverse(node, None, node, ctx.root, 4)
|
||||
_build_transition_table(ctx, node.left)
|
||||
_build_transition_table(ctx, node.right)
|
||||
|
||||
def huffman_tree_build_transition_table(ctx):
|
||||
_build_transition_table(ctx, ctx.root)
|
||||
|
||||
NGHTTP2_HUFF_ACCEPTED = 1
|
||||
NGHTTP2_HUFF_SYM = 1 << 1
|
||||
NGHTTP2_HUFF_FAIL = 1 << 2
|
||||
|
||||
def dfs_print(node):
|
||||
def _print_transition_table(node):
|
||||
if node.term is not None:
|
||||
return
|
||||
print '/* {} */'.format(node.id)
|
||||
print '{'
|
||||
for nd, bits, syms in node.trans:
|
||||
outlen = len(syms)
|
||||
for nd, sym in node.trans:
|
||||
flags = 0
|
||||
if outlen == 0:
|
||||
if sym is None:
|
||||
out = 0
|
||||
else:
|
||||
assert(outlen == 1)
|
||||
out = syms[0]
|
||||
out = sym
|
||||
flags |= NGHTTP2_HUFF_SYM
|
||||
if nd is None:
|
||||
id = 0
|
||||
@@ -122,52 +386,50 @@ def dfs_print(node):
|
||||
flags |= NGHTTP2_HUFF_ACCEPTED
|
||||
print ' {{{}, 0x{:02x}, {}}},'.format(id, flags, out)
|
||||
print '},'
|
||||
dfs_print(node.left)
|
||||
dfs_print(node.right)
|
||||
_print_transition_table(node.left)
|
||||
_print_transition_table(node.right)
|
||||
|
||||
symbol_tbl = [(None, 0) for i in range(257)]
|
||||
tables = {}
|
||||
def huffman_tree_print_transition_table(ctx):
|
||||
_print_transition_table(ctx.root)
|
||||
|
||||
root = Node()
|
||||
if __name__ == '__main__':
|
||||
ctx = Context()
|
||||
symbol_tbl = [(None, 0) for i in range(257)]
|
||||
|
||||
for line in sys.stdin:
|
||||
m = re.match(r'.*\(\s*(\d+)\)\s+([|01]+)\s+(\S+)\s+\[\s*(\d+)\].*', line)
|
||||
for line in StringIO.StringIO(HUFFMAN_CODE_TABLE):
|
||||
m = re.match(
|
||||
r'.*\(\s*(\d+)\)\s+([|01]+)\s+(\S+)\s+\[\s*(\d+)\].*', line)
|
||||
if m:
|
||||
#print m.group(1), m.group(2), m.group(4)
|
||||
if len(m.group(3)) > 8:
|
||||
raise Error('Code is more than 4 bytes long')
|
||||
sym = int(m.group(1))
|
||||
bits = re.sub(r'\|', '', m.group(2))
|
||||
code = m.group(3)
|
||||
nbits = int(m.group(4))
|
||||
if len(code) > 8:
|
||||
raise Error('Code is more than 4 bytes long')
|
||||
assert(len(bits) == nbits)
|
||||
binpat = to_bin(bits)
|
||||
assert(len(binpat) == (nbits+7)/8)
|
||||
symbol_tbl[sym] = (binpat, nbits, m.group(3))
|
||||
#print "Inserting", sym
|
||||
insert(root, sym, bits)
|
||||
symbol_tbl[sym] = (nbits, code)
|
||||
huffman_tree_add(ctx, sym, bits)
|
||||
|
||||
dfs_setid(root, [])
|
||||
dfs(root, root)
|
||||
huffman_tree_set_node_id(ctx)
|
||||
huffman_tree_build_transition_table(ctx)
|
||||
|
||||
print '''\
|
||||
print '''\
|
||||
typedef struct {
|
||||
uint32_t nbits;
|
||||
uint32_t code;
|
||||
} nghttp2_huff_sym;
|
||||
'''
|
||||
|
||||
print '''\
|
||||
print '''\
|
||||
const nghttp2_huff_sym huff_sym_table[] = {'''
|
||||
for i in range(257):
|
||||
pat = list(symbol_tbl[i][0])
|
||||
pat += [0]*(4 - len(pat))
|
||||
for i in range(257):
|
||||
print '''\
|
||||
{{ {}, 0x{}u }}{}\
|
||||
'''.format(symbol_tbl[i][1], symbol_tbl[i][2], ',' if i < 256 else '')
|
||||
print '};'
|
||||
print ''
|
||||
'''.format(symbol_tbl[i][0], symbol_tbl[i][1], ',' if i < 256 else '')
|
||||
print '};'
|
||||
print ''
|
||||
|
||||
print '''\
|
||||
print '''\
|
||||
enum {{
|
||||
NGHTTP2_HUFF_ACCEPTED = {},
|
||||
NGHTTP2_HUFF_SYM = {},
|
||||
@@ -175,7 +437,7 @@ enum {{
|
||||
}} nghttp2_huff_decode_flag;
|
||||
'''.format(NGHTTP2_HUFF_ACCEPTED, NGHTTP2_HUFF_SYM, NGHTTP2_HUFF_FAIL)
|
||||
|
||||
print '''\
|
||||
print '''\
|
||||
typedef struct {
|
||||
uint8_t state;
|
||||
uint8_t flags;
|
||||
@@ -183,7 +445,7 @@ typedef struct {
|
||||
} nghttp2_huff_decode;
|
||||
'''
|
||||
|
||||
print '''\
|
||||
print '''\
|
||||
const nghttp2_huff_decode huff_decode_table[][16] = {'''
|
||||
dfs_print(root)
|
||||
print '};'
|
||||
huffman_tree_print_transition_table(ctx)
|
||||
print '};'
|
||||
|
||||
@@ -10,39 +10,17 @@
|
||||
from __future__ import unicode_literals
|
||||
import re, sys
|
||||
|
||||
def hash(s):
|
||||
h = 0
|
||||
for c in s:
|
||||
h = h * 31 + ord(c)
|
||||
return h & ((1 << 32) - 1)
|
||||
|
||||
entries = []
|
||||
for line in sys.stdin:
|
||||
m = re.match(r'(\d+)\s+(\S+)\s+(\S.*)?', line)
|
||||
val = m.group(3).strip() if m.group(3) else ''
|
||||
entries.append((hash(m.group(2)), int(m.group(1)), m.group(2), val))
|
||||
|
||||
entries.sort()
|
||||
|
||||
print '/* Sorted by hash(name) and its table index */'
|
||||
print 'static nghttp2_hd_static_entry static_table[] = {'
|
||||
for ent in entries:
|
||||
print 'MAKE_STATIC_ENT({}, "{}", "{}", {}u, {}u),'\
|
||||
.format(ent[1] - 1, ent[2], ent[3], ent[0], hash(ent[3]))
|
||||
print '};'
|
||||
|
||||
print ''
|
||||
|
||||
print '/* Index to the position in static_table */'
|
||||
print 'const size_t static_table_index[] = {'
|
||||
for i in range(len(entries)):
|
||||
for j, ent in enumerate(entries):
|
||||
if ent[1] - 1 == i:
|
||||
sys.stdout.write('{: <2d},'.format(j))
|
||||
break
|
||||
if (i + 1) % 16 == 0:
|
||||
sys.stdout.write('\n')
|
||||
else:
|
||||
sys.stdout.write(' ')
|
||||
entries.append((int(m.group(1)), m.group(2), val))
|
||||
|
||||
print 'static nghttp2_hd_entry static_table[] = {'
|
||||
idx = 0
|
||||
for i, ent in enumerate(entries):
|
||||
if entries[idx][1] != ent[1]:
|
||||
idx = i
|
||||
print 'MAKE_STATIC_ENT("{}", "{}", {}),'\
|
||||
.format(ent[1], ent[2], entries[idx][0] - 1)
|
||||
print '};'
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# * The options which do not take argument in the command-line *take*
|
||||
# argument in the configuration file. Specify 'yes' as argument
|
||||
# (e.g., spdy-proxy=yes). If other string is given, it disables the
|
||||
# (e.g., http2-proxy=yes). If other string is given, it disables the
|
||||
# option.
|
||||
#
|
||||
# * To specify private key and certificate file, use private-key-file
|
||||
@@ -25,5 +25,5 @@
|
||||
# backend=127.0.0.1,80
|
||||
# private-key-file=/path/to/server.key
|
||||
# certificate-file=/path/to/server.crt
|
||||
# spdy-proxy=no
|
||||
# http2-proxy=no
|
||||
# workers=1
|
||||
|
||||
4
python/.gitignore
vendored
Normal file
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:
|
||||
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
|
||||
NGHTTP2_ERR_DEFERRED
|
||||
|
||||
ctypedef enum nghttp2_flag:
|
||||
NGHTTP2_FLAG_NONE
|
||||
@@ -282,6 +283,9 @@ cdef extern from 'nghttp2/nghttp2.h':
|
||||
int nghttp2_session_terminate_session(nghttp2_session *session,
|
||||
uint32_t error_code)
|
||||
|
||||
int nghttp2_session_resume_data(nghttp2_session *session,
|
||||
int32_t stream_id)
|
||||
|
||||
const char* nghttp2_strerror(int lib_error_code)
|
||||
|
||||
int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
|
||||
|
||||
@@ -258,19 +258,35 @@ try:
|
||||
except ImportError:
|
||||
asyncio = None
|
||||
|
||||
# body generator flags
|
||||
DATA_OK = 0
|
||||
DATA_EOF = 1
|
||||
DATA_DEFERRED = 2
|
||||
|
||||
class _ByteIOWrapper:
|
||||
|
||||
def __init__(self, b):
|
||||
self.b = b
|
||||
|
||||
def generate(self, n):
|
||||
data = self.b.read1(n)
|
||||
if not data:
|
||||
return None, DATA_EOF
|
||||
return data, DATA_OK
|
||||
|
||||
def wrap_body(body):
|
||||
if body is None:
|
||||
return body
|
||||
elif isinstance(body, str):
|
||||
return io.BytesIO(body.encode('utf-8'))
|
||||
return _ByteIOWrapper(io.BytesIO(body.encode('utf-8'))).generate
|
||||
elif isinstance(body, bytes):
|
||||
return io.BytesIO(body)
|
||||
return _ByteIOWrapper(io.BytesIO(body)).generate
|
||||
elif isinstance(body, io.IOBase):
|
||||
return body
|
||||
return _ByteIOWrapper(body).generate
|
||||
else:
|
||||
raise Exception(('body must be None or instance of str or '
|
||||
'bytes or io.IOBase'))
|
||||
|
||||
# assume that callable in the form f(n) returning tuple byte
|
||||
# string and flag.
|
||||
return body
|
||||
|
||||
cdef _get_stream_user_data(cnghttp2.nghttp2_session *session,
|
||||
int32_t stream_id):
|
||||
@@ -488,29 +504,39 @@ cdef int on_stream_close(cnghttp2.nghttp2_session *session,
|
||||
|
||||
return 0
|
||||
|
||||
cdef ssize_t server_data_source_read(cnghttp2.nghttp2_session *session,
|
||||
cdef ssize_t data_source_read(cnghttp2.nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint8_t *buf, size_t length,
|
||||
uint32_t *data_flags,
|
||||
cnghttp2.nghttp2_data_source *source,
|
||||
void *user_data):
|
||||
cdef http2 = <_HTTP2SessionCore>user_data
|
||||
handler = <object>source.ptr
|
||||
cdef http2 = <_HTTP2SessionCoreBase>user_data
|
||||
generator = <object>source.ptr
|
||||
|
||||
http2.enter_callback()
|
||||
try:
|
||||
data = handler.response_body.read(length)
|
||||
data, flag = generator(length)
|
||||
except:
|
||||
sys.stderr.write(traceback.format_exc())
|
||||
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
finally:
|
||||
http2.leave_callback()
|
||||
|
||||
if flag == DATA_DEFERRED:
|
||||
return cnghttp2.NGHTTP2_ERR_DEFERRED
|
||||
|
||||
if data:
|
||||
nread = len(data)
|
||||
memcpy(buf, <uint8_t*>data, nread)
|
||||
return nread
|
||||
else:
|
||||
nread = 0
|
||||
|
||||
if flag == DATA_EOF:
|
||||
data_flags[0] = cnghttp2.NGHTTP2_DATA_FLAG_EOF
|
||||
elif flag != DATA_OK:
|
||||
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
|
||||
|
||||
return 0
|
||||
return nread
|
||||
|
||||
cdef int client_on_begin_headers(cnghttp2.nghttp2_session *session,
|
||||
const cnghttp2.nghttp2_frame *frame,
|
||||
@@ -595,36 +621,13 @@ cdef int client_on_frame_send(cnghttp2.nghttp2_session *session,
|
||||
return 0
|
||||
http2._start_settings_timer()
|
||||
|
||||
cdef ssize_t client_data_source_read(cnghttp2.nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint8_t *buf, size_t length,
|
||||
uint32_t *data_flags,
|
||||
cnghttp2.nghttp2_data_source *source,
|
||||
void *user_data):
|
||||
cdef http2 = <_HTTP2ClientSessionCore>user_data
|
||||
body = <object>source.ptr
|
||||
|
||||
try:
|
||||
data = body.read(length)
|
||||
except:
|
||||
sys.stderr.write(traceback.format_exc())
|
||||
return cnghttp2.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
|
||||
if data:
|
||||
nread = len(data)
|
||||
memcpy(buf, <uint8_t*>data, nread)
|
||||
return nread
|
||||
|
||||
data_flags[0] = cnghttp2.NGHTTP2_DATA_FLAG_EOF
|
||||
|
||||
return 0
|
||||
|
||||
cdef class _HTTP2SessionCoreBase:
|
||||
cdef cnghttp2.nghttp2_session *session
|
||||
cdef transport
|
||||
cdef handler_class
|
||||
cdef handlers
|
||||
cdef settings_timer
|
||||
cdef inside_callback
|
||||
|
||||
def __cinit__(self, transport, handler_class=None):
|
||||
self.session = NULL
|
||||
@@ -632,6 +635,7 @@ cdef class _HTTP2SessionCoreBase:
|
||||
self.handler_class = handler_class
|
||||
self.handlers = set()
|
||||
self.settings_timer = None
|
||||
self.inside_callback = False
|
||||
|
||||
def __dealloc__(self):
|
||||
cnghttp2.nghttp2_session_del(self.session)
|
||||
@@ -668,6 +672,17 @@ cdef class _HTTP2SessionCoreBase:
|
||||
cnghttp2.nghttp2_session_want_write(self.session) == 0:
|
||||
self.transport.close()
|
||||
|
||||
def resume(self, stream_id):
|
||||
cnghttp2.nghttp2_session_resume_data(self.session, stream_id)
|
||||
if not self.inside_callback:
|
||||
self.send_data()
|
||||
|
||||
def enter_callback(self):
|
||||
self.inside_callback = True
|
||||
|
||||
def leave_callback(self):
|
||||
self.inside_callback = False
|
||||
|
||||
def _make_handler(self, stream_id):
|
||||
logging.debug('_make_handler, stream_id:%s', stream_id)
|
||||
handler = self.handler_class(self, stream_id)
|
||||
@@ -815,8 +830,8 @@ cdef class _HTTP2SessionCore(_HTTP2SessionCoreBase):
|
||||
nvlen = _make_nva(&nva, handler.response_headers)
|
||||
|
||||
if handler.response_body:
|
||||
prd.source.ptr = <void*>handler
|
||||
prd.read_callback = server_data_source_read
|
||||
prd.source.ptr = <void*>handler.response_body
|
||||
prd.read_callback = data_source_read
|
||||
prd_ptr = &prd
|
||||
else:
|
||||
prd_ptr = NULL
|
||||
@@ -921,8 +936,8 @@ cdef class _HTTP2ClientSessionCore(_HTTP2SessionCoreBase):
|
||||
|
||||
custom_headers = _encode_headers(headers)
|
||||
headers = [
|
||||
(b':scheme', scheme.encode('utf-8')),
|
||||
(b':method', method.encode('utf-8')),
|
||||
(b':scheme', scheme.encode('utf-8')),
|
||||
(b':authority', host.encode('utf-8')),
|
||||
(b':path', path.encode('utf-8'))
|
||||
]
|
||||
@@ -933,7 +948,7 @@ cdef class _HTTP2ClientSessionCore(_HTTP2SessionCoreBase):
|
||||
|
||||
if body:
|
||||
prd.source.ptr = <void*>body
|
||||
prd.read_callback = client_data_source_read
|
||||
prd.read_callback = data_source_read
|
||||
prd_ptr = &prd
|
||||
else:
|
||||
prd_ptr = NULL
|
||||
@@ -1095,8 +1110,26 @@ if asyncio:
|
||||
additional response headers. The :status header field is
|
||||
appended by the library. The body is the response body. It
|
||||
could be None if response body is empty. Or it must be
|
||||
instance of either str, bytes or io.IOBase. If instance of str
|
||||
is specified, it is encoded using UTF-8.
|
||||
instance of either str, bytes, io.IOBase or callable,
|
||||
called body generator, which takes one parameter,
|
||||
size. The body generator generates response body. It can
|
||||
pause generation of response so that it can wait for slow
|
||||
backend data generation. When invoked, it should return
|
||||
tuple, byte string and flag. The flag is either DATA_OK,
|
||||
DATA_EOF and DATA_DEFERRED. For non-empty byte string and
|
||||
it is not the last chunk of response, DATA_OK is returned
|
||||
as flag. If this is the last chunk of the response (byte
|
||||
string is possibly None), DATA_EOF must be returned as
|
||||
flag. If there is no data available right now, but
|
||||
additional data are anticipated, return tuple (None,
|
||||
DATA_DEFERRD). When data arrived, call resume() and
|
||||
restart response body transmission.
|
||||
|
||||
Only the body generator can pause response body
|
||||
generation; instance of io.IOBase must not block.
|
||||
|
||||
If instance of str is specified as body, it is encoded
|
||||
using UTF-8.
|
||||
|
||||
The headers is a list of tuple of the form (name,
|
||||
value). The name and value can be either unicode string or
|
||||
@@ -1129,11 +1162,9 @@ if asyncio:
|
||||
request_headers parameter).
|
||||
|
||||
The status is HTTP status code. The headers is additional
|
||||
response headers. The :status header field is appended by the
|
||||
library. The body is the response body. It could be None if
|
||||
response body is empty. Or it must be instance of either str,
|
||||
bytes or io.IOBase. If instance of str is specified, it is
|
||||
encoded using UTF-8.
|
||||
response headers. The :status header field is appended by
|
||||
the library. The body is the response body. It has the
|
||||
same semantics of body parameter of send_response().
|
||||
|
||||
The headers and request_headers are a list of tuple of the
|
||||
form (name, value). The name and value can be either
|
||||
@@ -1161,16 +1192,15 @@ if asyncio:
|
||||
promised_handler.path = path.encode('utf-8')
|
||||
promised_handler._set_response_prop(status, headers, body)
|
||||
|
||||
if request_headers is None:
|
||||
request_headers = []
|
||||
headers = [
|
||||
(b':method', promised_handler.method),
|
||||
(b':scheme', promised_handler.scheme),
|
||||
(b':authority', promised_handler.host),
|
||||
(b':path', promised_handler.path)
|
||||
]
|
||||
headers.extend(_encode_headers(request_headers))
|
||||
|
||||
request_headers = _encode_headers(request_headers)
|
||||
request_headers.append((b':scheme', promised_handler.scheme))
|
||||
request_headers.append((b':method', promised_handler.method))
|
||||
request_headers.append((b':authority', promised_handler.host))
|
||||
request_headers.append((b':path', promised_handler.path))
|
||||
|
||||
promised_handler.headers = request_headers
|
||||
promised_handler.headers = headers
|
||||
|
||||
return self.http2.push(self, promised_handler)
|
||||
|
||||
@@ -1180,12 +1210,14 @@ if asyncio:
|
||||
if headers is None:
|
||||
headers = []
|
||||
|
||||
self.response_headers = _encode_headers(headers)
|
||||
self.response_headers.append((b':status', str(status)\
|
||||
.encode('utf-8')))
|
||||
self.response_headers = [(b':status', str(status).encode('utf-8'))]
|
||||
self.response_headers.extend(_encode_headers(headers))
|
||||
|
||||
self.response_body = body
|
||||
|
||||
def resume(self):
|
||||
self.http2.resume(self.stream_id)
|
||||
|
||||
def _encode_headers(headers):
|
||||
if not headers:
|
||||
return []
|
||||
@@ -1432,6 +1464,9 @@ if asyncio:
|
||||
'''
|
||||
self.http2.push(push_promise, handler)
|
||||
|
||||
def resume(self):
|
||||
self.http2.resume(self.stream_id)
|
||||
|
||||
class _HTTP2ClientSession(asyncio.Protocol):
|
||||
|
||||
def __init__(self, client):
|
||||
|
||||
@@ -36,7 +36,7 @@ setup(
|
||||
author = 'Tatsuhiro Tsujikawa',
|
||||
version = '@PACKAGE_VERSION@',
|
||||
author_email = 'tatsuhiro.t@gmail.com',
|
||||
url = 'http://tatsuhiro-t.github.io/nghttp2/',
|
||||
url = 'https://nghttp2.org/',
|
||||
keywords = [],
|
||||
ext_modules = [Extension("nghttp2",
|
||||
["nghttp2.c"],
|
||||
|
||||
20
src/.gitignore
vendored
20
src/.gitignore
vendored
@@ -1,12 +1,16 @@
|
||||
# generated files
|
||||
libnghttp2_asio.pc
|
||||
|
||||
# programs
|
||||
deflatehd
|
||||
h2load
|
||||
inflatehd
|
||||
nghttp
|
||||
nghttpd
|
||||
nghttpx
|
||||
nghttpx-unittest
|
||||
nghttpx-unittest.log
|
||||
nghttpx-unittest.trs
|
||||
test-suite.log
|
||||
.dirstamp
|
||||
|
||||
# build
|
||||
libnghttpx.a
|
||||
deflatehd
|
||||
inflatehd
|
||||
h2load
|
||||
|
||||
# tests
|
||||
nghttpx-unittest
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
ParserData::ParserData(const std::string &base_uri) : base_uri(base_uri) {}
|
||||
ParserData::ParserData(const std::string &base_uri)
|
||||
: base_uri(base_uri), inside_head(0) {}
|
||||
|
||||
HtmlParser::HtmlParser(const std::string &base_uri)
|
||||
: base_uri_(base_uri), parser_ctx_(nullptr), parser_data_(base_uri) {}
|
||||
@@ -52,13 +53,13 @@ const char *get_attr(const xmlChar **attrs, const char *name) {
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void add_link(ParserData *parser_data, const char *uri, RequestPriority pri) {
|
||||
void add_link(ParserData *parser_data, const char *uri, ResourceType res_type) {
|
||||
auto u = xmlBuildURI(
|
||||
reinterpret_cast<const xmlChar *>(uri),
|
||||
reinterpret_cast<const xmlChar *>(parser_data->base_uri.c_str()));
|
||||
if (u) {
|
||||
parser_data->links.push_back(
|
||||
std::make_pair(reinterpret_cast<char *>(u), pri));
|
||||
std::make_pair(reinterpret_cast<char *>(u), res_type));
|
||||
free(u);
|
||||
}
|
||||
}
|
||||
@@ -68,6 +69,9 @@ namespace {
|
||||
void start_element_func(void *user_data, const xmlChar *name,
|
||||
const xmlChar **attrs) {
|
||||
auto parser_data = static_cast<ParserData *>(user_data);
|
||||
if (util::strieq(reinterpret_cast<const char *>(name), "head")) {
|
||||
++parser_data->inside_head;
|
||||
}
|
||||
if (util::strieq(reinterpret_cast<const char *>(name), "link")) {
|
||||
auto rel_attr = get_attr(attrs, "rel");
|
||||
auto href_attr = get_attr(attrs, "href");
|
||||
@@ -75,22 +79,35 @@ void start_element_func(void *user_data, const xmlChar *name,
|
||||
return;
|
||||
}
|
||||
if (util::strieq(rel_attr, "shortcut icon")) {
|
||||
add_link(parser_data, href_attr, REQ_PRI_LOWEST);
|
||||
add_link(parser_data, href_attr, REQ_OTHERS);
|
||||
} else if (util::strieq(rel_attr, "stylesheet")) {
|
||||
add_link(parser_data, href_attr, REQ_PRI_MEDIUM);
|
||||
add_link(parser_data, href_attr, REQ_CSS);
|
||||
}
|
||||
} else if (util::strieq(reinterpret_cast<const char *>(name), "img")) {
|
||||
auto src_attr = get_attr(attrs, "src");
|
||||
if (!src_attr) {
|
||||
return;
|
||||
}
|
||||
add_link(parser_data, src_attr, REQ_PRI_LOWEST);
|
||||
add_link(parser_data, src_attr, REQ_IMG);
|
||||
} else if (util::strieq(reinterpret_cast<const char *>(name), "script")) {
|
||||
auto src_attr = get_attr(attrs, "src");
|
||||
if (!src_attr) {
|
||||
return;
|
||||
}
|
||||
add_link(parser_data, src_attr, REQ_PRI_LOW);
|
||||
if (parser_data->inside_head) {
|
||||
add_link(parser_data, src_attr, REQ_JS);
|
||||
} else {
|
||||
add_link(parser_data, src_attr, REQ_UNBLOCK_JS);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void end_element_func(void *user_data, const xmlChar *name) {
|
||||
auto parser_data = static_cast<ParserData *>(user_data);
|
||||
if (util::strieq(reinterpret_cast<const char *>(name), "head")) {
|
||||
--parser_data->inside_head;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
@@ -112,7 +129,7 @@ xmlSAXHandler saxHandler = {
|
||||
nullptr, // startDocumentSAXFunc
|
||||
nullptr, // endDocumentSAXFunc
|
||||
&start_element_func, // startElementSAXFunc
|
||||
nullptr, // endElementSAXFunc
|
||||
&end_element_func, // endElementSAXFunc
|
||||
nullptr, // referenceSAXFunc
|
||||
nullptr, // charactersSAXFunc
|
||||
nullptr, // ignorableWhitespaceSAXFunc
|
||||
@@ -160,7 +177,7 @@ int HtmlParser::parse_chunk_internal(const char *chunk, size_t size, int fin) {
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, RequestPriority>> &
|
||||
const std::vector<std::pair<std::string, ResourceType>> &
|
||||
HtmlParser::get_links() const {
|
||||
return parser_data_.links;
|
||||
}
|
||||
|
||||
@@ -38,16 +38,19 @@
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
enum RequestPriority {
|
||||
REQ_PRI_HIGH = 0,
|
||||
REQ_PRI_MEDIUM = 1,
|
||||
REQ_PRI_LOW = 2,
|
||||
REQ_PRI_LOWEST = 3
|
||||
enum ResourceType {
|
||||
REQ_CSS = 1,
|
||||
REQ_JS,
|
||||
REQ_UNBLOCK_JS,
|
||||
REQ_IMG,
|
||||
REQ_OTHERS,
|
||||
};
|
||||
|
||||
struct ParserData {
|
||||
std::string base_uri;
|
||||
std::vector<std::pair<std::string, RequestPriority>> links;
|
||||
std::vector<std::pair<std::string, ResourceType>> links;
|
||||
// > 0 if we are inside "head" element.
|
||||
int inside_head;
|
||||
ParserData(const std::string &base_uri);
|
||||
};
|
||||
|
||||
@@ -58,7 +61,7 @@ public:
|
||||
HtmlParser(const std::string &base_uri);
|
||||
~HtmlParser();
|
||||
int parse_chunk(const char *chunk, size_t size, int fin);
|
||||
const std::vector<std::pair<std::string, RequestPriority>> &get_links() const;
|
||||
const std::vector<std::pair<std::string, ResourceType>> &get_links() const;
|
||||
void clear_links();
|
||||
|
||||
private:
|
||||
@@ -75,14 +78,13 @@ class HtmlParser {
|
||||
public:
|
||||
HtmlParser(const std::string &base_uri) {}
|
||||
int parse_chunk(const char *chunk, size_t size, int fin) { return 0; }
|
||||
const std::vector<std::pair<std::string, RequestPriority>> &
|
||||
get_links() const {
|
||||
const std::vector<std::pair<std::string, ResourceType>> &get_links() const {
|
||||
return links_;
|
||||
}
|
||||
void clear_links() {}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::string, RequestPriority>> links_;
|
||||
std::vector<std::pair<std::string, ResourceType>> links_;
|
||||
};
|
||||
|
||||
#endif // !HAVE_LIBXML2
|
||||
|
||||
@@ -57,11 +57,6 @@
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace {
|
||||
const std::string STATUS_200 = "200";
|
||||
const std::string STATUS_301 = "301";
|
||||
const std::string STATUS_304 = "304";
|
||||
const std::string STATUS_400 = "400";
|
||||
const std::string STATUS_404 = "404";
|
||||
const std::string DEFAULT_HTML = "index.html";
|
||||
const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION;
|
||||
} // namespace
|
||||
@@ -94,9 +89,9 @@ template <typename Array> void append_nv(Stream *stream, const Array &nva) {
|
||||
Config::Config()
|
||||
: stream_read_timeout(60.), stream_write_timeout(60.),
|
||||
session_option(nullptr), data_ptr(nullptr), padding(0), num_worker(1),
|
||||
header_table_size(-1), port(0), verbose(false), daemon(false),
|
||||
verify_client(false), no_tls(false), error_gzip(false),
|
||||
early_response(false) {
|
||||
max_concurrent_streams(100), header_table_size(-1), port(0),
|
||||
verbose(false), daemon(false), verify_client(false), no_tls(false),
|
||||
error_gzip(false), early_response(false), hexdump(false) {
|
||||
nghttp2_option_new(&session_option);
|
||||
nghttp2_option_set_recv_client_preface(session_option, 1);
|
||||
}
|
||||
@@ -171,9 +166,10 @@ void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config);
|
||||
|
||||
class Sessions {
|
||||
public:
|
||||
Sessions(struct ev_loop *loop, const Config *config, SSL_CTX *ssl_ctx)
|
||||
: loop_(loop), config_(config), ssl_ctx_(ssl_ctx), callbacks_(nullptr),
|
||||
next_session_id_(1), tstamp_cached_(ev_now(loop)),
|
||||
Sessions(HttpServer *sv, struct ev_loop *loop, const Config *config,
|
||||
SSL_CTX *ssl_ctx)
|
||||
: sv_(sv), loop_(loop), config_(config), ssl_ctx_(ssl_ctx),
|
||||
callbacks_(nullptr), next_session_id_(1), tstamp_cached_(ev_now(loop)),
|
||||
cached_date_(util::http_date(tstamp_cached_)) {
|
||||
nghttp2_session_callbacks_new(&callbacks_);
|
||||
|
||||
@@ -229,7 +225,7 @@ public:
|
||||
make_unique<Http2Handler>(this, fd, ssl, get_next_session_id());
|
||||
handler->setup_bev();
|
||||
if (!ssl) {
|
||||
if (handler->on_connect() != 0) {
|
||||
if (handler->connection_made() != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -244,9 +240,37 @@ public:
|
||||
}
|
||||
return cached_date_;
|
||||
}
|
||||
FileEntry *get_cached_fd(const std::string &path) {
|
||||
auto i = fd_cache_.find(path);
|
||||
if (i == std::end(fd_cache_)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto &ent = (*i).second;
|
||||
++ent.usecount;
|
||||
return &ent;
|
||||
}
|
||||
FileEntry *cache_fd(const std::string &path, const FileEntry &ent) {
|
||||
auto rv = fd_cache_.emplace(path, ent);
|
||||
return &(*rv.first).second;
|
||||
}
|
||||
void release_fd(const std::string &path) {
|
||||
auto i = fd_cache_.find(path);
|
||||
if (i == std::end(fd_cache_)) {
|
||||
return;
|
||||
}
|
||||
auto &ent = (*i).second;
|
||||
if (--ent.usecount == 0) {
|
||||
close(ent.fd);
|
||||
fd_cache_.erase(i);
|
||||
}
|
||||
}
|
||||
const HttpServer *get_server() const { return sv_; }
|
||||
|
||||
private:
|
||||
std::set<Http2Handler *> handlers_;
|
||||
// cache for file descriptors to read file.
|
||||
std::map<std::string, FileEntry> fd_cache_;
|
||||
HttpServer *sv_;
|
||||
struct ev_loop *loop_;
|
||||
const Config *config_;
|
||||
SSL_CTX *ssl_ctx_;
|
||||
@@ -257,7 +281,8 @@ private:
|
||||
};
|
||||
|
||||
Stream::Stream(Http2Handler *handler, int32_t stream_id)
|
||||
: handler(handler), body_left(0), stream_id(stream_id), file(-1) {
|
||||
: handler(handler), file_ent(nullptr), body_length(0), body_offset(0),
|
||||
stream_id(stream_id) {
|
||||
auto config = handler->get_config();
|
||||
ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
|
||||
ev_timer_init(&wtimer, stream_timeout_cb, 0., config->stream_write_timeout);
|
||||
@@ -270,8 +295,9 @@ Stream::Stream(Http2Handler *handler, int32_t stream_id)
|
||||
}
|
||||
|
||||
Stream::~Stream() {
|
||||
if (file != -1) {
|
||||
close(file);
|
||||
if (file_ent != nullptr) {
|
||||
auto sessions = handler->get_sessions();
|
||||
sessions->release_fd(file_ent->path);
|
||||
}
|
||||
|
||||
auto loop = handler->get_loop();
|
||||
@@ -371,6 +397,8 @@ struct ev_loop *Http2Handler::get_loop() const {
|
||||
return sessions_->get_loop();
|
||||
}
|
||||
|
||||
Http2Handler::WriteBuf *Http2Handler::get_wb() { return &wb_; }
|
||||
|
||||
int Http2Handler::setup_bev() { return 0; }
|
||||
|
||||
int Http2Handler::fill_wb() {
|
||||
@@ -426,6 +454,11 @@ int Http2Handler::read_clear() {
|
||||
if (nread == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_config()->hexdump) {
|
||||
util::hexdump(stdout, buf.data(), nread);
|
||||
}
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
|
||||
if (rv < 0) {
|
||||
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
|
||||
@@ -515,7 +548,7 @@ int Http2Handler::tls_handshake() {
|
||||
read_ = &Http2Handler::read_tls;
|
||||
write_ = &Http2Handler::write_tls;
|
||||
|
||||
if (on_connect() != 0) {
|
||||
if (connection_made() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -548,6 +581,11 @@ int Http2Handler::read_tls() {
|
||||
}
|
||||
|
||||
auto nread = rv;
|
||||
|
||||
if (get_config()->hexdump) {
|
||||
util::hexdump(stdout, buf.data(), nread);
|
||||
}
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
|
||||
if (rv < 0) {
|
||||
if (rv != NGHTTP2_ERR_BAD_PREFACE) {
|
||||
@@ -619,11 +657,13 @@ int Http2Handler::on_read() { return read_(*this); }
|
||||
|
||||
int Http2Handler::on_write() { return write_(*this); }
|
||||
|
||||
int Http2Handler::on_connect() {
|
||||
int Http2Handler::connection_made() {
|
||||
int r;
|
||||
|
||||
auto config = sessions_->get_config();
|
||||
|
||||
r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
|
||||
sessions_->get_config()->session_option);
|
||||
config->session_option);
|
||||
if (r != 0) {
|
||||
return r;
|
||||
}
|
||||
@@ -631,11 +671,11 @@ int Http2Handler::on_connect() {
|
||||
size_t niv = 1;
|
||||
|
||||
entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||
entry[0].value = 100;
|
||||
entry[0].value = config->max_concurrent_streams;
|
||||
|
||||
if (sessions_->get_config()->header_table_size >= 0) {
|
||||
if (config->header_table_size >= 0) {
|
||||
entry[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||
entry[niv].value = sessions_->get_config()->header_table_size;
|
||||
entry[niv].value = config->header_table_size;
|
||||
++niv;
|
||||
}
|
||||
r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(), niv);
|
||||
@@ -823,21 +863,12 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
||||
auto hd = static_cast<Http2Handler *>(user_data);
|
||||
auto stream = hd->get_stream(stream_id);
|
||||
|
||||
int fd = source->fd;
|
||||
ssize_t nread;
|
||||
auto nread = std::min(stream->body_length - stream->body_offset,
|
||||
static_cast<int64_t>(length));
|
||||
|
||||
while ((nread = read(fd, buf, length)) == -1 && errno == EINTR)
|
||||
;
|
||||
*data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
|
||||
|
||||
if (nread == -1) {
|
||||
remove_stream_read_timeout(stream);
|
||||
remove_stream_write_timeout(stream);
|
||||
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
stream->body_left -= nread;
|
||||
if (nread == 0 || stream->body_left <= 0) {
|
||||
if (nread == 0 || stream->body_length == stream->body_offset + nread) {
|
||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||
|
||||
auto config = hd->get_config();
|
||||
@@ -869,59 +900,27 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
||||
}
|
||||
|
||||
namespace {
|
||||
void prepare_status_response(Stream *stream, Http2Handler *hd,
|
||||
const std::string &status) {
|
||||
int pipefd[2];
|
||||
if (status == STATUS_304 || pipe(pipefd) == -1) {
|
||||
hd->submit_response(status, stream->stream_id, 0);
|
||||
return;
|
||||
}
|
||||
std::string body;
|
||||
body.reserve(256);
|
||||
body = "<html><head><title>";
|
||||
body += status;
|
||||
body += "</title></head><body><h1>";
|
||||
body += status;
|
||||
body += "</h1><hr><address>";
|
||||
body += NGHTTPD_SERVER;
|
||||
body += " at port ";
|
||||
body += util::utos(hd->get_config()->port);
|
||||
body += "</address>";
|
||||
body += "</body></html>";
|
||||
void prepare_status_response(Stream *stream, Http2Handler *hd, int status) {
|
||||
auto sessions = hd->get_sessions();
|
||||
auto status_page = sessions->get_server()->get_status_page(status);
|
||||
auto file_ent = &status_page->file_ent;
|
||||
|
||||
// we don't set stream->file_ent since we don't want to expire it.
|
||||
stream->body_length = file_ent->length;
|
||||
nghttp2_data_provider data_prd;
|
||||
data_prd.source.fd = file_ent->fd;
|
||||
data_prd.read_callback = file_read_callback;
|
||||
|
||||
Headers headers;
|
||||
if (hd->get_config()->error_gzip) {
|
||||
gzFile write_fd = gzdopen(pipefd[1], "w");
|
||||
gzwrite(write_fd, body.c_str(), body.size());
|
||||
gzclose(write_fd);
|
||||
headers.emplace_back("content-encoding", "gzip");
|
||||
} else {
|
||||
ssize_t rv;
|
||||
|
||||
while ((rv = write(pipefd[1], body.c_str(), body.size())) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
|
||||
if (rv != static_cast<ssize_t>(body.size())) {
|
||||
std::cerr << "Could not write all response body: " << rv << std::endl;
|
||||
}
|
||||
}
|
||||
close(pipefd[1]);
|
||||
|
||||
stream->file = pipefd[0];
|
||||
stream->body_left = body.size();
|
||||
nghttp2_data_provider data_prd;
|
||||
data_prd.source.fd = pipefd[0];
|
||||
data_prd.read_callback = file_read_callback;
|
||||
headers.emplace_back("content-type", "text/html; charset=UTF-8");
|
||||
hd->submit_response(status, stream->stream_id, headers, &data_prd);
|
||||
hd->submit_response(status_page->status, stream->stream_id, headers,
|
||||
&data_prd);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void prepare_redirect_response(Stream *stream, Http2Handler *hd,
|
||||
const std::string &path,
|
||||
const std::string &status) {
|
||||
const std::string &path, int status) {
|
||||
auto scheme =
|
||||
http2::get_header(stream->hdidx, http2::HD__SCHEME, stream->headers);
|
||||
auto authority =
|
||||
@@ -938,7 +937,10 @@ void prepare_redirect_response(Stream *stream, Http2Handler *hd,
|
||||
|
||||
auto headers = Headers{{"location", redirect_url}};
|
||||
|
||||
hd->submit_response(status, stream->stream_id, headers, nullptr);
|
||||
auto sessions = hd->get_sessions();
|
||||
auto status_page = sessions->get_server()->get_status_page(status);
|
||||
|
||||
hd->submit_response(status_page->status, stream->stream_id, headers, nullptr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -972,7 +974,7 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
||||
|
||||
url = util::percentDecode(url.begin(), url.end());
|
||||
if (!util::check_path(url)) {
|
||||
prepare_status_response(stream, hd, STATUS_404);
|
||||
prepare_status_response(stream, hd, 404);
|
||||
return;
|
||||
}
|
||||
auto push_itr = hd->get_config()->push.find(url);
|
||||
@@ -989,9 +991,14 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
||||
if (path[path.size() - 1] == '/') {
|
||||
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);
|
||||
if (file == -1) {
|
||||
prepare_status_response(stream, hd, STATUS_404);
|
||||
prepare_status_response(stream, hd, 404);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1000,7 +1007,7 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
||||
|
||||
if (fstat(file, &buf) == -1) {
|
||||
close(file);
|
||||
prepare_status_response(stream, hd, STATUS_404);
|
||||
prepare_status_response(stream, hd, 404);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1014,26 +1021,36 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
||||
reqpath.insert(query_pos, "/");
|
||||
}
|
||||
|
||||
prepare_redirect_response(stream, hd, reqpath, STATUS_301);
|
||||
prepare_redirect_response(stream, hd, reqpath, 301);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
stream->file = file;
|
||||
stream->body_left = buf.st_size;
|
||||
if (last_mod_found && buf.st_mtime <= last_mod) {
|
||||
close(file);
|
||||
prepare_status_response(stream, hd, 304);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
file_ent = sessions->cache_fd(
|
||||
path, FileEntry(path, buf.st_size, buf.st_mtime, file));
|
||||
} else if (last_mod_found && file_ent->mtime <= last_mod) {
|
||||
sessions->release_fd(file_ent->path);
|
||||
prepare_status_response(stream, hd, 304);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
stream->file_ent = file_ent;
|
||||
stream->body_length = file_ent->length;
|
||||
|
||||
nghttp2_data_provider data_prd;
|
||||
|
||||
data_prd.source.fd = file;
|
||||
data_prd.source.fd = file_ent->fd;
|
||||
data_prd.read_callback = file_read_callback;
|
||||
|
||||
if (last_mod_found && buf.st_mtime <= last_mod) {
|
||||
prepare_status_response(stream, hd, STATUS_304);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
hd->submit_file_response(STATUS_200, stream, buf.st_mtime, buf.st_size,
|
||||
hd->submit_file_response("200", stream, file_ent->mtime, file_ent->length,
|
||||
&data_prd);
|
||||
}
|
||||
} // namespace
|
||||
@@ -1210,6 +1227,58 @@ int hd_on_frame_send_callback(nghttp2_session *session,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int send_data_callback(nghttp2_session *session, nghttp2_frame *frame,
|
||||
const uint8_t *framehd, size_t length,
|
||||
nghttp2_data_source *source, void *user_data) {
|
||||
auto hd = static_cast<Http2Handler *>(user_data);
|
||||
auto wb = hd->get_wb();
|
||||
auto padlen = frame->data.padlen;
|
||||
auto stream = hd->get_stream(frame->hd.stream_id);
|
||||
|
||||
if (wb->wleft() < 9 + length + padlen) {
|
||||
return NGHTTP2_ERR_WOULDBLOCK;
|
||||
}
|
||||
|
||||
int fd = source->fd;
|
||||
|
||||
auto p = wb->last;
|
||||
|
||||
p = std::copy_n(framehd, 9, p);
|
||||
|
||||
if (padlen) {
|
||||
*p++ = padlen - 1;
|
||||
}
|
||||
|
||||
while (length) {
|
||||
ssize_t nread;
|
||||
while ((nread = pread(fd, p, length, stream->body_offset)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
|
||||
if (nread == -1) {
|
||||
remove_stream_read_timeout(stream);
|
||||
remove_stream_write_timeout(stream);
|
||||
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
stream->body_offset += nread;
|
||||
length -= nread;
|
||||
p += nread;
|
||||
}
|
||||
|
||||
if (padlen) {
|
||||
std::fill(p, p + padlen - 1, 0);
|
||||
p += padlen - 1;
|
||||
}
|
||||
|
||||
wb->last = p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
ssize_t select_padding_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, size_t max_payload,
|
||||
@@ -1278,6 +1347,9 @@ void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config) {
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
callbacks, on_begin_headers_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_send_data_callback(callbacks,
|
||||
send_data_callback);
|
||||
|
||||
if (config->padding) {
|
||||
nghttp2_session_callbacks_set_select_padding_callback(
|
||||
callbacks, select_padding_callback);
|
||||
@@ -1324,7 +1396,7 @@ void run_worker(Worker *worker) {
|
||||
|
||||
class AcceptHandler {
|
||||
public:
|
||||
AcceptHandler(Sessions *sessions, const Config *config)
|
||||
AcceptHandler(HttpServer *sv, Sessions *sessions, const Config *config)
|
||||
: sessions_(sessions), config_(config), next_worker_(0) {
|
||||
if (config_->num_worker == 1) {
|
||||
return;
|
||||
@@ -1336,7 +1408,7 @@ public:
|
||||
auto worker = make_unique<Worker>();
|
||||
auto loop = ev_loop_new(0);
|
||||
worker->sessions =
|
||||
make_unique<Sessions>(loop, config_, sessions_->get_ssl_ctx());
|
||||
make_unique<Sessions>(sv, loop, config_, sessions_->get_ssl_ctx());
|
||||
ev_async_init(&worker->w, worker_acceptcb);
|
||||
worker->w.data = worker.get();
|
||||
ev_async_start(loop, &worker->w);
|
||||
@@ -1420,7 +1492,61 @@ void acceptcb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
HttpServer::HttpServer(const Config *config) : config_(config) {}
|
||||
namespace {
|
||||
FileEntry make_status_body(int status, uint16_t port) {
|
||||
std::string body;
|
||||
body = "<html><head><title>";
|
||||
body += http2::get_status_string(status);
|
||||
body += "</title></head><body><h1>";
|
||||
body += http2::get_status_string(status);
|
||||
body += "</h1><hr><address>";
|
||||
body += NGHTTPD_SERVER;
|
||||
body += " at port ";
|
||||
body += util::utos(port);
|
||||
body += "</address>";
|
||||
body += "</body></html>";
|
||||
|
||||
char tempfn[] = "/tmp/nghttpd.temp.XXXXXX";
|
||||
int fd = mkstemp(tempfn);
|
||||
if (fd == -1) {
|
||||
auto error = errno;
|
||||
std::cerr << "Could not open status response body file: errno=" << error;
|
||||
assert(0);
|
||||
}
|
||||
unlink(tempfn);
|
||||
ssize_t nwrite;
|
||||
while ((nwrite = write(fd, body.c_str(), body.size())) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
if (nwrite == -1) {
|
||||
auto error = errno;
|
||||
std::cerr << "Could not write status response body into file: errno="
|
||||
<< error;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return FileEntry(util::utos(status), nwrite, 0, fd);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// index into HttpServer::status_pages_
|
||||
enum {
|
||||
IDX_200,
|
||||
IDX_301,
|
||||
IDX_304,
|
||||
IDX_400,
|
||||
IDX_404,
|
||||
};
|
||||
|
||||
HttpServer::HttpServer(const Config *config) : config_(config) {
|
||||
status_pages_ = std::vector<StatusPage>{
|
||||
{"200", make_status_body(200, config_->port)},
|
||||
{"301", make_status_body(301, config_->port)},
|
||||
{"304", make_status_body(304, config_->port)},
|
||||
{"400", make_status_body(400, config_->port)},
|
||||
{"404", make_status_body(404, config_->port)},
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
|
||||
@@ -1441,14 +1567,14 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int start_listen(struct ev_loop *loop, Sessions *sessions,
|
||||
int start_listen(HttpServer *sv, struct ev_loop *loop, Sessions *sessions,
|
||||
const Config *config) {
|
||||
addrinfo hints;
|
||||
int r;
|
||||
bool ok = false;
|
||||
const char *addr = nullptr;
|
||||
|
||||
auto acceptor = std::make_shared<AcceptHandler>(sessions, config);
|
||||
auto acceptor = std::make_shared<AcceptHandler>(sv, sessions, config);
|
||||
auto service = util::utos(config->port);
|
||||
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
@@ -1643,8 +1769,8 @@ int HttpServer::run() {
|
||||
|
||||
auto loop = EV_DEFAULT;
|
||||
|
||||
Sessions sessions(loop, config_, ssl_ctx);
|
||||
if (start_listen(loop, &sessions, config_) != 0) {
|
||||
Sessions sessions(this, loop, config_, ssl_ctx);
|
||||
if (start_listen(this, loop, &sessions, config_) != 0) {
|
||||
std::cerr << "Could not listen" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
@@ -1655,4 +1781,22 @@ int HttpServer::run() {
|
||||
|
||||
const Config *HttpServer::get_config() const { return config_; }
|
||||
|
||||
const StatusPage *HttpServer::get_status_page(int status) const {
|
||||
switch (status) {
|
||||
case 200:
|
||||
return &status_pages_[IDX_200];
|
||||
case 301:
|
||||
return &status_pages_[IDX_301];
|
||||
case 304:
|
||||
return &status_pages_[IDX_304];
|
||||
case 400:
|
||||
return &status_pages_[IDX_400];
|
||||
case 404:
|
||||
return &status_pages_[IDX_404];
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user