mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-08 11:08:52 +08:00
Compare commits
381 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e74466231 | ||
|
|
478eac099f | ||
|
|
88e2029e37 | ||
|
|
45d76cf501 | ||
|
|
54573f28a8 | ||
|
|
17793e99dc | ||
|
|
5eac3c9025 | ||
|
|
e70195ae91 | ||
|
|
fe51e7fa1a | ||
|
|
eb951c2ce4 | ||
|
|
39f0ce7c25 | ||
|
|
65157811d4 | ||
|
|
e8af7afc65 | ||
|
|
38abfd1863 | ||
|
|
ff3edc09ed | ||
|
|
0bb1540682 | ||
|
|
f0836c7e39 | ||
|
|
25db178b7d | ||
|
|
1b6713e6ec | ||
|
|
c1a496cf4e | ||
|
|
e098a21132 | ||
|
|
0ba4bf51e4 | ||
|
|
6deee2037d | ||
|
|
6761a933fe | ||
|
|
5cc3d159e1 | ||
|
|
652f57e79d | ||
|
|
acd6b40e4c | ||
|
|
0fbb46edd6 | ||
|
|
6ad629de47 | ||
|
|
74754982f1 | ||
|
|
a31a2e3b2c | ||
|
|
a776b0dbcc | ||
|
|
cfd926f09b | ||
|
|
72f52716ae | ||
|
|
439b9b6c6a | ||
|
|
4849845292 | ||
|
|
d30f38163c | ||
|
|
cff9ebe1dd | ||
|
|
4d1139f653 | ||
|
|
48f574076c | ||
|
|
c1f14d73c7 | ||
|
|
216f4dad83 | ||
|
|
a4e27d766b | ||
|
|
96df14d2ec | ||
|
|
2365f12e39 | ||
|
|
96ea9cdaf7 | ||
|
|
03f7ec0f60 | ||
|
|
a941699962 | ||
|
|
2056e812bd | ||
|
|
04348ff20e | ||
|
|
d8e378fea9 | ||
|
|
1ebb6810a1 | ||
|
|
2a694b270a | ||
|
|
a3ebeeafba | ||
|
|
422ad1be32 | ||
|
|
97f1735cf5 | ||
|
|
939ad5ddbe | ||
|
|
24d92b979d | ||
|
|
4c92ff1843 | ||
|
|
280db5c6ba | ||
|
|
7fbcb2d005 | ||
|
|
53aeb2c3d7 | ||
|
|
ff200bfcf3 | ||
|
|
fee3151fd2 | ||
|
|
99a85159ae | ||
|
|
2a981a3f56 | ||
|
|
0028275d7b | ||
|
|
ee8bfddfc9 | ||
|
|
194acb1f2c | ||
|
|
43a2a70ae7 | ||
|
|
73344ae9aa | ||
|
|
c479f6122f | ||
|
|
eca0a3025b | ||
|
|
4720c5cb3d | ||
|
|
cd55ab28ab | ||
|
|
d402cfdf16 | ||
|
|
22502182d0 | ||
|
|
05e1fd5e77 | ||
|
|
943d7923f9 | ||
|
|
568ecbfb28 | ||
|
|
f5ddd7f43b | ||
|
|
88abbce7e7 | ||
|
|
16e9036568 | ||
|
|
fa7945c627 | ||
|
|
daca43f0dd | ||
|
|
16bc11e670 | ||
|
|
6f7e94cdba | ||
|
|
61efa15a14 | ||
|
|
8c0ea56bb8 | ||
|
|
549053710b | ||
|
|
6010d39325 | ||
|
|
be5c39a1cf | ||
|
|
b8fda6808b | ||
|
|
e29b9c1261 | ||
|
|
539e27812b | ||
|
|
7008afd40e | ||
|
|
77a41756db | ||
|
|
b15045d60e | ||
|
|
03084f7517 | ||
|
|
60baca27e4 | ||
|
|
86990db236 | ||
|
|
cb376bcd80 | ||
|
|
f2b8edd1e2 | ||
|
|
c4f8afcfde | ||
|
|
1a1a216d5a | ||
|
|
9f80a82c1a | ||
|
|
c573c80bd3 | ||
|
|
3cd6817e21 | ||
|
|
d4a69658a1 | ||
|
|
8e06fe4971 | ||
|
|
aaeeec8f1c | ||
|
|
66d5e24606 | ||
|
|
e8907a073f | ||
|
|
9656ac0254 | ||
|
|
75624617ce | ||
|
|
1a8f6578b3 | ||
|
|
4f0548b018 | ||
|
|
5119e82b93 | ||
|
|
3be5856c82 | ||
|
|
a319143901 | ||
|
|
17c88d60c7 | ||
|
|
7601511fdf | ||
|
|
f507b5eee4 | ||
|
|
93821165be | ||
|
|
aaa0b858e4 | ||
|
|
5fa1938691 | ||
|
|
56ee3d4820 | ||
|
|
c2d9a1ed6f | ||
|
|
fcf9ab2798 | ||
|
|
35e445bd04 | ||
|
|
88ce3c31b7 | ||
|
|
16320a0f81 | ||
|
|
8c72fb3539 | ||
|
|
8ffe389daa | ||
|
|
189a4516a1 | ||
|
|
2576855ded | ||
|
|
7d4d48a35e | ||
|
|
cc6f759190 | ||
|
|
c23fc86a23 | ||
|
|
d2324bdda1 | ||
|
|
6f0ae9d49a | ||
|
|
0389af5724 | ||
|
|
1766e25f45 | ||
|
|
323001238a | ||
|
|
91f062f873 | ||
|
|
650a0cfbff | ||
|
|
e6b8b3d1d3 | ||
|
|
a170023f23 | ||
|
|
4be4c0cddc | ||
|
|
0de9d374df | ||
|
|
0df199198a | ||
|
|
7646e376e0 | ||
|
|
5996798a34 | ||
|
|
6fec532012 | ||
|
|
15713e0b7c | ||
|
|
a6a561af47 | ||
|
|
09c468a4b4 | ||
|
|
bcda1c2409 | ||
|
|
afcd8d9ab1 | ||
|
|
c9b1c91944 | ||
|
|
5d9434eb09 | ||
|
|
1a44b5d52a | ||
|
|
6635ca5e26 | ||
|
|
9c6c78833b | ||
|
|
9a9ab0813c | ||
|
|
0ccaaa48ce | ||
|
|
3f2fe98dd1 | ||
|
|
0d91e9c255 | ||
|
|
af926fbe1f | ||
|
|
83039ae2d4 | ||
|
|
4c53da6961 | ||
|
|
eb306f463e | ||
|
|
788835c5fd | ||
|
|
4d76606fa2 | ||
|
|
1baf7d34b3 | ||
|
|
c78159469a | ||
|
|
b72ca0289c | ||
|
|
46f670f8a2 | ||
|
|
4b44362b9f | ||
|
|
d068a29798 | ||
|
|
0836a51408 | ||
|
|
566cee8fe7 | ||
|
|
e85698e131 | ||
|
|
5f3c541c4c | ||
|
|
3c43e00d8a | ||
|
|
92d686d356 | ||
|
|
0f69e9c825 | ||
|
|
217d979458 | ||
|
|
cc289972fc | ||
|
|
c601e603c2 | ||
|
|
1002c6da1c | ||
|
|
0911337689 | ||
|
|
3bcc416e13 | ||
|
|
65837806f5 | ||
|
|
b0772dcc66 | ||
|
|
c6d65aad3b | ||
|
|
18dd20ce55 | ||
|
|
0f6d76a501 | ||
|
|
0f1320109f | ||
|
|
defa28c618 | ||
|
|
b7c95be47c | ||
|
|
a18d154e0e | ||
|
|
52195a12ee | ||
|
|
59c78d5809 | ||
|
|
be164fc8f9 | ||
|
|
5833ef1efc | ||
|
|
28f88d46f3 | ||
|
|
6ec7683991 | ||
|
|
fb2d8f79d6 | ||
|
|
8f7fa1b1bf | ||
|
|
e5889ce622 | ||
|
|
3a6f83394c | ||
|
|
acf36f3d1a | ||
|
|
63e6a8bab2 | ||
|
|
5361cc6bd1 | ||
|
|
cabac55394 | ||
|
|
db7483ef10 | ||
|
|
4b51ccbefe | ||
|
|
74c2f1257a | ||
|
|
1428a5e3ae | ||
|
|
fe021c1524 | ||
|
|
c57bf21306 | ||
|
|
1743b7d92d | ||
|
|
7f31278c4c | ||
|
|
8401e16a15 | ||
|
|
07fb5854f3 | ||
|
|
b56a99bfba | ||
|
|
b91e4e4df1 | ||
|
|
52a4d6ac31 | ||
|
|
796ab87b14 | ||
|
|
ed1fad3bd4 | ||
|
|
9c1876f542 | ||
|
|
7d111d9963 | ||
|
|
8c2ce0cf3f | ||
|
|
1b442cb16f | ||
|
|
2bf3680d87 | ||
|
|
0d4f0f0db5 | ||
|
|
e17ff8fd32 | ||
|
|
14edd12304 | ||
|
|
e6ffdb23a4 | ||
|
|
98fdedac06 | ||
|
|
255037264a | ||
|
|
d3fcbe9a02 | ||
|
|
bcdd588c6e | ||
|
|
b5007d45f7 | ||
|
|
a584cf5a4f | ||
|
|
77f7a2fa7f | ||
|
|
f2c539dc70 | ||
|
|
78d7160a99 | ||
|
|
196673bbce | ||
|
|
794d13082c | ||
|
|
5f5cf4107e | ||
|
|
6f3ec54b9f | ||
|
|
58043a6b04 | ||
|
|
a885315ef5 | ||
|
|
d7581525ac | ||
|
|
385068eb91 | ||
|
|
1085f68018 | ||
|
|
21af775ce0 | ||
|
|
bf16fee6e9 | ||
|
|
2358a2137a | ||
|
|
66baa7dc25 | ||
|
|
d63b4c1034 | ||
|
|
963e220a1c | ||
|
|
2f146e4d4c | ||
|
|
f796eede5a | ||
|
|
c89453be95 | ||
|
|
c3f5f5ca36 | ||
|
|
911d12f7c4 | ||
|
|
34d3c45d35 | ||
|
|
17614312e0 | ||
|
|
977779ae8d | ||
|
|
a2e35a0757 | ||
|
|
a4a2b6403b | ||
|
|
8ce8e289c9 | ||
|
|
03be97e437 | ||
|
|
2c5cf5a82a | ||
|
|
0a2d1965df | ||
|
|
c8a5f1e335 | ||
|
|
5e00cf9620 | ||
|
|
ce6370e25c | ||
|
|
3f8c1e4b34 | ||
|
|
25cda200be | ||
|
|
a1bc83a2ba | ||
|
|
bc3949db9e | ||
|
|
6cfa885207 | ||
|
|
899588e0b5 | ||
|
|
49af52a68d | ||
|
|
ec908af19c | ||
|
|
e61ac4682e | ||
|
|
4d10dce61d | ||
|
|
c569830dfc | ||
|
|
2d9fd87029 | ||
|
|
2670bfb8ba | ||
|
|
cc9190ab37 | ||
|
|
980570de71 | ||
|
|
ef92b54db3 | ||
|
|
0130124cea | ||
|
|
e2a7e867f9 | ||
|
|
32ce0ce5d9 | ||
|
|
28082ff5f5 | ||
|
|
46ccc4332c | ||
|
|
3a1217e667 | ||
|
|
39fd0c1278 | ||
|
|
4e6bd54dd1 | ||
|
|
5c9f46a6b0 | ||
|
|
7d53866157 | ||
|
|
9a2e948c42 | ||
|
|
223e971c7e | ||
|
|
df814223ff | ||
|
|
82b326e684 | ||
|
|
6aa581d2f0 | ||
|
|
8c0b2c684a | ||
|
|
62324781bd | ||
|
|
7ae0b2dc09 | ||
|
|
058122b804 | ||
|
|
69f63c529d | ||
|
|
e17a6b29b6 | ||
|
|
b12c2a13c0 | ||
|
|
236c835abc | ||
|
|
b41a5afe04 | ||
|
|
ad338bfa44 | ||
|
|
a899522679 | ||
|
|
b9b58c781e | ||
|
|
aa1eec4642 | ||
|
|
0c8d9469ea | ||
|
|
079e1bdffc | ||
|
|
b4337d1b54 | ||
|
|
e6a11c5e12 | ||
|
|
dbe287ff5e | ||
|
|
61dc1a7c62 | ||
|
|
dc1e0c0195 | ||
|
|
041531458b | ||
|
|
1374bb81fd | ||
|
|
f41ac103d3 | ||
|
|
f6301714db | ||
|
|
7dc39b1ee9 | ||
|
|
696a7ce407 | ||
|
|
d28d788623 | ||
|
|
99122ee7bb | ||
|
|
19ee7ec794 | ||
|
|
cd9ec0d20f | ||
|
|
e77883e980 | ||
|
|
0994c92550 | ||
|
|
465c7208cc | ||
|
|
4f9f181f07 | ||
|
|
b7e7a4bf26 | ||
|
|
c7df65309b | ||
|
|
26900262f3 | ||
|
|
9b5ce36368 | ||
|
|
f69b52b1aa | ||
|
|
1e1d908c12 | ||
|
|
6c69d675da | ||
|
|
feabd6f739 | ||
|
|
1ea590c364 | ||
|
|
b21779e685 | ||
|
|
12a4e7c3a2 | ||
|
|
799a76de74 | ||
|
|
b1fee8ff63 | ||
|
|
9cc223d419 | ||
|
|
20edd64301 | ||
|
|
9aee518352 | ||
|
|
6ca515ea70 | ||
|
|
51b933c5f0 | ||
|
|
3f13d33543 | ||
|
|
85a12429ee | ||
|
|
3e0e3f5459 | ||
|
|
801869a5d5 | ||
|
|
54f4b85beb | ||
|
|
fa074145a4 | ||
|
|
b2d6550179 | ||
|
|
62dd1f5177 | ||
|
|
dc7c12d474 | ||
|
|
a6dda5f91c | ||
|
|
c1f7795dd6 | ||
|
|
4989e6e419 | ||
|
|
d4963bcd32 | ||
|
|
d725255784 | ||
|
|
5f4159a0d7 | ||
|
|
0a2a5e6604 | ||
|
|
3ddc446ba2 |
@@ -4,7 +4,7 @@ AccessModifierOffset: -2
|
|||||||
AlignAfterOpenBracket: Align
|
AlignAfterOpenBracket: Align
|
||||||
AlignConsecutiveAssignments: false
|
AlignConsecutiveAssignments: false
|
||||||
AlignConsecutiveDeclarations: false
|
AlignConsecutiveDeclarations: false
|
||||||
AlignEscapedNewlinesLeft: false
|
AlignEscapedNewlines: Right
|
||||||
AlignOperands: true
|
AlignOperands: true
|
||||||
AlignTrailingComments: true
|
AlignTrailingComments: true
|
||||||
AllowAllParametersOfDeclarationOnNextLine: true
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
@@ -31,14 +31,20 @@ BraceWrapping:
|
|||||||
BeforeCatch: false
|
BeforeCatch: false
|
||||||
BeforeElse: false
|
BeforeElse: false
|
||||||
IndentBraces: false
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
BreakBeforeBinaryOperators: None
|
BreakBeforeBinaryOperators: None
|
||||||
BreakBeforeBraces: Attach
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
BreakBeforeTernaryOperators: true
|
BreakBeforeTernaryOperators: true
|
||||||
BreakConstructorInitializersBeforeComma: false
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
BreakAfterJavaFieldAnnotations: false
|
BreakAfterJavaFieldAnnotations: false
|
||||||
BreakStringLiterals: true
|
BreakStringLiterals: true
|
||||||
ColumnLimit: 80
|
ColumnLimit: 80
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
ConstructorInitializerIndentWidth: 4
|
ConstructorInitializerIndentWidth: 4
|
||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 4
|
||||||
@@ -46,7 +52,11 @@ Cpp11BracedListStyle: true
|
|||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
DisableFormat: false
|
DisableFormat: false
|
||||||
ExperimentalAutoDetectBinPacking: false
|
ExperimentalAutoDetectBinPacking: false
|
||||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
IncludeCategories:
|
IncludeCategories:
|
||||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
Priority: 2
|
Priority: 2
|
||||||
@@ -68,6 +78,7 @@ NamespaceIndentation: None
|
|||||||
ObjCBlockIndentWidth: 2
|
ObjCBlockIndentWidth: 2
|
||||||
ObjCSpaceAfterProperty: false
|
ObjCSpaceAfterProperty: false
|
||||||
ObjCSpaceBeforeProtocolList: true
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
PenaltyBreakBeforeFirstCallParameter: 19
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
PenaltyBreakComment: 300
|
PenaltyBreakComment: 300
|
||||||
PenaltyBreakFirstLessLess: 120
|
PenaltyBreakFirstLessLess: 120
|
||||||
@@ -77,7 +88,9 @@ PenaltyReturnTypeOnItsOwnLine: 60
|
|||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
ReflowComments: true
|
ReflowComments: true
|
||||||
SortIncludes: false
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: true
|
||||||
SpaceAfterCStyleCast: false
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
SpaceBeforeAssignmentOperators: true
|
SpaceBeforeAssignmentOperators: true
|
||||||
SpaceBeforeParens: ControlStatements
|
SpaceBeforeParens: ControlStatements
|
||||||
SpaceInEmptyParentheses: false
|
SpaceInEmptyParentheses: false
|
||||||
|
|||||||
26
.travis.yml
26
.travis.yml
@@ -1,3 +1,4 @@
|
|||||||
|
dist: trusty
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
- CI_BUILD=cmake
|
- CI_BUILD=cmake
|
||||||
@@ -6,15 +7,13 @@ language: cpp
|
|||||||
compiler:
|
compiler:
|
||||||
- clang
|
- clang
|
||||||
- gcc
|
- gcc
|
||||||
sudo: false
|
sudo: required
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- george-edison55-precise-backports
|
|
||||||
packages:
|
packages:
|
||||||
- g++-4.9
|
- g++-7
|
||||||
- libstdc++-4.9-dev
|
|
||||||
- autoconf
|
- autoconf
|
||||||
- automake
|
- automake
|
||||||
- autotools-dev
|
- autotools-dev
|
||||||
@@ -33,29 +32,18 @@ addons:
|
|||||||
- cmake-data
|
- cmake-data
|
||||||
before_install:
|
before_install:
|
||||||
- $CC --version
|
- $CC --version
|
||||||
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
|
- if [ "$CXX" = "g++" ]; then export CXX="g++-7" CC="gcc-7"; fi
|
||||||
- $CC --version
|
- $CC --version
|
||||||
- go version
|
- go version
|
||||||
- cmake --version
|
- cmake --version
|
||||||
before_script:
|
before_script:
|
||||||
# First build spdylay, since integration tests require it.
|
|
||||||
# spdylay is going to be built under third-party/spdylay
|
|
||||||
- cd third-party
|
|
||||||
- git clone https://github.com/tatsuhiro-t/spdylay.git
|
|
||||||
- cd spdylay
|
|
||||||
- autoreconf -i
|
|
||||||
# Don't use ASAN for spdylay since failmalloc does not work with it.
|
|
||||||
- ./configure --disable-src --disable-examples
|
|
||||||
- make check
|
|
||||||
- export SPDYLAY_HOME=$PWD
|
|
||||||
- cd ../..
|
|
||||||
# Now build nghttp2
|
# Now build nghttp2
|
||||||
- if [ "$CI_BUILD" = "autotools" ]; then autoreconf -i; fi
|
- if [ "$CI_BUILD" = "autotools" ]; then autoreconf -i; fi
|
||||||
- git submodule update --init
|
- git submodule update --init
|
||||||
- if [ "$CI_BUILD" = "autotools" ]; then ./configure --enable-werror --with-mruby --with-neverbleed LIBSPDYLAY_CFLAGS="-I$SPDYLAY_HOME/lib/includes" LIBSPDYLAY_LIBS="-L$SPDYLAY_HOME/lib/.libs -lspdylay" CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address; fi
|
- if [ "$CI_BUILD" = "autotools" ]; then ./configure --with-mruby; fi
|
||||||
- if [ "$CI_BUILD" = "cmake" ]; then cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1 -DSPDYLAY_INCLUDE_DIR="$SPDYLAY_HOME/lib/includes" -DSPDYLAY_LIBRARY="$SPDYLAY_HOME/lib/.libs/libspdylay.so"; fi
|
- if [ "$CI_BUILD" = "cmake" ]; then cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1; fi
|
||||||
script:
|
script:
|
||||||
- if [ "$CI_BUILD" = "autotools" ]; then make distcheck; fi
|
- if [ "$CI_BUILD" = "autotools" ]; then make distcheck DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --enable-werror CPPFLAGS=-fsanitize=address LDFLAGS=\"-fsanitize=address -fuse-ld=gold\""; fi
|
||||||
- if [ "$CI_BUILD" = "cmake" ]; then make check; fi
|
- if [ "$CI_BUILD" = "cmake" ]; then make check; fi
|
||||||
# As of April, 23, 2016, golang http2 build fails, probably because
|
# As of April, 23, 2016, golang http2 build fails, probably because
|
||||||
# the default go version is too old.
|
# the default go version is too old.
|
||||||
|
|||||||
20
AUTHORS
20
AUTHORS
@@ -21,21 +21,26 @@ Amir Pakdel
|
|||||||
Anders Bakken
|
Anders Bakken
|
||||||
Andreas Pohl
|
Andreas Pohl
|
||||||
Andy Davies
|
Andy Davies
|
||||||
|
Angus Gratton
|
||||||
|
Anna Henningsen
|
||||||
Ant Bryan
|
Ant Bryan
|
||||||
Benedikt Christoph Wolters
|
Benedikt Christoph Wolters
|
||||||
Benedikt Christoph Wolters
|
Benjamin Peterson
|
||||||
Bernard Spil
|
|
||||||
Bernard Spil
|
Bernard Spil
|
||||||
Brian Card
|
Brian Card
|
||||||
Brian Suh
|
Brian Suh
|
||||||
|
Daniel Evers
|
||||||
Daniel Stenberg
|
Daniel Stenberg
|
||||||
Dave Reisner
|
Dave Reisner
|
||||||
David Beitey
|
David Beitey
|
||||||
David Weekly
|
David Weekly
|
||||||
|
Dmitriy Vetutnev
|
||||||
|
Dylan Plecki
|
||||||
Etienne Cimon
|
Etienne Cimon
|
||||||
Fabian Möller
|
Fabian Möller
|
||||||
Fabian Wiesel
|
Fabian Wiesel
|
||||||
Gabi Davar
|
Gabi Davar
|
||||||
|
Gitai
|
||||||
Google Inc.
|
Google Inc.
|
||||||
Jacob Champion
|
Jacob Champion
|
||||||
Jan-E
|
Jan-E
|
||||||
@@ -50,11 +55,15 @@ Kenny (kang-yen) Peng
|
|||||||
Kenny Peng
|
Kenny Peng
|
||||||
Kit Chan
|
Kit Chan
|
||||||
Kyle Schomp
|
Kyle Schomp
|
||||||
|
LazyHamster
|
||||||
Lucas Pardue
|
Lucas Pardue
|
||||||
MATSUMOTO Ryosuke
|
MATSUMOTO Ryosuke
|
||||||
|
Marc Bachmann
|
||||||
Matt Rudary
|
Matt Rudary
|
||||||
|
Matt Way
|
||||||
Mike Conlen
|
Mike Conlen
|
||||||
Mike Frysinger
|
Mike Frysinger
|
||||||
|
Mike Lothian
|
||||||
Nicholas Hurley
|
Nicholas Hurley
|
||||||
Nora Shoemaker
|
Nora Shoemaker
|
||||||
Peeyush Aggarwal
|
Peeyush Aggarwal
|
||||||
@@ -63,15 +72,21 @@ Piotr Sikora
|
|||||||
Raul Gutierrez Segales
|
Raul Gutierrez Segales
|
||||||
Remo E
|
Remo E
|
||||||
Reza Tavakoli
|
Reza Tavakoli
|
||||||
|
Rick Lei
|
||||||
Ross Smith II
|
Ross Smith II
|
||||||
Scott Mitchell
|
Scott Mitchell
|
||||||
|
Sebastiaan Deckers
|
||||||
|
Simone Basso
|
||||||
|
Soham Sinha
|
||||||
Stefan Eissing
|
Stefan Eissing
|
||||||
Stephen Ludin
|
Stephen Ludin
|
||||||
Sunpoet Po-Chuan Hsieh
|
Sunpoet Po-Chuan Hsieh
|
||||||
Svante Signell
|
Svante Signell
|
||||||
Syohei YOSHIDA
|
Syohei YOSHIDA
|
||||||
|
Tapanito
|
||||||
Tatsuhiko Kubo
|
Tatsuhiko Kubo
|
||||||
Tatsuhiro Tsujikawa
|
Tatsuhiro Tsujikawa
|
||||||
|
Tobias Geerinckx-Rice
|
||||||
Tom Harwood
|
Tom Harwood
|
||||||
Tomasz Buchert
|
Tomasz Buchert
|
||||||
Tomasz Torcz
|
Tomasz Torcz
|
||||||
@@ -89,6 +104,7 @@ dalf
|
|||||||
es
|
es
|
||||||
fangdingjun
|
fangdingjun
|
||||||
kumagi
|
kumagi
|
||||||
|
lstefani
|
||||||
makovich
|
makovich
|
||||||
mod-h2-dev
|
mod-h2-dev
|
||||||
moparisthebest
|
moparisthebest
|
||||||
|
|||||||
@@ -24,15 +24,15 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
# XXX using 1.8.90 instead of 1.9.0-DEV
|
# XXX using 1.8.90 instead of 1.9.0-DEV
|
||||||
project(nghttp2 VERSION 1.20.0)
|
project(nghttp2 VERSION 1.31.0)
|
||||||
|
|
||||||
# See versioning rule:
|
# See versioning rule:
|
||||||
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||||
set(LT_CURRENT 27)
|
set(LT_CURRENT 30)
|
||||||
set(LT_REVISION 0)
|
set(LT_REVISION 0)
|
||||||
set(LT_AGE 13)
|
set(LT_AGE 16)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||||
include(Version)
|
include(Version)
|
||||||
|
|
||||||
math(EXPR LT_SOVERSION "${LT_CURRENT} - ${LT_AGE}")
|
math(EXPR LT_SOVERSION "${LT_CURRENT} - ${LT_AGE}")
|
||||||
@@ -79,7 +79,7 @@ else()
|
|||||||
set(ENABLE_PYTHON_BINDINGS_DEFAULT OFF)
|
set(ENABLE_PYTHON_BINDINGS_DEFAULT OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(LibXml2 2.7.7)
|
find_package(LibXml2 2.6.26)
|
||||||
set(WITH_LIBXML2_DEFAULT ${LIBXML2_FOUND})
|
set(WITH_LIBXML2_DEFAULT ${LIBXML2_FOUND})
|
||||||
find_package(Jemalloc)
|
find_package(Jemalloc)
|
||||||
set(WITH_JEMALLOC_DEFAULT ${JEMALLOC_FOUND})
|
set(WITH_JEMALLOC_DEFAULT ${JEMALLOC_FOUND})
|
||||||
@@ -106,23 +106,13 @@ endif()
|
|||||||
foreach(_build_type "Release" "MinSizeRel" "RelWithDebInfo")
|
foreach(_build_type "Release" "MinSizeRel" "RelWithDebInfo")
|
||||||
foreach(_lang C CXX)
|
foreach(_lang C CXX)
|
||||||
string(TOUPPER "CMAKE_${_lang}_FLAGS_${_build_type}" _var)
|
string(TOUPPER "CMAKE_${_lang}_FLAGS_${_build_type}" _var)
|
||||||
string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" "" ${_var} "${${_var}}")
|
string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " ${_var} "${${_var}}")
|
||||||
endforeach()
|
endforeach()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
#
|
|
||||||
# If we're running GCC or clang define _U_ to be "__attribute__((unused))"
|
|
||||||
# so we can use _U_ to flag unused function parameters and not get warnings
|
|
||||||
# about them. Otherwise, define _U_ to be an empty string so that _U_ used
|
|
||||||
# to flag an unused function parameters will compile with other compilers.
|
|
||||||
#
|
|
||||||
# XXX - similar hints for other compilers?
|
|
||||||
#
|
|
||||||
if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||||
set(HINT_UNUSED_PARAM "__attribute__((unused))")
|
|
||||||
set(HINT_NORETURN "__attribute__((noreturn))")
|
set(HINT_NORETURN "__attribute__((noreturn))")
|
||||||
else()
|
else()
|
||||||
set(HINT_UNUSED_PARAM)
|
|
||||||
set(HINT_NORETURN)
|
set(HINT_NORETURN)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -312,6 +302,7 @@ check_type_size("time_t" SIZEOF_TIME_T)
|
|||||||
include(CheckFunctionExists)
|
include(CheckFunctionExists)
|
||||||
check_function_exists(_Exit HAVE__EXIT)
|
check_function_exists(_Exit HAVE__EXIT)
|
||||||
check_function_exists(accept4 HAVE_ACCEPT4)
|
check_function_exists(accept4 HAVE_ACCEPT4)
|
||||||
|
check_function_exists(mkostemp HAVE_MKOSTEMP)
|
||||||
|
|
||||||
include(CheckSymbolExists)
|
include(CheckSymbolExists)
|
||||||
# XXX does this correctly detect initgroups (un)availability on cygwin?
|
# XXX does this correctly detect initgroups (un)availability on cygwin?
|
||||||
|
|||||||
@@ -10,39 +10,47 @@
|
|||||||
#
|
#
|
||||||
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
|
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
|
||||||
|
|
||||||
FROM ubuntu:vivid
|
|
||||||
|
|
||||||
|
# Only use standalone-toolchain for reduce size
|
||||||
|
FROM ubuntu:xenial
|
||||||
MAINTAINER Tatsuhiro Tsujikawa
|
MAINTAINER Tatsuhiro Tsujikawa
|
||||||
|
ENV ANDROID_HOME /root
|
||||||
ENV ANDROID_HOME /root/android
|
|
||||||
ENV PREFIX $ANDROID_HOME/usr/local
|
|
||||||
ENV TOOLCHAIN $ANDROID_HOME/toolchain
|
ENV TOOLCHAIN $ANDROID_HOME/toolchain
|
||||||
ENV PATH $TOOLCHAIN/bin:$PATH
|
ENV PATH $TOOLCHAIN/bin:$PATH
|
||||||
|
|
||||||
# It would be better to use nearest ubuntu archive mirror for faster
|
ENV NDK_VERSION r14b
|
||||||
# downloads.
|
|
||||||
# RUN sed -ie 's/archive\.ubuntu/jp.archive.ubuntu/g' /etc/apt/sources.list
|
|
||||||
|
|
||||||
RUN apt-get update
|
WORKDIR /root
|
||||||
# genisoimage, libc6-i386 and lib32stdc++6 are required to decompress ndk.
|
RUN apt-get update && \
|
||||||
RUN apt-get install -y make binutils autoconf automake autotools-dev libtool \
|
apt-get install -y unzip make binutils autoconf \
|
||||||
pkg-config git curl dpkg-dev libxml2-dev \
|
automake autotools-dev libtool pkg-config git \
|
||||||
genisoimage libc6-i386 lib32stdc++6
|
curl dpkg-dev libxml2-dev genisoimage libc6-i386 \
|
||||||
|
lib32stdc++6 python&& \
|
||||||
|
rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
# Install toolchain
|
||||||
|
RUN curl -L -O https://dl.google.com/android/repository/android-ndk-$NDK_VERSION-linux-x86_64.zip && \
|
||||||
|
unzip -q android-ndk-$NDK_VERSION-linux-x86_64.zip && \
|
||||||
|
rm android-ndk-$NDK_VERSION-linux-x86_64.zip && \
|
||||||
|
mkdir -p $ANDROID_HOME/toolchain && \
|
||||||
|
$ANDROID_HOME/android-ndk-$NDK_VERSION/build/tools/make-standalone-toolchain.sh \
|
||||||
|
--install-dir=$ANDROID_HOME/toolchain \
|
||||||
|
--toolchain=arm-linux-androideabi-4.9 \
|
||||||
|
--force && \
|
||||||
|
rm -r android-ndk-$NDK_VERSION
|
||||||
|
|
||||||
|
ENV PREFIX /root/usr/local
|
||||||
|
|
||||||
|
# Setup version of libraries
|
||||||
|
ENV OPENSSL_VERSION 1.0.2d
|
||||||
|
ENV SPDYLAY_VERSION v1.4.0
|
||||||
|
ENV LIBEV_VERSION 4.19
|
||||||
|
ENV ZLIB_VERSION 1.2.8
|
||||||
|
ENV CARES_VERSION 1.13.0
|
||||||
|
ENV NGHTTP2_VERSION v1.24.0
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86_64.bin && \
|
RUN git clone https://github.com/tatsuhiro-t/spdylay -b $SPDYLAY_VERSION --depth 1
|
||||||
chmod a+x android-ndk-r10d-linux-x86_64.bin && \
|
|
||||||
./android-ndk-r10d-linux-x86_64.bin && \
|
|
||||||
rm android-ndk-r10d-linux-x86_64.bin
|
|
||||||
|
|
||||||
WORKDIR /root/build/android-ndk-r10d
|
|
||||||
RUN /bin/bash build/tools/make-standalone-toolchain.sh \
|
|
||||||
--install-dir=$ANDROID_HOME/toolchain \
|
|
||||||
--toolchain=arm-linux-androideabi-4.9 --llvm-version=3.5 \
|
|
||||||
--system=linux-x86_64
|
|
||||||
|
|
||||||
WORKDIR /root/build
|
|
||||||
RUN git clone https://github.com/tatsuhiro-t/spdylay
|
|
||||||
WORKDIR /root/build/spdylay
|
WORKDIR /root/build/spdylay
|
||||||
RUN autoreconf -i && \
|
RUN autoreconf -i && \
|
||||||
./configure \
|
./configure \
|
||||||
@@ -59,22 +67,22 @@ RUN autoreconf -i && \
|
|||||||
make install
|
make install
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.2d.tar.gz && \
|
RUN curl -L -O https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz && \
|
||||||
tar xf openssl-1.0.2d.tar.gz && \
|
tar xf openssl-$OPENSSL_VERSION.tar.gz && \
|
||||||
rm openssl-1.0.2d.tar.gz
|
rm openssl-$OPENSSL_VERSION.tar.gz
|
||||||
|
|
||||||
WORKDIR /root/build/openssl-1.0.2d
|
WORKDIR /root/build/openssl-$OPENSSL_VERSION
|
||||||
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
|
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
|
||||||
./Configure --prefix=$PREFIX android && \
|
./Configure --prefix=$PREFIX android && \
|
||||||
make && make install_sw
|
make && make install_sw
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O http://dist.schmorp.de/libev/libev-4.19.tar.gz && \
|
RUN curl -L -O http://dist.schmorp.de/libev/Attic/libev-$LIBEV_VERSION.tar.gz && \
|
||||||
curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch && \
|
curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch && \
|
||||||
tar xf libev-4.19.tar.gz && \
|
tar xf libev-$LIBEV_VERSION.tar.gz && \
|
||||||
rm libev-4.19.tar.gz
|
rm libev-$LIBEV_VERSION.tar.gz
|
||||||
|
|
||||||
WORKDIR /root/build/libev-4.19
|
WORKDIR /root/build/libev-$LIBEV_VERSION
|
||||||
RUN patch -p1 < ../libev-4.19-android.patch && \
|
RUN patch -p1 < ../libev-4.19-android.patch && \
|
||||||
./configure \
|
./configure \
|
||||||
--host=arm-linux-androideabi \
|
--host=arm-linux-androideabi \
|
||||||
@@ -87,11 +95,11 @@ RUN patch -p1 < ../libev-4.19-android.patch && \
|
|||||||
make install
|
make install
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O http://zlib.net/zlib-1.2.8.tar.gz && \
|
RUN curl -L -O https://downloads.sourceforge.net/project/libpng/zlib/$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz && \
|
||||||
tar xf zlib-1.2.8.tar.gz && \
|
tar xf zlib-$ZLIB_VERSION.tar.gz && \
|
||||||
rm zlib-1.2.8.tar.gz
|
rm zlib-$ZLIB_VERSION.tar.gz
|
||||||
|
|
||||||
WORKDIR /root/build/zlib-1.2.8
|
WORKDIR /root/build/zlib-$ZLIB_VERSION
|
||||||
RUN HOST=arm-linux-androideabi \
|
RUN HOST=arm-linux-androideabi \
|
||||||
CC=$HOST-gcc \
|
CC=$HOST-gcc \
|
||||||
AR=$HOST-ar \
|
AR=$HOST-ar \
|
||||||
@@ -105,11 +113,26 @@ RUN HOST=arm-linux-androideabi \
|
|||||||
--static && \
|
--static && \
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN git clone https://github.com/nghttp2/nghttp2
|
RUN curl -L -O https://c-ares.haxx.se/download/c-ares-$CARES_VERSION.tar.gz && \
|
||||||
|
tar xf c-ares-$CARES_VERSION.tar.gz && \
|
||||||
|
rm c-ares-$CARES_VERSION.tar.gz
|
||||||
|
|
||||||
|
WORKDIR /root/build/c-ares-$CARES_VERSION
|
||||||
|
RUN ./configure \
|
||||||
|
--host=arm-linux-androideabi \
|
||||||
|
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||||
|
--prefix=$PREFIX \
|
||||||
|
--disable-shared && \
|
||||||
|
make install
|
||||||
|
|
||||||
|
WORKDIR /root/build
|
||||||
|
RUN git clone https://github.com/nghttp2/nghttp2 -b $NGHTTP2_VERSION --depth 1
|
||||||
WORKDIR /root/build/nghttp2
|
WORKDIR /root/build/nghttp2
|
||||||
RUN autoreconf -i && \
|
RUN autoreconf -i && \
|
||||||
./configure \
|
./configure \
|
||||||
|
--enable-app \
|
||||||
--disable-shared \
|
--disable-shared \
|
||||||
--host=arm-linux-androideabi \
|
--host=arm-linux-androideabi \
|
||||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||||
@@ -118,11 +141,10 @@ RUN autoreconf -i && \
|
|||||||
--disable-python-bindings \
|
--disable-python-bindings \
|
||||||
--disable-examples \
|
--disable-examples \
|
||||||
--disable-threads \
|
--disable-threads \
|
||||||
LIBSPDYLAY_CFLAGS=-I$PREFIX/usr/local/include \
|
CC="$TOOLCHAIN"/bin/arm-linux-androideabi-clang \
|
||||||
LIBSPDYLAY_LIBS="-L$PREFIX/usr/local/lib -lspdylay" \
|
CXX="$TOOLCHAIN"/bin/arm-linux-androideabi-clang++ \
|
||||||
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||||
CXXFLAGS="-fno-strict-aliasing" \
|
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
|
||||||
LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
|
|
||||||
make && \
|
make && \
|
||||||
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp
|
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp
|
||||||
|
|||||||
170
README.rst
170
README.rst
@@ -4,10 +4,10 @@ nghttp2 - HTTP/2 C Library
|
|||||||
This is an implementation of the Hypertext Transfer Protocol version 2
|
This is an implementation of the Hypertext Transfer Protocol version 2
|
||||||
in C.
|
in C.
|
||||||
|
|
||||||
The framing layer of HTTP/2 is implemented as a reusable C
|
The framing layer of HTTP/2 is implemented as a reusable C library.
|
||||||
library. On top of that, we have implemented an HTTP/2 client, server
|
On top of that, we have implemented an HTTP/2 client, server and
|
||||||
and proxy. We have also developed load test and benchmarking tools for
|
proxy. We have also developed load test and benchmarking tools for
|
||||||
HTTP/2 and SPDY.
|
HTTP/2.
|
||||||
|
|
||||||
An HPACK encoder and decoder are available as a public API.
|
An HPACK encoder and decoder are available as a public API.
|
||||||
|
|
||||||
@@ -34,8 +34,8 @@ implementation.
|
|||||||
|
|
||||||
* https://nghttp2.org/ (TLS + ALPN/NPN)
|
* https://nghttp2.org/ (TLS + ALPN/NPN)
|
||||||
|
|
||||||
This endpoint supports ``h2``, ``h2-16``, ``h2-14``, ``spdy/3.1``
|
This endpoint supports ``h2``, ``h2-16``, ``h2-14``, and
|
||||||
and ``http/1.1`` via ALPN/NPN and requires TLSv1.2 for HTTP/2
|
``http/1.1`` via ALPN/NPN and requires TLSv1.2 for HTTP/2
|
||||||
connection.
|
connection.
|
||||||
|
|
||||||
* http://nghttp2.org/ (HTTP Upgrade and HTTP/2 Direct)
|
* http://nghttp2.org/ (HTTP Upgrade and HTTP/2 Direct)
|
||||||
@@ -76,18 +76,10 @@ ALPN support requires OpenSSL >= 1.0.2 (released 22 January 2015).
|
|||||||
LibreSSL >= 2.2.0 can be used instead of OpenSSL, but OpenSSL has more
|
LibreSSL >= 2.2.0 can be used instead of OpenSSL, but OpenSSL has more
|
||||||
features than LibreSSL at the time of this writing.
|
features than LibreSSL at the time of this writing.
|
||||||
|
|
||||||
To enable the SPDY protocol in the application program ``nghttpx`` and
|
|
||||||
``h2load``, the following package is required:
|
|
||||||
|
|
||||||
* spdylay >= 1.3.2
|
|
||||||
|
|
||||||
We no longer recommend to build nghttp2 with SPDY protocol support
|
|
||||||
enabled. SPDY support will be removed soon.
|
|
||||||
|
|
||||||
To enable ``-a`` option (getting linked assets from the downloaded
|
To enable ``-a`` option (getting linked assets from the downloaded
|
||||||
resource) in ``nghttp``, the following package is required:
|
resource) in ``nghttp``, the following package is required:
|
||||||
|
|
||||||
* libxml2 >= 2.7.7
|
* libxml2 >= 2.6.26
|
||||||
|
|
||||||
To enable systemd support in nghttpx, the following package is
|
To enable systemd support in nghttpx, the following package is
|
||||||
required:
|
required:
|
||||||
@@ -130,13 +122,9 @@ and above, run the following to install the required packages:
|
|||||||
|
|
||||||
sudo apt-get install g++ make binutils autoconf automake autotools-dev libtool pkg-config \
|
sudo apt-get install g++ make binutils autoconf automake autotools-dev libtool pkg-config \
|
||||||
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \
|
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \
|
||||||
libc-ares-dev libjemalloc-dev libsystemd-dev libspdylay-dev \
|
libc-ares-dev libjemalloc-dev libsystemd-dev \
|
||||||
cython python3-dev python-setuptools
|
cython python3-dev python-setuptools
|
||||||
|
|
||||||
Since Ubuntu 15.10, spdylay has been available as a package named
|
|
||||||
`libspdylay-dev`. For the earlier Ubuntu release, you need to build
|
|
||||||
it yourself: http://tatsuhiro-t.github.io/spdylay/
|
|
||||||
|
|
||||||
To enable mruby support for nghttpx, `mruby
|
To enable mruby support for nghttpx, `mruby
|
||||||
<https://github.com/mruby/mruby>`_ is required. We need to build
|
<https://github.com/mruby/mruby>`_ is required. We need to build
|
||||||
mruby with C++ ABI explicitly turned on, and probably need other
|
mruby with C++ ABI explicitly turned on, and probably need other
|
||||||
@@ -157,22 +145,8 @@ minimizes the risk of private key leakage when serious bug like
|
|||||||
Heartbleed is exploited. The neverbleed is disabled by default. To
|
Heartbleed is exploited. The neverbleed is disabled by default. To
|
||||||
enable it, use ``--with-neverbleed`` configure option.
|
enable it, use ``--with-neverbleed`` configure option.
|
||||||
|
|
||||||
Building from git
|
In order to compile the source code, gcc >= 4.8.3 or clang >= 3.4 is
|
||||||
-----------------
|
required.
|
||||||
|
|
||||||
Building from git is easy, but please be sure that at least autoconf 2.68 is
|
|
||||||
used:
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
|
|
||||||
$ git submodule update --init
|
|
||||||
$ autoreconf -i
|
|
||||||
$ automake
|
|
||||||
$ autoconf
|
|
||||||
$ ./configure
|
|
||||||
$ make
|
|
||||||
|
|
||||||
To compile the source code, gcc >= 4.8.3 or clang >= 3.4 is required.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
@@ -197,6 +171,62 @@ To compile the source code, gcc >= 4.8.3 or clang >= 3.4 is required.
|
|||||||
applications were not built, then using ``--enable-app`` may find
|
applications were not built, then using ``--enable-app`` may find
|
||||||
that cause, such as the missing dependency.
|
that cause, such as the missing dependency.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
In order to detect third party libraries, pkg-config is used
|
||||||
|
(however we don't use pkg-config for some libraries (e.g., libev)).
|
||||||
|
By default, pkg-config searches ``*.pc`` file in the standard
|
||||||
|
locations (e.g., /usr/lib/pkgconfig). If it is necessary to use
|
||||||
|
``*.pc`` file in the custom location, specify paths to
|
||||||
|
``PKG_CONFIG_PATH`` environment variable, and pass it to configure
|
||||||
|
script, like so:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ ./configure PKG_CONFIG_PATH=/path/to/pkgconfig
|
||||||
|
|
||||||
|
For pkg-config managed libraries, ``*_CFLAG`` and ``*_LIBS``
|
||||||
|
environment variables are defined (e.g., ``OPENSSL_CFLAGS``,
|
||||||
|
``OPENSSL_LIBS``). Specifying non-empty string to these variables
|
||||||
|
completely overrides pkg-config. In other words, if they are
|
||||||
|
specified, pkg-config is not used for detection, and user is
|
||||||
|
responsible to specify the correct values to these variables. For
|
||||||
|
complete list of these variables, run ``./configure -h``.
|
||||||
|
|
||||||
|
Building nghttp2 from release tar archive
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
The nghttp2 project regularly releases tar archives which includes
|
||||||
|
nghttp2 source code, and generated build files. They can be
|
||||||
|
downloaded from `Releases
|
||||||
|
<https://github.com/nghttp2/nghttp2/releases>`_ page.
|
||||||
|
|
||||||
|
Building nghttp2 from git requires autotools development packages.
|
||||||
|
Building from tar archives does not require them, and thus it is much
|
||||||
|
easier. The usual build step is as follows:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ tar xf nghttp2-X.Y.Z.tar.bz2
|
||||||
|
$ cd nghttp2-X.Y.Z
|
||||||
|
$ ./configure
|
||||||
|
$ make
|
||||||
|
|
||||||
|
Building from git
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Building from git is easy, but please be sure that at least autoconf 2.68 is
|
||||||
|
used:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ git submodule update --init
|
||||||
|
$ autoreconf -i
|
||||||
|
$ automake
|
||||||
|
$ autoconf
|
||||||
|
$ ./configure
|
||||||
|
$ make
|
||||||
|
|
||||||
Notes for building on Windows (MSVC)
|
Notes for building on Windows (MSVC)
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
@@ -243,6 +273,18 @@ If you want to compile the applications under ``examples/``, you need
|
|||||||
to remove or rename the ``event.h`` from libev's installation, because
|
to remove or rename the ``event.h`` from libev's installation, because
|
||||||
it conflicts with libevent's installation.
|
it conflicts with libevent's installation.
|
||||||
|
|
||||||
|
Notes for installation on Linux systems
|
||||||
|
--------------------------------------------
|
||||||
|
After installing nghttp2 tool suite with ``make install`` one might experience a similar error:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
nghttpx: error while loading shared libraries: libnghttp2.so.14: cannot open shared object file: No such file or directory
|
||||||
|
|
||||||
|
This means that the tool is unable to locate the ``libnghttp2.so`` shared library.
|
||||||
|
|
||||||
|
To update the shared library cache run ``sudo ldconfig``.
|
||||||
|
|
||||||
Building the documentation
|
Building the documentation
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
@@ -278,7 +320,6 @@ its testing framework. We depend on the following libraries:
|
|||||||
* golang.org/x/net/http2
|
* golang.org/x/net/http2
|
||||||
* golang.org/x/net/websocket
|
* golang.org/x/net/websocket
|
||||||
* https://github.com/tatsuhiro-t/go-nghttp2
|
* https://github.com/tatsuhiro-t/go-nghttp2
|
||||||
* https://github.com/tatsuhiro-t/spdy
|
|
||||||
|
|
||||||
To download the above packages, after settings ``GOPATH``, run the
|
To download the above packages, after settings ``GOPATH``, run the
|
||||||
following command under ``integration-tests`` directory:
|
following command under ``integration-tests`` directory:
|
||||||
@@ -296,11 +337,6 @@ To run the tests, run the following command under
|
|||||||
|
|
||||||
Inside the tests, we use port 3009 to run the test subject server.
|
Inside the tests, we use port 3009 to run the test subject server.
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
github.com/tatsuhiro-t/spdy is a copy used to be available at
|
|
||||||
golang.org/x/net/spdy, but it is now gone.
|
|
||||||
|
|
||||||
Migration from v0.7.15 or earlier
|
Migration from v0.7.15 or earlier
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
@@ -701,7 +737,7 @@ information. Here is sample output from ``nghttpd``:
|
|||||||
nghttpx - proxy
|
nghttpx - proxy
|
||||||
+++++++++++++++
|
+++++++++++++++
|
||||||
|
|
||||||
``nghttpx`` is a multi-threaded reverse proxy for HTTP/2, SPDY and
|
``nghttpx`` is a multi-threaded reverse proxy for HTTP/2, and
|
||||||
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server
|
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server
|
||||||
push.
|
push.
|
||||||
|
|
||||||
@@ -716,31 +752,30 @@ to know how to migrate from earlier releases.
|
|||||||
``nghttpx`` implements `important performance-oriented features
|
``nghttpx`` implements `important performance-oriented features
|
||||||
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
|
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
|
||||||
session IDs, session tickets (with automatic key rotation), OCSP
|
session IDs, session tickets (with automatic key rotation), OCSP
|
||||||
stapling, dynamic record sizing, ALPN/NPN, forward secrecy and SPDY &
|
stapling, dynamic record sizing, ALPN/NPN, forward secrecy and HTTP/2.
|
||||||
HTTP/2. ``nghttpx`` also offers the functionality to share session
|
``nghttpx`` also offers the functionality to share session cache and
|
||||||
cache and ticket keys among multiple ``nghttpx`` instances via
|
ticket keys among multiple ``nghttpx`` instances via memcached.
|
||||||
memcached.
|
|
||||||
|
|
||||||
``nghttpx`` has 2 operation modes:
|
``nghttpx`` has 2 operation modes:
|
||||||
|
|
||||||
================== ====================== ================ =============
|
================== ================ ================ =============
|
||||||
Mode option Frontend Backend Note
|
Mode option Frontend Backend Note
|
||||||
================== ====================== ================ =============
|
================== ================ ================ =============
|
||||||
default mode HTTP/2, SPDY, HTTP/1.1 HTTP/1.1, HTTP/2 Reverse proxy
|
default mode HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Reverse proxy
|
||||||
``--http2-proxy`` HTTP/2, SPDY, HTTP/1.1 HTTP/1.1, HTTP/2 Forward proxy
|
``--http2-proxy`` HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Forward proxy
|
||||||
================== ====================== ================ =============
|
================== ================ ================ =============
|
||||||
|
|
||||||
The interesting mode at the moment is the default mode. It works like
|
The interesting mode at the moment is the default mode. It works like
|
||||||
a reverse proxy and listens for HTTP/2, SPDY and HTTP/1.1 and can be
|
a reverse proxy and listens for HTTP/2, and HTTP/1.1 and can be
|
||||||
deployed as a SSL/TLS terminator for existing web server.
|
deployed as a SSL/TLS terminator for existing web server.
|
||||||
|
|
||||||
In all modes, the frontend connections are encrypted by SSL/TLS by
|
In all modes, the frontend connections are encrypted by SSL/TLS by
|
||||||
default. To disable encryption, use the ``no-tls`` keyword in
|
default. To disable encryption, use the ``no-tls`` keyword in
|
||||||
``--frontend`` option. If encryption is disabled, SPDY is disabled in
|
``--frontend`` option. If encryption is disabled, incoming HTTP/1.1
|
||||||
the frontend and incoming HTTP/1.1 connections can be upgraded to
|
connections can be upgraded to HTTP/2 through HTTP Upgrade. On the
|
||||||
HTTP/2 through HTTP Upgrade. On the other hard, backend connections
|
other hard, backend connections are not encrypted by default. To
|
||||||
are not encrypted by default. To encrypt backend connections, use
|
encrypt backend connections, use ``tls`` keyword in ``--backend``
|
||||||
``tls`` keyword in ``--backend`` option.
|
option.
|
||||||
|
|
||||||
``nghttpx`` supports a configuration file. See the ``--conf`` option and
|
``nghttpx`` supports a configuration file. See the ``--conf`` option and
|
||||||
sample configuration file ``nghttpx.conf.sample``.
|
sample configuration file ``nghttpx.conf.sample``.
|
||||||
@@ -750,16 +785,16 @@ server:
|
|||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Web Server
|
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Web Server
|
||||||
[reverse proxy]
|
[reverse proxy]
|
||||||
|
|
||||||
With the ``--http2-proxy`` option, it works as forward proxy, and it
|
With the ``--http2-proxy`` option, it works as forward proxy, and it
|
||||||
is so called secure HTTP/2 proxy (aka SPDY proxy):
|
is so called secure HTTP/2 proxy:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
|
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
|
||||||
[secure proxy] (e.g., Squid, ATS)
|
[secure proxy] (e.g., Squid, ATS)
|
||||||
|
|
||||||
The ``Client`` in the above example needs to be configured to use
|
The ``Client`` in the above example needs to be configured to use
|
||||||
``nghttpx`` as secure proxy.
|
``nghttpx`` as secure proxy.
|
||||||
@@ -791,7 +826,7 @@ proxy through an HTTP proxy:
|
|||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
Client <-- (HTTP/2, SPDY, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
|
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
|
||||||
|
|
||||||
--===================---> HTTP/2 Proxy
|
--===================---> HTTP/2 Proxy
|
||||||
(HTTP proxy tunnel) (e.g., nghttpx -s)
|
(HTTP proxy tunnel) (e.g., nghttpx -s)
|
||||||
@@ -799,9 +834,8 @@ proxy through an HTTP proxy:
|
|||||||
Benchmarking tool
|
Benchmarking tool
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The ``h2load`` program is a benchmarking tool for HTTP/2 and SPDY.
|
The ``h2load`` program is a benchmarking tool for HTTP/2. The UI of
|
||||||
The SPDY support is enabled if the program was built with the spdylay
|
``h2load`` is heavily inspired by ``weighttp``
|
||||||
library. The UI of ``h2load`` is heavily inspired by ``weighttp``
|
|
||||||
(https://github.com/lighttpd/weighttp). The typical usage is as
|
(https://github.com/lighttpd/weighttp). The typical usage is as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
|
|
||||||
/* Hint to the compiler that a function parameter is not used */
|
|
||||||
#define _U_ @HINT_UNUSED_PARAM@
|
|
||||||
|
|
||||||
/* Hint to the compiler that a function never returns */
|
/* Hint to the compiler that a function never returns */
|
||||||
#define NGHTTP2_NORETURN @HINT_NORETURN@
|
#define NGHTTP2_NORETURN @HINT_NORETURN@
|
||||||
|
|
||||||
@@ -38,6 +34,9 @@
|
|||||||
/* Define to 1 if you have the `accept4` function. */
|
/* Define to 1 if you have the `accept4` function. */
|
||||||
#cmakedefine HAVE_ACCEPT4 1
|
#cmakedefine HAVE_ACCEPT4 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `mkostemp` function. */
|
||||||
|
#cmakedefine HAVE_MKOSTEMP 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `initgroups` function. */
|
/* Define to 1 if you have the `initgroups` function. */
|
||||||
#cmakedefine01 HAVE_DECL_INITGROUPS
|
#cmakedefine01 HAVE_DECL_INITGROUPS
|
||||||
|
|
||||||
|
|||||||
48
configure.ac
48
configure.ac
@@ -25,7 +25,7 @@ dnl Do not change user variables!
|
|||||||
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
||||||
|
|
||||||
AC_PREREQ(2.61)
|
AC_PREREQ(2.61)
|
||||||
AC_INIT([nghttp2], [1.20.0], [t-tujikawa@users.sourceforge.net])
|
AC_INIT([nghttp2], [1.31.0], [t-tujikawa@users.sourceforge.net])
|
||||||
AC_CONFIG_AUX_DIR([.])
|
AC_CONFIG_AUX_DIR([.])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
@@ -44,9 +44,9 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
|||||||
|
|
||||||
dnl See versioning rule:
|
dnl See versioning rule:
|
||||||
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||||
AC_SUBST(LT_CURRENT, 27)
|
AC_SUBST(LT_CURRENT, 30)
|
||||||
AC_SUBST(LT_REVISION, 0)
|
AC_SUBST(LT_REVISION, 0)
|
||||||
AC_SUBST(LT_AGE, 13)
|
AC_SUBST(LT_AGE, 16)
|
||||||
|
|
||||||
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
|
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
|
||||||
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
|
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
|
||||||
@@ -117,11 +117,6 @@ AC_ARG_WITH([jemalloc],
|
|||||||
[Use jemalloc [default=check]])],
|
[Use jemalloc [default=check]])],
|
||||||
[request_jemalloc=$withval], [request_jemalloc=check])
|
[request_jemalloc=$withval], [request_jemalloc=check])
|
||||||
|
|
||||||
AC_ARG_WITH([spdylay],
|
|
||||||
[AS_HELP_STRING([--with-spdylay],
|
|
||||||
[Use spdylay [default=no]])],
|
|
||||||
[request_spdylay=$withval], [request_spdylay=no])
|
|
||||||
|
|
||||||
AC_ARG_WITH([systemd],
|
AC_ARG_WITH([systemd],
|
||||||
[AS_HELP_STRING([--with-systemd],
|
[AS_HELP_STRING([--with-systemd],
|
||||||
[Enable systemd support in nghttpx [default=check]])],
|
[Enable systemd support in nghttpx [default=check]])],
|
||||||
@@ -176,19 +171,9 @@ else
|
|||||||
AC_SUBST([CYTHON])
|
AC_SUBST([CYTHON])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
|
||||||
# If we're running GCC or clang define _U_ to be "__attribute__((unused))"
|
|
||||||
# so we can use _U_ to flag unused function parameters and not get warnings
|
|
||||||
# about them. Otherwise, define _U_ to be an empty string so that _U_ used
|
|
||||||
# to flag an unused function parameters will compile with other compilers.
|
|
||||||
#
|
|
||||||
# XXX - similar hints for other compilers?
|
|
||||||
#
|
|
||||||
if test "x$GCC" = "xyes" -o "x$CC" = "xclang" ; then
|
if test "x$GCC" = "xyes" -o "x$CC" = "xclang" ; then
|
||||||
AC_DEFINE([_U_], [__attribute__((unused))], [Hint to the compiler that a function parameters is not used])
|
|
||||||
AC_DEFINE([NGHTTP2_NORETURN], [__attribute__((noreturn))], [Hint to the compiler that a function never return])
|
AC_DEFINE([NGHTTP2_NORETURN], [__attribute__((noreturn))], [Hint to the compiler that a function never return])
|
||||||
else
|
else
|
||||||
AC_DEFINE([_U_], , [Hint to the compiler that a function parameter is not used])
|
|
||||||
AC_DEFINE([NGHTTP2_NORETURN], , [Hint to the compiler that a function never return])
|
AC_DEFINE([NGHTTP2_NORETURN], , [Hint to the compiler that a function never return])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -420,7 +405,7 @@ if test "x${request_systemd}" = "xyes" &&
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# libxml2 (for src/nghttp)
|
# libxml2 (for src/nghttp)
|
||||||
PKG_CHECK_MODULES([LIBXML2], [libxml-2.0 >= 2.7.7],
|
PKG_CHECK_MODULES([LIBXML2], [libxml-2.0 >= 2.6.26],
|
||||||
[have_libxml2=yes], [have_libxml2=no])
|
[have_libxml2=yes], [have_libxml2=no])
|
||||||
if test "x${have_libxml2}" = "xyes"; then
|
if test "x${have_libxml2}" = "xyes"; then
|
||||||
AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have `libxml2` library.])
|
AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have `libxml2` library.])
|
||||||
@@ -468,26 +453,6 @@ if test "x${request_jemalloc}" = "xyes" &&
|
|||||||
AC_MSG_ERROR([jemalloc was requested (--with-jemalloc) but not found])
|
AC_MSG_ERROR([jemalloc was requested (--with-jemalloc) but not found])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# spdylay (for src/nghttpx and src/h2load)
|
|
||||||
have_spdylay=no
|
|
||||||
if test "x${request_spdylay}" != "xno"; then
|
|
||||||
PKG_CHECK_MODULES([LIBSPDYLAY], [libspdylay >= 1.3.2],
|
|
||||||
[have_spdylay=yes], [have_spdylay=no])
|
|
||||||
if test "x${have_spdylay}" = "xyes"; then
|
|
||||||
AC_DEFINE([HAVE_SPDYLAY], [1], [Define to 1 if you have `spdylay` library.])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE($LIBSPDYLAY_PKG_ERRORS)
|
|
||||||
AC_MSG_NOTICE([The SPDY support in nghttpx and h2load will be disabled.])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x${request_spdylay}" = "xyes" &&
|
|
||||||
test "x${have_spdylay}" != "xyes"; then
|
|
||||||
AC_MSG_ERROR([spdylay was requested (--with-spdylay) but not found])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AM_CONDITIONAL([HAVE_SPDYLAY], [ test "x${have_spdylay}" = "xyes" ])
|
|
||||||
|
|
||||||
# Check Boost Asio library
|
# Check Boost Asio library
|
||||||
have_asio_lib=no
|
have_asio_lib=no
|
||||||
|
|
||||||
@@ -723,6 +688,7 @@ AC_CHECK_FUNCS([ \
|
|||||||
memchr \
|
memchr \
|
||||||
memmove \
|
memmove \
|
||||||
memset \
|
memset \
|
||||||
|
mkostemp \
|
||||||
socket \
|
socket \
|
||||||
sqrt \
|
sqrt \
|
||||||
strchr \
|
strchr \
|
||||||
@@ -814,6 +780,9 @@ if test "x$werror" != "xno"; then
|
|||||||
AX_CHECK_COMPILE_FLAG([-Werror], [CXXFLAGS="$CXXFLAGS -Werror"])
|
AX_CHECK_COMPILE_FLAG([-Werror], [CXXFLAGS="$CXXFLAGS -Werror"])
|
||||||
AX_CHECK_COMPILE_FLAG([-Wformat-security], [CXXFLAGS="$CXXFLAGS -Wformat-security"])
|
AX_CHECK_COMPILE_FLAG([-Wformat-security], [CXXFLAGS="$CXXFLAGS -Wformat-security"])
|
||||||
AX_CHECK_COMPILE_FLAG([-Wsometimes-uninitialized], [CXXFLAGS="$CXXFLAGS -Wsometimes-uninitialized"])
|
AX_CHECK_COMPILE_FLAG([-Wsometimes-uninitialized], [CXXFLAGS="$CXXFLAGS -Wsometimes-uninitialized"])
|
||||||
|
# Disable noexcept-type warning of g++-7. This is not harmful as
|
||||||
|
# long as all source files are compiled with the same compiler.
|
||||||
|
AX_CHECK_COMPILE_FLAG([-Wno-noexcept-type], [CXXFLAGS="$CXXFLAGS -Wno-noexcept-type"])
|
||||||
AC_LANG_POP()
|
AC_LANG_POP()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -934,7 +903,6 @@ AC_MSG_NOTICE([summary of build options:
|
|||||||
Libev: ${have_libev} (CFLAGS='${LIBEV_CFLAGS}' LIBS='${LIBEV_LIBS}')
|
Libev: ${have_libev} (CFLAGS='${LIBEV_CFLAGS}' LIBS='${LIBEV_LIBS}')
|
||||||
Libc-ares ${have_libcares} (CFLAGS='${LIBCARES_CFLAGS}' LIBS='${LIBCARES_LIBS}')
|
Libc-ares ${have_libcares} (CFLAGS='${LIBCARES_CFLAGS}' LIBS='${LIBCARES_LIBS}')
|
||||||
Libevent(SSL): ${have_libevent_openssl} (CFLAGS='${LIBEVENT_OPENSSL_CFLAGS}' LIBS='${LIBEVENT_OPENSSL_LIBS}')
|
Libevent(SSL): ${have_libevent_openssl} (CFLAGS='${LIBEVENT_OPENSSL_CFLAGS}' LIBS='${LIBEVENT_OPENSSL_LIBS}')
|
||||||
Spdylay: ${have_spdylay} (CFLAGS='${LIBSPDYLAY_CFLAGS}' LIBS='${LIBSPDYLAY_LIBS}')
|
|
||||||
Jansson: ${have_jansson} (CFLAGS='${JANSSON_CFLAGS}' LIBS='${JANSSON_LIBS}')
|
Jansson: ${have_jansson} (CFLAGS='${JANSSON_CFLAGS}' LIBS='${JANSSON_LIBS}')
|
||||||
Jemalloc: ${have_jemalloc} (LIBS='${JEMALLOC_LIBS}')
|
Jemalloc: ${have_jemalloc} (LIBS='${JEMALLOC_LIBS}')
|
||||||
Zlib: ${have_zlib} (CFLAGS='${ZLIB_CFLAGS}' LIBS='${ZLIB_LIBS}')
|
Zlib: ${have_zlib} (CFLAGS='${ZLIB_CFLAGS}' LIBS='${ZLIB_LIBS}')
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ set(APIDOCS
|
|||||||
nghttp2_rcbuf_decref.rst
|
nghttp2_rcbuf_decref.rst
|
||||||
nghttp2_rcbuf_get_buf.rst
|
nghttp2_rcbuf_get_buf.rst
|
||||||
nghttp2_rcbuf_incref.rst
|
nghttp2_rcbuf_incref.rst
|
||||||
|
nghttp2_rcbuf_is_static.rst
|
||||||
nghttp2_select_next_protocol.rst
|
nghttp2_select_next_protocol.rst
|
||||||
nghttp2_session_callbacks_del.rst
|
nghttp2_session_callbacks_del.rst
|
||||||
nghttp2_session_callbacks_new.rst
|
nghttp2_session_callbacks_new.rst
|
||||||
|
|||||||
@@ -74,12 +74,14 @@ APIDOCS= \
|
|||||||
nghttp2_rcbuf_decref.rst \
|
nghttp2_rcbuf_decref.rst \
|
||||||
nghttp2_rcbuf_get_buf.rst \
|
nghttp2_rcbuf_get_buf.rst \
|
||||||
nghttp2_rcbuf_incref.rst \
|
nghttp2_rcbuf_incref.rst \
|
||||||
|
nghttp2_rcbuf_is_static.rst \
|
||||||
nghttp2_select_next_protocol.rst \
|
nghttp2_select_next_protocol.rst \
|
||||||
nghttp2_session_callbacks_del.rst \
|
nghttp2_session_callbacks_del.rst \
|
||||||
nghttp2_session_callbacks_new.rst \
|
nghttp2_session_callbacks_new.rst \
|
||||||
nghttp2_session_callbacks_set_before_frame_send_callback.rst \
|
nghttp2_session_callbacks_set_before_frame_send_callback.rst \
|
||||||
nghttp2_session_callbacks_set_data_source_read_length_callback.rst \
|
nghttp2_session_callbacks_set_data_source_read_length_callback.rst \
|
||||||
nghttp2_session_callbacks_set_error_callback.rst \
|
nghttp2_session_callbacks_set_error_callback.rst \
|
||||||
|
nghttp2_session_callbacks_set_error_callback2.rst \
|
||||||
nghttp2_session_callbacks_set_on_begin_frame_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_begin_headers_callback.rst \
|
||||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst \
|
nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst \
|
||||||
@@ -141,6 +143,7 @@ APIDOCS= \
|
|||||||
nghttp2_session_set_local_window_size.rst \
|
nghttp2_session_set_local_window_size.rst \
|
||||||
nghttp2_session_set_next_stream_id.rst \
|
nghttp2_session_set_next_stream_id.rst \
|
||||||
nghttp2_session_set_stream_user_data.rst \
|
nghttp2_session_set_stream_user_data.rst \
|
||||||
|
nghttp2_session_set_user_data.rst \
|
||||||
nghttp2_session_terminate_session.rst \
|
nghttp2_session_terminate_session.rst \
|
||||||
nghttp2_session_terminate_session2.rst \
|
nghttp2_session_terminate_session2.rst \
|
||||||
nghttp2_session_upgrade.rst \
|
nghttp2_session_upgrade.rst \
|
||||||
@@ -267,7 +270,7 @@ apiref.rst: \
|
|||||||
$(APIDOCS): apiref.rst
|
$(APIDOCS): apiref.rst
|
||||||
|
|
||||||
clean-local:
|
clean-local:
|
||||||
[ $(srcdir) = $(builddir) ] || for i in $(RST_FILES); do [ -e $(builddir)/$$i ] && rm -f $(builddir)/$$i; done
|
if [ $(srcdir) != $(builddir) ]; then for i in $(RST_FILES); do rm -f $(builddir)/$$i; done fi
|
||||||
-rm -f apiref.rst
|
-rm -f apiref.rst
|
||||||
-rm -f $(APIDOCS)
|
-rm -f $(APIDOCS)
|
||||||
-rm -rf $(BUILDDIR)/*
|
-rm -rf $(BUILDDIR)/*
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import re
|
|||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.parsers.rst import directives
|
from docutils.parsers.rst import directives
|
||||||
|
from docutils.parsers.rst import Directive
|
||||||
|
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
from sphinx import version_info
|
from sphinx import version_info
|
||||||
@@ -21,10 +22,8 @@ from sphinx.locale import l_, _
|
|||||||
from sphinx.domains import Domain, ObjType, Index
|
from sphinx.domains import Domain, ObjType, Index
|
||||||
from sphinx.directives import ObjectDescription
|
from sphinx.directives import ObjectDescription
|
||||||
from sphinx.util.nodes import make_refnode
|
from sphinx.util.nodes import make_refnode
|
||||||
from sphinx.util.compat import Directive
|
|
||||||
from sphinx.util.docfields import Field, GroupedField, TypedField
|
from sphinx.util.docfields import Field, GroupedField, TypedField
|
||||||
|
|
||||||
|
|
||||||
# REs for Ruby signatures
|
# REs for Ruby signatures
|
||||||
rb_sig_re = re.compile(
|
rb_sig_re = re.compile(
|
||||||
r'''^ ([\w.]*\.)? # class name(s)
|
r'''^ ([\w.]*\.)? # class name(s)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _h2load()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--connection-window-bits --clients --verbose --ciphers --rate --no-tls-proto --header-table-size --requests --base-uri --h1 --threads --npn-list --rate-period --data --version --connection-inactivity-timeout --timing-script-file --encoder-header-table-size --max-concurrent-streams --connection-active-timeout --input-file --help --window-bits --header ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--connection-window-bits --clients --verbose --ciphers --rate --no-tls-proto --header-table-size --requests --base-uri --h1 --threads --npn-list --rate-period --data --version --connection-inactivity-timeout --timing-script-file --encoder-header-table-size --max-concurrent-streams --connection-active-timeout --input-file --help --window-bits --warm-up-time --duration --header ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _nghttp()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --encoder-header-table-size --padding --hexdump --max-concurrent-streams --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 --expect-continue --stat --header ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --encoder-header-table-size --padding --hexdump --max-concurrent-streams --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 --expect-continue --stat --no-verify-peer --header ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _nghttpx()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--worker-read-rate --include --frontend-http2-dump-response-header --tls-ticket-key-file --verify-client-cacert --max-response-header-fields --backend-http2-window-size --frontend-keep-alive-timeout --backend-request-buffer --max-request-header-fields --fastopen --backend-connect-timeout --tls-max-proto-version --conf --dns-lookup-timeout --backend-http2-max-concurrent-streams --worker-write-burst --npn-list --dns-max-try --fetch-ocsp-response-file --no-via --tls-session-cache-memcached-cert-file --no-http2-cipher-black-list --mruby-file --client-no-http2-cipher-black-list --stream-read-timeout --client-ciphers --forwarded-for --accesslog-syslog --dns-cache-timeout --frontend-http2-read-timeout --listener-disable-timeout --ciphers --client-psk-secrets --strip-incoming-x-forwarded-for --no-server-rewrite --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --frontend-max-requests --rlimit-nofile --tls-ticket-key-memcached-cert-file --ocsp-update-interval --forwarded-by --tls-session-cache-memcached-private-key-file --error-page --backend-write-timeout --tls-dyn-rec-warmup-threshold --tls-ticket-key-memcached-max-retry --frontend-http2-window-size --http2-no-cookie-crumbling --worker-read-burst --dh-param-file --accesslog-format --errorlog-syslog --redirect-https-port --request-header-field-buffer --api-max-request-body --frontend-http2-decoder-dynamic-table-size --errorlog-file --frontend-http2-max-concurrent-streams --psk-secrets --frontend-write-timeout --tls-ticket-key-cipher --read-burst --backend --server-name --insecure --backend-max-backoff --log-level --host-rewrite --tls-ticket-key-memcached-interval --frontend-http2-setting-timeout --frontend-http2-connection-window-size --worker-frontend-connections --syslog-facility --no-server-push --no-location-rewrite --single-thread --tls-session-cache-memcached --no-ocsp --backend-response-buffer --tls-min-proto-version --workers --add-forwarded --worker-write-rate --add-request-header --backend-http2-settings-timeout --subcert --ecdh-curves --no-kqueue --help --frontend-frame-debug --tls-sct-dir --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --backend-http2-decoder-dynamic-table-size --user --add-x-forwarded-for --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --backend-connections-per-host --response-header-field-buffer --tls-ticket-key-memcached-address-family --padding --tls-session-cache-memcached-address-family --stream-write-timeout --cacert --tls-ticket-key-memcached-private-key-file --accesslog-write-early --backend-address-family --backend-http2-connection-window-size --version --add-response-header --backend-read-timeout --frontend-http2-optimize-window-size --frontend --accesslog-file --http2-proxy --backend-http2-encoder-dynamic-table-size --client-private-key-file --client-cert-file --tls-ticket-key-memcached --tls-dyn-rec-idle-timeout --frontend-http2-optimize-write-buffer-size --verify-client --frontend-http2-encoder-dynamic-table-size --read-rate --backend-connections-per-frontend --strip-incoming-forwarded ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--worker-read-rate --include --frontend-http2-dump-response-header --tls-ticket-key-file --verify-client-cacert --max-response-header-fields --backend-http2-window-size --frontend-keep-alive-timeout --backend-request-buffer --max-request-header-fields --backend-connect-timeout --tls-max-proto-version --conf --dns-lookup-timeout --backend-http2-max-concurrent-streams --worker-write-burst --npn-list --dns-max-try --fetch-ocsp-response-file --no-via --tls-session-cache-memcached-cert-file --no-http2-cipher-black-list --mruby-file --add-forwarded --client-no-http2-cipher-black-list --stream-read-timeout --client-ciphers --ocsp-update-interval --forwarded-for --accesslog-syslog --dns-cache-timeout --frontend-http2-read-timeout --listener-disable-timeout --ciphers --client-psk-secrets --strip-incoming-x-forwarded-for --no-server-rewrite --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --frontend-max-requests --rlimit-nofile --no-strip-incoming-x-forwarded-proto --tls-ticket-key-memcached-cert-file --no-verify-ocsp --forwarded-by --tls-session-cache-memcached-private-key-file --error-page --ocsp-startup --backend-write-timeout --tls-dyn-rec-warmup-threshold --tls-ticket-key-memcached-max-retry --frontend-http2-window-size --http2-no-cookie-crumbling --worker-read-burst --dh-param-file --accesslog-format --errorlog-syslog --redirect-https-port --request-header-field-buffer --api-max-request-body --frontend-http2-decoder-dynamic-table-size --errorlog-file --frontend-http2-max-concurrent-streams --psk-secrets --frontend-write-timeout --tls-ticket-key-cipher --read-burst --no-add-x-forwarded-proto --backend --server-name --insecure --backend-max-backoff --log-level --host-rewrite --tls-ticket-key-memcached-interval --frontend-http2-setting-timeout --frontend-http2-connection-window-size --worker-frontend-connections --syslog-facility --fastopen --no-location-rewrite --single-thread --tls-session-cache-memcached --no-ocsp --backend-response-buffer --tls-min-proto-version --workers --add-x-forwarded-for --no-server-push --worker-write-rate --add-request-header --backend-http2-settings-timeout --subcert --ecdh-curves --no-kqueue --help --frontend-frame-debug --tls-sct-dir --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --backend-http2-decoder-dynamic-table-size --user --verify-client-tolerate-expired --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --backend-connections-per-host --response-header-field-buffer --tls-ticket-key-memcached-address-family --padding --tls-session-cache-memcached-address-family --stream-write-timeout --cacert --tls-ticket-key-memcached-private-key-file --accesslog-write-early --backend-address-family --backend-http2-connection-window-size --version --add-response-header --backend-read-timeout --frontend-http2-optimize-window-size --frontend --accesslog-file --http2-proxy --backend-http2-encoder-dynamic-table-size --client-private-key-file --single-process --client-cert-file --tls-ticket-key-memcached --tls-dyn-rec-idle-timeout --frontend-http2-optimize-write-buffer-size --verify-client --frontend-http2-encoder-dynamic-table-size --read-rate --backend-connections-per-frontend --strip-incoming-forwarded ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ html_theme_path = ['@top_srcdir@/doc/_themes']
|
|||||||
|
|
||||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
# typographically correct entities.
|
# typographically correct entities.
|
||||||
html_use_smartypants = False
|
#html_use_smartypants = False
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
# Custom sidebar templates, maps document names to template names.
|
||||||
html_sidebars = {
|
html_sidebars = {
|
||||||
|
|||||||
2
doc/docutils.conf
Normal file
2
doc/docutils.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[parsers]
|
||||||
|
smart_quotes=no
|
||||||
36
doc/h2load.1
36
doc/h2load.1
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "H2LOAD" "1" "Feb 26, 2017" "1.20.0" "nghttp2"
|
.TH "H2LOAD" "1" "Feb 27, 2018" "1.31.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
h2load \- HTTP/2 benchmarking tool
|
h2load \- HTTP/2 benchmarking tool
|
||||||
.
|
.
|
||||||
@@ -35,7 +35,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|||||||
\fBh2load\fP [OPTIONS]... [URI]...
|
\fBh2load\fP [OPTIONS]... [URI]...
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.sp
|
.sp
|
||||||
benchmarking tool for HTTP/2 and SPDY server
|
benchmarking tool for HTTP/2 server
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B <URI>
|
.B <URI>
|
||||||
@@ -54,7 +54,9 @@ scheme, host or port values.
|
|||||||
Number of requests across all clients. If it is used
|
Number of requests across all clients. If it is used
|
||||||
with \fI\%\-\-timing\-script\-file\fP option, this option specifies
|
with \fI\%\-\-timing\-script\-file\fP option, this option specifies
|
||||||
the number of requests each client performs rather than
|
the number of requests each client performs rather than
|
||||||
the number of requests across all clients.
|
the number of requests across all clients. This option
|
||||||
|
is ignored if timing\-based benchmarking is enabled (see
|
||||||
|
\fI\%\-\-duration\fP option).
|
||||||
.sp
|
.sp
|
||||||
Default: \fB1\fP
|
Default: \fB1\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -99,7 +101,6 @@ Default: \fB1\fP
|
|||||||
.TP
|
.TP
|
||||||
.B \-w, \-\-window\-bits=<N>
|
.B \-w, \-\-window\-bits=<N>
|
||||||
Sets the stream level initial window size to (2**<N>)\-1.
|
Sets the stream level initial window size to (2**<N>)\-1.
|
||||||
For SPDY, 2**<N> is used instead.
|
|
||||||
.sp
|
.sp
|
||||||
Default: \fB30\fP
|
Default: \fB30\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -107,9 +108,7 @@ Default: \fB30\fP
|
|||||||
.TP
|
.TP
|
||||||
.B \-W, \-\-connection\-window\-bits=<N>
|
.B \-W, \-\-connection\-window\-bits=<N>
|
||||||
Sets the connection level initial window size to
|
Sets the connection level initial window size to
|
||||||
(2**<N>)\-1. For SPDY, if <N> is strictly less than 16,
|
(2**<N>)\-1.
|
||||||
this option is ignored. Otherwise 2**<N> is used for
|
|
||||||
SPDY.
|
|
||||||
.sp
|
.sp
|
||||||
Default: \fB30\fP
|
Default: \fB30\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -124,15 +123,14 @@ Add/Override a header to the requests.
|
|||||||
Set allowed cipher list. The format of the string is
|
Set allowed cipher list. The format of the string is
|
||||||
described in OpenSSL ciphers(1).
|
described in OpenSSL ciphers(1).
|
||||||
.sp
|
.sp
|
||||||
Default: \fBECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:DHE\-RSA\-AES128\-GCM\-SHA256:DHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-AES128\-SHA256:ECDHE\-RSA\-AES128\-SHA256:ECDHE\-ECDSA\-AES128\-SHA:ECDHE\-RSA\-AES256\-SHA384:ECDHE\-RSA\-AES128\-SHA:ECDHE\-ECDSA\-AES256\-SHA384:ECDHE\-ECDSA\-AES256\-SHA:ECDHE\-RSA\-AES256\-SHA:DHE\-RSA\-AES128\-SHA256:DHE\-RSA\-AES128\-SHA:DHE\-RSA\-AES256\-SHA256:DHE\-RSA\-AES256\-SHA:ECDHE\-ECDSA\-DES\-CBC3\-SHA:ECDHE\-RSA\-DES\-CBC3\-SHA:EDH\-RSA\-DES\-CBC3\-SHA:AES128\-GCM\-SHA256:AES256\-GCM\-SHA384:AES128\-SHA256:AES256\-SHA256:AES128\-SHA:AES256\-SHA:DES\-CBC3\-SHA:!DSS\fP
|
Default: \fBECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-SHA384:ECDHE\-RSA\-AES256\-SHA384:ECDHE\-ECDSA\-AES128\-SHA256:ECDHE\-RSA\-AES128\-SHA256\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-p, \-\-no\-tls\-proto=<PROTOID>
|
.B \-p, \-\-no\-tls\-proto=<PROTOID>
|
||||||
Specify ALPN identifier of the protocol to be used when
|
Specify ALPN identifier of the protocol to be used when
|
||||||
accessing http URI without SSL/TLS.
|
accessing http URI without SSL/TLS.
|
||||||
Available protocols: h2c and
|
Available protocols: h2c and http/1.1
|
||||||
http/1.1
|
|
||||||
.sp
|
.sp
|
||||||
Default: \fBh2c\fP
|
Default: \fBh2c\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -170,6 +168,19 @@ option is 1s.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-D, \-\-duration=<N>
|
||||||
|
Specifies the main duration for the measurements in case
|
||||||
|
of timing\-based benchmarking.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-warm\-up\-time=<DURATION>
|
||||||
|
Specifies the time period before starting the actual
|
||||||
|
measurements, in case of timing\-based benchmarking.
|
||||||
|
Needs to provided along with \fI\%\-D\fP option.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-T, \-\-connection\-active\-timeout=<DURATION>
|
.B \-T, \-\-connection\-active\-timeout=<DURATION>
|
||||||
Specifies the maximum time that h2load is willing to
|
Specifies the maximum time that h2load is willing to
|
||||||
keep a connection open, regardless of the activity on
|
keep a connection open, regardless of the activity on
|
||||||
@@ -335,8 +346,7 @@ compression. Let \fBdecompressed(headers)\fP to the number of bytes
|
|||||||
used for header fields after decompression. The \fBspace savings\fP
|
used for header fields after decompression. The \fBspace savings\fP
|
||||||
is calculated by (1 \- \fBheaders\fP / \fBdecompressed(headers)\fP) *
|
is calculated by (1 \- \fBheaders\fP / \fBdecompressed(headers)\fP) *
|
||||||
100. For HTTP/1.1, this is usually 0.00%, since it does not have
|
100. For HTTP/1.1, this is usually 0.00%, since it does not have
|
||||||
header compression. For HTTP/2 and SPDY, it shows some insightful
|
header compression. For HTTP/2, it shows some insightful numbers.
|
||||||
numbers.
|
|
||||||
.TP
|
.TP
|
||||||
.B data
|
.B data
|
||||||
The number of response body bytes received from the server.
|
The number of response body bytes received from the server.
|
||||||
@@ -433,7 +443,7 @@ h2load sets large flow control window by default, and effectively
|
|||||||
disables flow control to avoid under utilization of server
|
disables flow control to avoid under utilization of server
|
||||||
performance. To set smaller flow control window, use \fI\%\-w\fP and
|
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
|
\fI\%\-W\fP options. For example, use \fB\-w16 \-W16\fP to set default
|
||||||
window size described in HTTP/2 and SPDY protocol specification.
|
window size described in HTTP/2 protocol specification.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.sp
|
.sp
|
||||||
\fBnghttp(1)\fP, \fBnghttpd(1)\fP, \fBnghttpx(1)\fP
|
\fBnghttp(1)\fP, \fBnghttpd(1)\fP, \fBnghttpx(1)\fP
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ SYNOPSIS
|
|||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
benchmarking tool for HTTP/2 and SPDY server
|
benchmarking tool for HTTP/2 server
|
||||||
|
|
||||||
.. describe:: <URI>
|
.. describe:: <URI>
|
||||||
|
|
||||||
@@ -34,7 +34,9 @@ OPTIONS
|
|||||||
Number of requests across all clients. If it is used
|
Number of requests across all clients. If it is used
|
||||||
with :option:`--timing-script-file` option, this option specifies
|
with :option:`--timing-script-file` option, this option specifies
|
||||||
the number of requests each client performs rather than
|
the number of requests each client performs rather than
|
||||||
the number of requests across all clients.
|
the number of requests across all clients. This option
|
||||||
|
is ignored if timing-based benchmarking is enabled (see
|
||||||
|
:option:`--duration` option).
|
||||||
|
|
||||||
Default: ``1``
|
Default: ``1``
|
||||||
|
|
||||||
@@ -74,16 +76,13 @@ OPTIONS
|
|||||||
.. option:: -w, --window-bits=<N>
|
.. option:: -w, --window-bits=<N>
|
||||||
|
|
||||||
Sets the stream level initial window size to (2\*\*<N>)-1.
|
Sets the stream level initial window size to (2\*\*<N>)-1.
|
||||||
For SPDY, 2\*\*<N> is used instead.
|
|
||||||
|
|
||||||
Default: ``30``
|
Default: ``30``
|
||||||
|
|
||||||
.. option:: -W, --connection-window-bits=<N>
|
.. option:: -W, --connection-window-bits=<N>
|
||||||
|
|
||||||
Sets the connection level initial window size to
|
Sets the connection level initial window size to
|
||||||
(2\*\*<N>)-1. For SPDY, if <N> is strictly less than 16,
|
(2\*\*<N>)-1.
|
||||||
this option is ignored. Otherwise 2\*\*<N> is used for
|
|
||||||
SPDY.
|
|
||||||
|
|
||||||
Default: ``30``
|
Default: ``30``
|
||||||
|
|
||||||
@@ -96,14 +95,13 @@ OPTIONS
|
|||||||
Set allowed cipher list. The format of the string is
|
Set allowed cipher list. The format of the string is
|
||||||
described in OpenSSL ciphers(1).
|
described in OpenSSL ciphers(1).
|
||||||
|
|
||||||
Default: ``ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS``
|
Default: ``ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256``
|
||||||
|
|
||||||
.. option:: -p, --no-tls-proto=<PROTOID>
|
.. option:: -p, --no-tls-proto=<PROTOID>
|
||||||
|
|
||||||
Specify ALPN identifier of the protocol to be used when
|
Specify ALPN identifier of the protocol to be used when
|
||||||
accessing http URI without SSL/TLS.
|
accessing http URI without SSL/TLS.
|
||||||
Available protocols: h2c and
|
Available protocols: h2c and http/1.1
|
||||||
http/1.1
|
|
||||||
|
|
||||||
Default: ``h2c``
|
Default: ``h2c``
|
||||||
|
|
||||||
@@ -136,6 +134,17 @@ OPTIONS
|
|||||||
the rate option is not used. The default value for this
|
the rate option is not used. The default value for this
|
||||||
option is 1s.
|
option is 1s.
|
||||||
|
|
||||||
|
.. option:: -D, --duration=<N>
|
||||||
|
|
||||||
|
Specifies the main duration for the measurements in case
|
||||||
|
of timing-based benchmarking.
|
||||||
|
|
||||||
|
.. option:: --warm-up-time=<DURATION>
|
||||||
|
|
||||||
|
Specifies the time period before starting the actual
|
||||||
|
measurements, in case of timing-based benchmarking.
|
||||||
|
Needs to provided along with :option:`-D` option.
|
||||||
|
|
||||||
.. option:: -T, --connection-active-timeout=<DURATION>
|
.. option:: -T, --connection-active-timeout=<DURATION>
|
||||||
|
|
||||||
Specifies the maximum time that h2load is willing to
|
Specifies the maximum time that h2load is willing to
|
||||||
@@ -284,8 +293,7 @@ traffic
|
|||||||
used for header fields after decompression. The ``space savings``
|
used for header fields after decompression. The ``space savings``
|
||||||
is calculated by (1 - ``headers`` / ``decompressed(headers)``) *
|
is calculated by (1 - ``headers`` / ``decompressed(headers)``) *
|
||||||
100. For HTTP/1.1, this is usually 0.00%, since it does not have
|
100. For HTTP/1.1, this is usually 0.00%, since it does not have
|
||||||
header compression. For HTTP/2 and SPDY, it shows some insightful
|
header compression. For HTTP/2, it shows some insightful numbers.
|
||||||
numbers.
|
|
||||||
data
|
data
|
||||||
The number of response body bytes received from the server.
|
The number of response body bytes received from the server.
|
||||||
|
|
||||||
@@ -353,7 +361,7 @@ h2load sets large flow control window by default, and effectively
|
|||||||
disables flow control to avoid under utilization of server
|
disables flow control to avoid under utilization of server
|
||||||
performance. To set smaller flow control window, use :option:`-w` and
|
performance. To set smaller flow control window, use :option:`-w` and
|
||||||
:option:`-W` options. For example, use ``-w16 -W16`` to set default
|
:option:`-W` options. For example, use ``-w16 -W16`` to set default
|
||||||
window size described in HTTP/2 and SPDY protocol specification.
|
window size described in HTTP/2 protocol specification.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ traffic
|
|||||||
used for header fields after decompression. The ``space savings``
|
used for header fields after decompression. The ``space savings``
|
||||||
is calculated by (1 - ``headers`` / ``decompressed(headers)``) *
|
is calculated by (1 - ``headers`` / ``decompressed(headers)``) *
|
||||||
100. For HTTP/1.1, this is usually 0.00%, since it does not have
|
100. For HTTP/1.1, this is usually 0.00%, since it does not have
|
||||||
header compression. For HTTP/2 and SPDY, it shows some insightful
|
header compression. For HTTP/2, it shows some insightful numbers.
|
||||||
numbers.
|
|
||||||
data
|
data
|
||||||
The number of response body bytes received from the server.
|
The number of response body bytes received from the server.
|
||||||
|
|
||||||
@@ -110,7 +109,7 @@ h2load sets large flow control window by default, and effectively
|
|||||||
disables flow control to avoid under utilization of server
|
disables flow control to avoid under utilization of server
|
||||||
performance. To set smaller flow control window, use :option:`-w` and
|
performance. To set smaller flow control window, use :option:`-w` and
|
||||||
:option:`-W` options. For example, use ``-w16 -W16`` to set default
|
:option:`-W` options. For example, use ``-w16 -W16`` to set default
|
||||||
window size described in HTTP/2 and SPDY protocol specification.
|
window size described in HTTP/2 protocol specification.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTP" "1" "Feb 26, 2017" "1.20.0" "nghttp2"
|
.TH "NGHTTP" "1" "Feb 27, 2018" "1.31.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttp \- HTTP/2 client
|
nghttp \- HTTP/2 client
|
||||||
.
|
.
|
||||||
@@ -236,6 +236,12 @@ combined with the \fI\%\-d\fP option.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-y, \-\-no\-verify\-peer
|
||||||
|
Suppress warning on server certificate verification
|
||||||
|
failure.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-version
|
.B \-\-version
|
||||||
Display version information and exit.
|
Display version information and exit.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
|||||||
@@ -186,6 +186,11 @@ OPTIONS
|
|||||||
Continue interim response. This option is ignored unless
|
Continue interim response. This option is ignored unless
|
||||||
combined with the :option:`-d` option.
|
combined with the :option:`-d` option.
|
||||||
|
|
||||||
|
.. option:: -y, --no-verify-peer
|
||||||
|
|
||||||
|
Suppress warning on server certificate verification
|
||||||
|
failure.
|
||||||
|
|
||||||
.. option:: --version
|
.. option:: --version
|
||||||
|
|
||||||
Display version information and exit.
|
Display version information and exit.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTPD" "1" "Feb 26, 2017" "1.20.0" "nghttp2"
|
.TH "NGHTTPD" "1" "Feb 27, 2018" "1.31.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpd \- HTTP/2 server
|
nghttpd \- HTTP/2 server
|
||||||
.
|
.
|
||||||
|
|||||||
326
doc/nghttpx.1
326
doc/nghttpx.1
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTPX" "1" "Feb 26, 2017" "1.20.0" "nghttp2"
|
.TH "NGHTTPX" "1" "Feb 27, 2018" "1.31.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpx \- HTTP/2 proxy
|
nghttpx \- HTTP/2 proxy
|
||||||
.
|
.
|
||||||
@@ -35,7 +35,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|||||||
\fBnghttpx\fP [OPTIONS]... [<PRIVATE_KEY> <CERT>]
|
\fBnghttpx\fP [OPTIONS]... [<PRIVATE_KEY> <CERT>]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.sp
|
.sp
|
||||||
A reverse proxy for HTTP/2, HTTP/1 and SPDY.
|
A reverse proxy for HTTP/2, and HTTP/1.
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B <PRIVATE_KEY>
|
.B <PRIVATE_KEY>
|
||||||
@@ -62,8 +62,7 @@ domain socket can be specified by prefixing path name
|
|||||||
with "unix:" (e.g., unix:/var/run/backend.sock).
|
with "unix:" (e.g., unix:/var/run/backend.sock).
|
||||||
.sp
|
.sp
|
||||||
Optionally, if <PATTERN>s are given, the backend address
|
Optionally, if <PATTERN>s are given, the backend address
|
||||||
is only used if request matches the pattern. If
|
is only used if request matches the pattern. The
|
||||||
\fI\%\-\-http2\-proxy\fP is used, <PATTERN>s are ignored. The
|
|
||||||
pattern matching is closely designed to ServeMux in
|
pattern matching is closely designed to ServeMux in
|
||||||
net/http package of Go programming language. <PATTERN>
|
net/http package of Go programming language. <PATTERN>
|
||||||
consists of path, host + path or just host. The path
|
consists of path, host + path or just host. The path
|
||||||
@@ -74,11 +73,16 @@ path which ends with "\fI/\fP" also matches the request path
|
|||||||
which only lacks trailing \(aq\fI/\fP\(aq (e.g., path "\fI/foo/\fP"
|
which only lacks trailing \(aq\fI/\fP\(aq (e.g., path "\fI/foo/\fP"
|
||||||
matches request path "\fI/foo\fP"). If it does not end with
|
matches request path "\fI/foo\fP"). If it does not end with
|
||||||
"\fI/\fP", it performs exact match against the request path.
|
"\fI/\fP", it performs exact match against the request path.
|
||||||
If host is given, it performs exact match against the
|
If host is given, it performs a match against the
|
||||||
request host. If host alone is given, "\fI/\fP" is appended
|
request host. For a request received on the frontend
|
||||||
to it, so that it matches all request paths under the
|
listener with "sni\-fwd" parameter enabled, SNI host is
|
||||||
host (e.g., specifying "nghttp2.org" equals to
|
used instead of a request host. If host alone is given,
|
||||||
"nghttp2.org/").
|
"\fI/\fP" is appended to it, so that it matches all request
|
||||||
|
paths under the host (e.g., specifying "nghttp2.org"
|
||||||
|
equals to "nghttp2.org/"). CONNECT method is treated
|
||||||
|
specially. It does not have path, and we don\(aqt allow
|
||||||
|
empty path. To workaround this, we assume that CONNECT
|
||||||
|
method has "\fI/\fP" as path.
|
||||||
.sp
|
.sp
|
||||||
Patterns with host take precedence over patterns with
|
Patterns with host take precedence over patterns with
|
||||||
just path. Then, longer patterns take precedence over
|
just path. Then, longer patterns take precedence over
|
||||||
@@ -92,6 +96,18 @@ host pattern "*.nghttp2.org" matches against
|
|||||||
match against "nghttp2.org". The exact hosts match
|
match against "nghttp2.org". The exact hosts match
|
||||||
takes precedence over the wildcard hosts match.
|
takes precedence over the wildcard hosts match.
|
||||||
.sp
|
.sp
|
||||||
|
If path part ends with "*", it is treated as wildcard
|
||||||
|
path. The wildcard path behaves differently from the
|
||||||
|
normal path. For normal path, match is made around the
|
||||||
|
boundary of path component separator,"\fI/\fP". On the other
|
||||||
|
hand, the wildcard path does not take into account the
|
||||||
|
path component separator. All paths which include the
|
||||||
|
wildcard path without last "*" as prefix, and are
|
||||||
|
strictly longer than wildcard path without last "*" are
|
||||||
|
matched. "*" must match at least one character. For
|
||||||
|
example, the pattern "\fI/foo*\fP" matches "\fI/foo/\fP" and
|
||||||
|
"\fI/foobar\fP". But it does not match "\fI/foo\fP", or "\fI/fo\fP".
|
||||||
|
.sp
|
||||||
If <PATTERN> is omitted or empty string, "\fI/\fP" is used as
|
If <PATTERN> is omitted or empty string, "\fI/\fP" is used as
|
||||||
pattern, which matches all request paths (catch\-all
|
pattern, which matches all request paths (catch\-all
|
||||||
pattern). The catch\-all backend must be given.
|
pattern). The catch\-all backend must be given.
|
||||||
@@ -164,16 +180,32 @@ state, and this is the default behaviour.
|
|||||||
The session affinity is enabled using
|
The session affinity is enabled using
|
||||||
"affinity=<METHOD>" parameter. If "ip" is given in
|
"affinity=<METHOD>" parameter. If "ip" is given in
|
||||||
<METHOD>, client IP based session affinity is enabled.
|
<METHOD>, client IP based session affinity is enabled.
|
||||||
If "none" is given in <METHOD>, session affinity is
|
If "cookie" is given in <METHOD>, cookie based session
|
||||||
disabled, and this is the default. The session affinity
|
affinity is enabled. If "none" is given in <METHOD>,
|
||||||
is enabled per <PATTERN>. If at least one backend has
|
session affinity is disabled, and this is the default.
|
||||||
"affinity" parameter, and its <METHOD> is not "none",
|
The session affinity is enabled per <PATTERN>. If at
|
||||||
session affinity is enabled for all backend servers
|
least one backend has "affinity" parameter, and its
|
||||||
sharing the same <PATTERN>. It is advised to set
|
<METHOD> is not "none", session affinity is enabled for
|
||||||
"affinity" parameter to all backend explicitly if
|
all backend servers sharing the same <PATTERN>. It is
|
||||||
session affinity is desired. The session affinity may
|
advised to set "affinity" parameter to all backend
|
||||||
break if one of the backend gets unreachable, or backend
|
explicitly if session affinity is desired. The session
|
||||||
settings are reloaded or replaced by API.
|
affinity may break if one of the backend gets
|
||||||
|
unreachable, or backend settings are reloaded or
|
||||||
|
replaced by API.
|
||||||
|
.sp
|
||||||
|
If "affinity=cookie" is used, the additional
|
||||||
|
configuration is required.
|
||||||
|
"affinity\-cookie\-name=<NAME>" must be used to specify a
|
||||||
|
name of cookie to use. Optionally,
|
||||||
|
"affinity\-cookie\-path=<PATH>" can be used to specify a
|
||||||
|
path which cookie is applied. The optional
|
||||||
|
"affinity\-cookie\-secure=<SECURE>" controls the Secure
|
||||||
|
attribute of a cookie. The default value is "auto", and
|
||||||
|
the Secure attribute is determined by a request scheme.
|
||||||
|
If a request scheme is "https", then Secure attribute is
|
||||||
|
set. Otherwise, it is not set. If <SECURE> is "yes",
|
||||||
|
the Secure attribute is always set. If <SECURE> is
|
||||||
|
"no", the Secure attribute is always omitted.
|
||||||
.sp
|
.sp
|
||||||
By default, name resolution of backend host name is done
|
By default, name resolution of backend host name is done
|
||||||
at start up, or reloading configuration. If "dns"
|
at start up, or reloading configuration. If "dns"
|
||||||
@@ -196,6 +228,13 @@ the same <PATTERN>. It is advised to set
|
|||||||
"redirect\-if\-no\-tls" parameter to all backends
|
"redirect\-if\-no\-tls" parameter to all backends
|
||||||
explicitly if this feature is desired.
|
explicitly if this feature is desired.
|
||||||
.sp
|
.sp
|
||||||
|
If "upgrade\-scheme" parameter is used along with "tls"
|
||||||
|
parameter, HTTP/2 :scheme pseudo header field is changed
|
||||||
|
to "https" from "http" when forwarding a request to this
|
||||||
|
particular backend. This is a workaround for a backend
|
||||||
|
server which requires "https" :scheme pseudo header
|
||||||
|
field on TLS encrypted connection.
|
||||||
|
.sp
|
||||||
Since ";" and ":" are used as delimiter, <PATTERN> must
|
Since ";" and ":" are used as delimiter, <PATTERN> must
|
||||||
not contain these characters. Since ";" has special
|
not contain these characters. Since ";" has special
|
||||||
meaning in shell, the option value must be quoted.
|
meaning in shell, the option value must be quoted.
|
||||||
@@ -219,6 +258,11 @@ parameters are mutually exclusive.
|
|||||||
Optionally, TLS can be disabled by specifying "no\-tls"
|
Optionally, TLS can be disabled by specifying "no\-tls"
|
||||||
parameter. TLS is enabled by default.
|
parameter. TLS is enabled by default.
|
||||||
.sp
|
.sp
|
||||||
|
If "sni\-fwd" parameter is used, when performing a match
|
||||||
|
to select a backend server, SNI host name received from
|
||||||
|
the client is used instead of the request host. See
|
||||||
|
\fI\%\-\-backend\fP option about the pattern match.
|
||||||
|
.sp
|
||||||
To make this frontend as API endpoint, specify "api"
|
To make this frontend as API endpoint, specify "api"
|
||||||
parameter. This is disabled by default. It is
|
parameter. This is disabled by default. It is
|
||||||
important to limit the access to the API frontend.
|
important to limit the access to the API frontend.
|
||||||
@@ -434,8 +478,7 @@ this option will be simply ignored.
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-frontend\-http2\-read\-timeout=<DURATION>
|
.B \-\-frontend\-http2\-read\-timeout=<DURATION>
|
||||||
Specify read timeout for HTTP/2 and SPDY frontend
|
Specify read timeout for HTTP/2 frontend connection.
|
||||||
connection.
|
|
||||||
.sp
|
.sp
|
||||||
Default: \fB3m\fP
|
Default: \fB3m\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -464,16 +507,16 @@ Default: \fB1m\fP
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-stream\-read\-timeout=<DURATION>
|
.B \-\-stream\-read\-timeout=<DURATION>
|
||||||
Specify read timeout for HTTP/2 and SPDY streams. 0
|
Specify read timeout for HTTP/2 streams. 0 means no
|
||||||
means no timeout.
|
timeout.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB0\fP
|
Default: \fB0\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-stream\-write\-timeout=<DURATION>
|
.B \-\-stream\-write\-timeout=<DURATION>
|
||||||
Specify write timeout for HTTP/2 and SPDY streams. 0
|
Specify write timeout for HTTP/2 streams. 0 means no
|
||||||
means no timeout.
|
timeout.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB1m\fP
|
Default: \fB1m\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -553,7 +596,7 @@ Default: \fB2m\fP
|
|||||||
Set allowed cipher list for frontend connection. The
|
Set allowed cipher list for frontend connection. The
|
||||||
format of the string is described in OpenSSL ciphers(1).
|
format of the string is described in OpenSSL ciphers(1).
|
||||||
.sp
|
.sp
|
||||||
Default: \fBECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:DHE\-RSA\-AES128\-GCM\-SHA256:DHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-AES128\-SHA256:ECDHE\-RSA\-AES128\-SHA256:ECDHE\-ECDSA\-AES128\-SHA:ECDHE\-RSA\-AES256\-SHA384:ECDHE\-RSA\-AES128\-SHA:ECDHE\-ECDSA\-AES256\-SHA384:ECDHE\-ECDSA\-AES256\-SHA:ECDHE\-RSA\-AES256\-SHA:DHE\-RSA\-AES128\-SHA256:DHE\-RSA\-AES128\-SHA:DHE\-RSA\-AES256\-SHA256:DHE\-RSA\-AES256\-SHA:ECDHE\-ECDSA\-DES\-CBC3\-SHA:ECDHE\-RSA\-DES\-CBC3\-SHA:EDH\-RSA\-DES\-CBC3\-SHA:AES128\-GCM\-SHA256:AES256\-GCM\-SHA384:AES128\-SHA256:AES256\-SHA256:AES128\-SHA:AES256\-SHA:DES\-CBC3\-SHA:!DSS\fP
|
Default: \fBECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-SHA384:ECDHE\-RSA\-AES256\-SHA384:ECDHE\-ECDSA\-AES128\-SHA256:ECDHE\-RSA\-AES128\-SHA256\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -561,7 +604,7 @@ Default: \fBECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDH
|
|||||||
Set allowed cipher list for backend connection. The
|
Set allowed cipher list for backend connection. The
|
||||||
format of the string is described in OpenSSL ciphers(1).
|
format of the string is described in OpenSSL ciphers(1).
|
||||||
.sp
|
.sp
|
||||||
Default: \fBECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:DHE\-RSA\-AES128\-GCM\-SHA256:DHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-AES128\-SHA256:ECDHE\-RSA\-AES128\-SHA256:ECDHE\-ECDSA\-AES128\-SHA:ECDHE\-RSA\-AES256\-SHA384:ECDHE\-RSA\-AES128\-SHA:ECDHE\-ECDSA\-AES256\-SHA384:ECDHE\-ECDSA\-AES256\-SHA:ECDHE\-RSA\-AES256\-SHA:DHE\-RSA\-AES128\-SHA256:DHE\-RSA\-AES128\-SHA:DHE\-RSA\-AES256\-SHA256:DHE\-RSA\-AES256\-SHA:ECDHE\-ECDSA\-DES\-CBC3\-SHA:ECDHE\-RSA\-DES\-CBC3\-SHA:EDH\-RSA\-DES\-CBC3\-SHA:AES128\-GCM\-SHA256:AES256\-GCM\-SHA384:AES128\-SHA256:AES256\-SHA256:AES128\-SHA:AES256\-SHA:DES\-CBC3\-SHA:!DSS\fP
|
Default: \fBECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-SHA384:ECDHE\-RSA\-AES256\-SHA384:ECDHE\-ECDSA\-AES128\-SHA256:ECDHE\-RSA\-AES128\-SHA256\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -583,11 +626,14 @@ enabled for backend connections.
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-cacert=<PATH>
|
.B \-\-cacert=<PATH>
|
||||||
Set path to trusted CA certificate file used in backend
|
Set path to trusted CA certificate file. It is used in
|
||||||
TLS connections. The file must be in PEM format. It
|
backend TLS connections to verify peer\(aqs certificate.
|
||||||
can contain multiple certificates. If the linked
|
It is also used to verify OCSP response from the script
|
||||||
OpenSSL is configured to load system wide certificates,
|
set by \fI\%\-\-fetch\-ocsp\-response\-file\fP\&. The file must be in
|
||||||
they are loaded at startup regardless of this option.
|
PEM format. It can contain multiple certificates. If
|
||||||
|
the linked OpenSSL is configured to load system wide
|
||||||
|
certificates, they are loaded at startup regardless of
|
||||||
|
this option.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -602,12 +648,12 @@ password protected it\(aqll be requested interactively.
|
|||||||
Specify additional certificate and private key file.
|
Specify additional certificate and private key file.
|
||||||
nghttpx will choose certificates based on the hostname
|
nghttpx will choose certificates based on the hostname
|
||||||
indicated by client using TLS SNI extension. If nghttpx
|
indicated by client using TLS SNI extension. If nghttpx
|
||||||
is built with OpenSSL >= 1.0.2, signature algorithms
|
is built with OpenSSL >= 1.0.2, the shared elliptic
|
||||||
(e.g., ECDSA+SHA256, RSA+SHA256) presented by client are
|
curves (e.g., P\-256) between client and server are also
|
||||||
also taken into consideration. This allows nghttpx to
|
taken into consideration. This allows nghttpx to send
|
||||||
send ECDSA certificate to modern clients, while sending
|
ECDSA certificate to modern clients, while sending RSA
|
||||||
RSA based certificate to older clients. This option can
|
based certificate to older clients. This option can be
|
||||||
be used multiple times. To make OCSP stapling work,
|
used multiple times. To make OCSP stapling work,
|
||||||
<CERTPATH> must be absolute path.
|
<CERTPATH> must be absolute path.
|
||||||
.sp
|
.sp
|
||||||
Additional parameter can be specified in <PARAM>. The
|
Additional parameter can be specified in <PARAM>. The
|
||||||
@@ -652,6 +698,14 @@ can contain multiple certificates.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-verify\-client\-tolerate\-expired
|
||||||
|
Accept expired client certificate. Operator should
|
||||||
|
handle the expired client certificate by some means
|
||||||
|
(e.g., mruby script). Otherwise, this option might
|
||||||
|
cause a security risk.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-client\-private\-key\-file=<PATH>
|
.B \-\-client\-private\-key\-file=<PATH>
|
||||||
Path to file that contains client private key used in
|
Path to file that contains client private key used in
|
||||||
backend client authentication.
|
backend client authentication.
|
||||||
@@ -670,10 +724,14 @@ done in case\-insensitive manner. The versions between
|
|||||||
\fI\%\-\-tls\-min\-proto\-version\fP and \fI\%\-\-tls\-max\-proto\-version\fP are
|
\fI\%\-\-tls\-min\-proto\-version\fP and \fI\%\-\-tls\-max\-proto\-version\fP are
|
||||||
enabled. If the protocol list advertised by client does
|
enabled. If the protocol list advertised by client does
|
||||||
not overlap this range, you will receive the error
|
not overlap this range, you will receive the error
|
||||||
message "unknown protocol". The available versions are:
|
message "unknown protocol". If a protocol version lower
|
||||||
|
than TLSv1.2 is specified, make sure that the compatible
|
||||||
|
ciphers are included in \fI\%\-\-ciphers\fP option. The default
|
||||||
|
cipher list only includes ciphers compatible with
|
||||||
|
TLSv1.2 or above. The available versions are:
|
||||||
TLSv1.2, TLSv1.1, and TLSv1.0
|
TLSv1.2, TLSv1.1, and TLSv1.0
|
||||||
.sp
|
.sp
|
||||||
Default: \fBTLSv1.1\fP
|
Default: \fBTLSv1.2\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -803,6 +861,20 @@ Default: \fB4h\fP
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-ocsp\-startup
|
||||||
|
Start accepting connections after initial attempts to
|
||||||
|
get OCSP responses finish. It does not matter some of
|
||||||
|
the attempts fail. This feature is useful if OCSP
|
||||||
|
responses must be available before accepting
|
||||||
|
connections.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-no\-verify\-ocsp
|
||||||
|
nghttpx does not verify OCSP response.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-no\-ocsp
|
.B \-\-no\-ocsp
|
||||||
Disable OCSP stapling.
|
Disable OCSP stapling.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -925,14 +997,14 @@ HTTP/2. To use those cipher suites with HTTP/2,
|
|||||||
consider to use \fI\%\-\-client\-no\-http2\-cipher\-black\-list\fP
|
consider to use \fI\%\-\-client\-no\-http2\-cipher\-black\-list\fP
|
||||||
option. But be aware its implications.
|
option. But be aware its implications.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.SS HTTP/2 and SPDY
|
.SS HTTP/2
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-c, \-\-frontend\-http2\-max\-concurrent\-streams=<N>
|
.B \-c, \-\-frontend\-http2\-max\-concurrent\-streams=<N>
|
||||||
Set the maximum number of the concurrent streams in one
|
Set the maximum number of the concurrent streams in one
|
||||||
frontend HTTP/2 and SPDY session.
|
frontend HTTP/2 session.
|
||||||
.sp
|
.sp
|
||||||
Default: \(ga\(ga 100\(ga\(ga
|
Default: \fB100\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -947,17 +1019,16 @@ Default: \fB100\fP
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-frontend\-http2\-window\-size=<SIZE>
|
.B \-\-frontend\-http2\-window\-size=<SIZE>
|
||||||
Sets the per\-stream initial window size of HTTP/2 and
|
Sets the per\-stream initial window size of HTTP/2
|
||||||
SPDY frontend connection.
|
frontend connection.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB65535\fP
|
Default: \fB65535\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-frontend\-http2\-connection\-window\-size=<SIZE>
|
.B \-\-frontend\-http2\-connection\-window\-size=<SIZE>
|
||||||
Sets the per\-connection window size of HTTP/2 and SPDY
|
Sets the per\-connection window size of HTTP/2 frontend
|
||||||
frontend connection. For SPDY connection, the value
|
connection.
|
||||||
less than 64KiB is rounded up to 64KiB.
|
|
||||||
.sp
|
.sp
|
||||||
Default: \fB65535\fP
|
Default: \fB65535\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -998,8 +1069,7 @@ default mode and HTTP/2 frontend via Link header field.
|
|||||||
It is also supported if both frontend and backend are
|
It is also supported if both frontend and backend are
|
||||||
HTTP/2 in default mode. In this case, server push from
|
HTTP/2 in default mode. In this case, server push from
|
||||||
backend session is relayed to frontend, and server push
|
backend session is relayed to frontend, and server push
|
||||||
via Link header field is also supported. SPDY frontend
|
via Link header field is also supported.
|
||||||
does not support server push.
|
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -1070,7 +1140,7 @@ Default: \fB4K\fP
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B (default mode)
|
.B (default mode)
|
||||||
Accept HTTP/2, SPDY and HTTP/1.1 over SSL/TLS. "no\-tls"
|
Accept HTTP/2, and HTTP/1.1 over SSL/TLS. "no\-tls"
|
||||||
parameter is used in \fI\%\-\-frontend\fP option, accept HTTP/2
|
parameter is used in \fI\%\-\-frontend\fP option, accept HTTP/2
|
||||||
and HTTP/1.1 over cleartext TCP. The incoming HTTP/1.1
|
and HTTP/1.1 over cleartext TCP. The incoming HTTP/1.1
|
||||||
connection can be upgraded to HTTP/2 through HTTP
|
connection can be upgraded to HTTP/2 through HTTP
|
||||||
@@ -1140,15 +1210,32 @@ $alpn: ALPN identifier of the protocol which generates
|
|||||||
the response. For HTTP/1, ALPN is always http/1.1,
|
the response. For HTTP/1, ALPN is always http/1.1,
|
||||||
regardless of minor version.
|
regardless of minor version.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
$ssl_cipher: cipher used for SSL/TLS connection.
|
$tls_cipher: cipher used for SSL/TLS connection.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
$ssl_protocol: protocol for SSL/TLS connection.
|
$tls_client_fingerprint_sha256: SHA\-256 fingerprint of
|
||||||
|
client certificate.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
$ssl_session_id: session ID for SSL/TLS connection.
|
$tls_client_fingerprint_sha1: SHA\-1 fingerprint of
|
||||||
|
client certificate.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
$ssl_session_reused: "r" if SSL/TLS session was
|
$tls_client_subject_name: subject name in client
|
||||||
|
certificate.
|
||||||
|
.IP \(bu 2
|
||||||
|
$tls_client_issuer_name: issuer name in client
|
||||||
|
certificate.
|
||||||
|
.IP \(bu 2
|
||||||
|
$tls_client_serial: serial number in client
|
||||||
|
certificate.
|
||||||
|
.IP \(bu 2
|
||||||
|
$tls_protocol: protocol for SSL/TLS connection.
|
||||||
|
.IP \(bu 2
|
||||||
|
$tls_session_id: session ID for SSL/TLS connection.
|
||||||
|
.IP \(bu 2
|
||||||
|
$tls_session_reused: "r" if SSL/TLS session was
|
||||||
reused. Otherwise, "."
|
reused. Otherwise, "."
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
|
$tls_sni: SNI server name for SSL/TLS connection.
|
||||||
|
.IP \(bu 2
|
||||||
$backend_host: backend host used to fulfill the
|
$backend_host: backend host used to fulfill the
|
||||||
request. "\-" if backend host is not available.
|
request. "\-" if backend host is not available.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
@@ -1205,6 +1292,21 @@ requests.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-no\-add\-x\-forwarded\-proto
|
||||||
|
Don\(aqt append additional X\-Forwarded\-Proto header field
|
||||||
|
to the backend request. If inbound client sets
|
||||||
|
X\-Forwarded\-Proto, and
|
||||||
|
\fI\%\-\-no\-strip\-incoming\-x\-forwarded\-proto\fP option is used,
|
||||||
|
they are passed to the backend.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-no\-strip\-incoming\-x\-forwarded\-proto
|
||||||
|
Don\(aqt strip X\-Forwarded\-Proto header field from inbound
|
||||||
|
client requests.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-add\-forwarded=<LIST>
|
.B \-\-add\-forwarded=<LIST>
|
||||||
Append RFC 7239 Forwarded header field with parameters
|
Append RFC 7239 Forwarded header field with parameters
|
||||||
specified in comma delimited list <LIST>. The supported
|
specified in comma delimited list <LIST>. The supported
|
||||||
@@ -1375,7 +1477,7 @@ Default: \fB443\fP
|
|||||||
.B \-\-api\-max\-request\-body=<SIZE>
|
.B \-\-api\-max\-request\-body=<SIZE>
|
||||||
Set the maximum size of request body for API request.
|
Set the maximum size of request body for API request.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB16K\fP
|
Default: \fB32M\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.SS DNS
|
.SS DNS
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
@@ -1458,6 +1560,17 @@ Set path to save PID of this program.
|
|||||||
Run this program as <USER>. This option is intended to
|
Run this program as <USER>. This option is intended to
|
||||||
be used to drop root privileges.
|
be used to drop root privileges.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-single\-process
|
||||||
|
Run this program in a single process mode for debugging
|
||||||
|
purpose. Without this option, nghttpx creates at least
|
||||||
|
2 processes: master and worker processes. If this
|
||||||
|
option is used, master and worker are unified into a
|
||||||
|
single process. nghttpx still spawns additional process
|
||||||
|
if neverbleed is used. In the single process mode, the
|
||||||
|
signal handling feature is disabled.
|
||||||
|
.UNINDENT
|
||||||
.SS Scripting
|
.SS Scripting
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -1468,7 +1581,9 @@ Set mruby script file
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-conf=<PATH>
|
.B \-\-conf=<PATH>
|
||||||
Load configuration from <PATH>.
|
Load configuration from <PATH>. Please note that
|
||||||
|
nghttpx always tries to read the default configuration
|
||||||
|
file if \fI\%\-\-conf\fP is not given.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB/etc/nghttpx/nghttpx.conf\fP
|
Default: \fB/etc/nghttpx/nghttpx.conf\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -1562,7 +1677,7 @@ follows:
|
|||||||
.INDENT 7.0
|
.INDENT 7.0
|
||||||
.TP
|
.TP
|
||||||
.B <datetime>
|
.B <datetime>
|
||||||
It is a conbination of date and time when the log is written. It
|
It is a combination of date and time when the log is written. It
|
||||||
is in ISO 8601 format.
|
is in ISO 8601 format.
|
||||||
.TP
|
.TP
|
||||||
.B <master\-pid>
|
.B <master\-pid>
|
||||||
@@ -1691,6 +1806,22 @@ be customized using \fI\%\-\-fetch\-ocsp\-response\-file\fP option.
|
|||||||
.sp
|
.sp
|
||||||
If OCSP query is failed, previous OCSP response, if any, is continued
|
If OCSP query is failed, previous OCSP response, if any, is continued
|
||||||
to be used.
|
to be used.
|
||||||
|
.sp
|
||||||
|
\fI\%\-\-fetch\-ocsp\-response\-file\fP option provides wide range of
|
||||||
|
possibility to manage OCSP response. It can take an arbitrary script
|
||||||
|
or executable. The requirement is that it supports the command\-line
|
||||||
|
interface of \fBfetch\-ocsp\-response\fP script, and it must return a
|
||||||
|
valid DER encoded OCSP response on success. It must return exit code
|
||||||
|
0 on success, and 75 for temporary error, and the other error code for
|
||||||
|
generic failure. For large cluster of servers, it is not efficient
|
||||||
|
for each server to perform OCSP query using \fBfetch\-ocsp\-response\fP\&.
|
||||||
|
Instead, you can retrieve OCSP response in some way, and store it in a
|
||||||
|
disk or a shared database. Then specify a program in
|
||||||
|
\fI\%\-\-fetch\-ocsp\-response\-file\fP to fetch it from those stores.
|
||||||
|
This could provide a way to share the OCSP response between fleet of
|
||||||
|
servers, and also any OCSP query strategy can be applied which may be
|
||||||
|
beyond the ability of nghttpx itself or \fBfetch\-ocsp\-response\fP
|
||||||
|
script.
|
||||||
.SH TLS SESSION RESUMPTION
|
.SH TLS SESSION RESUMPTION
|
||||||
.sp
|
.sp
|
||||||
nghttpx supports TLS session resumption through both session ID and
|
nghttpx supports TLS session resumption through both session ID and
|
||||||
@@ -1701,7 +1832,7 @@ By default, session ID is shared by all worker threads.
|
|||||||
.sp
|
.sp
|
||||||
If \fI\%\-\-tls\-session\-cache\-memcached\fP is given, nghttpx will
|
If \fI\%\-\-tls\-session\-cache\-memcached\fP is given, nghttpx will
|
||||||
insert serialized session data to memcached with
|
insert serialized session data to memcached with
|
||||||
\fBnghttpx:tls\-session\-cache:\fP + lowercased hex string of session ID
|
\fBnghttpx:tls\-session\-cache:\fP + lowercase hex string of session ID
|
||||||
as a memcached entry key, with expiry time 12 hours. Session timeout
|
as a memcached entry key, with expiry time 12 hours. Session timeout
|
||||||
is set to 12 hours.
|
is set to 12 hours.
|
||||||
.sp
|
.sp
|
||||||
@@ -1783,6 +1914,17 @@ API is subject to change in the future release.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.sp
|
.sp
|
||||||
|
\fBWARNING:\fP
|
||||||
|
.INDENT 0.0
|
||||||
|
.INDENT 3.5
|
||||||
|
Almost all string value returned from method, or attribute is a
|
||||||
|
fresh new mruby string, which involves memory allocation, and
|
||||||
|
copies. Therefore, it is strongly recommended to store a return
|
||||||
|
value in a local variable, and use it, instead of calling method or
|
||||||
|
accessing attribute repeatedly.
|
||||||
|
.UNINDENT
|
||||||
|
.UNINDENT
|
||||||
|
.sp
|
||||||
nghttpx allows users to extend its capability using mruby scripts.
|
nghttpx allows users to extend its capability using mruby scripts.
|
||||||
nghttpx has 2 hook points to execute mruby script: request phase and
|
nghttpx has 2 hook points to execute mruby script: request phase and
|
||||||
response phase. The request phase hook is invoked after all request
|
response phase. The request phase hook is invoked after all request
|
||||||
@@ -1831,7 +1973,7 @@ Return \fI\%Response\fP object.
|
|||||||
.TP
|
.TP
|
||||||
.B attribute [R] ctx
|
.B attribute [R] ctx
|
||||||
Return Ruby hash object. It persists until request finishes.
|
Return Ruby hash object. It persists until request finishes.
|
||||||
So values set in request phase hoo can be retrieved in
|
So values set in request phase hook can be retrieved in
|
||||||
response phase hook.
|
response phase hook.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 7.0
|
.INDENT 7.0
|
||||||
@@ -1869,6 +2011,68 @@ Return true if TLS is used on the connection.
|
|||||||
.B attribute [R] tls_sni
|
.B attribute [R] tls_sni
|
||||||
Return the TLS SNI value which client sent in this connection.
|
Return the TLS SNI value which client sent in this connection.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_client_fingerprint_sha256
|
||||||
|
Return the SHA\-256 fingerprint of a client certificate.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_client_fingerprint_sha1
|
||||||
|
Return the SHA\-1 fingerprint of a client certificate.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_client_issuer_name
|
||||||
|
Return the issuer name of a client certificate.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_client_subject_name
|
||||||
|
Return the subject name of a client certificate.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_client_serial
|
||||||
|
Return the serial number of a client certificate.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_client_not_before
|
||||||
|
Return the start date of a client certificate in seconds since
|
||||||
|
the epoch.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_client_not_after
|
||||||
|
Return the end date of a client certificate in seconds since
|
||||||
|
the epoch.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_cipher
|
||||||
|
Return a TLS cipher negotiated in this connection.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_protocol
|
||||||
|
Return a TLS protocol version negotiated in this connection.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_session_id
|
||||||
|
Return a session ID for this connection in hex string.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] tls_session_reused
|
||||||
|
Return true if, and only if a SSL/TLS session is reused.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 7.0
|
||||||
|
.TP
|
||||||
|
.B attribute [R] alpn
|
||||||
|
Return ALPN identifier negotiated in this connection.
|
||||||
|
.UNINDENT
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -2146,7 +2350,7 @@ The replacement is done instantly without breaking existing
|
|||||||
connections or requests. It also avoids any process creation as is
|
connections or requests. It also avoids any process creation as is
|
||||||
the case with hot swapping with signals.
|
the case with hot swapping with signals.
|
||||||
.sp
|
.sp
|
||||||
The one limitation is that only numeric IP address is allowd in
|
The one limitation is that only numeric IP address is allowed in
|
||||||
\fI\%backend\fP in request body unless "dns" parameter
|
\fI\%backend\fP in request body unless "dns" parameter
|
||||||
is used while non numeric hostname is allowed in command\-line or
|
is used while non numeric hostname is allowed in command\-line or
|
||||||
configuration file is read using \fI\%\-\-conf\fP\&.
|
configuration file is read using \fI\%\-\-conf\fP\&.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ SYNOPSIS
|
|||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
A reverse proxy for HTTP/2, HTTP/1 and SPDY.
|
A reverse proxy for HTTP/2, and HTTP/1.
|
||||||
|
|
||||||
.. describe:: <PRIVATE_KEY>
|
.. describe:: <PRIVATE_KEY>
|
||||||
|
|
||||||
@@ -46,8 +46,7 @@ Connections
|
|||||||
with "unix:" (e.g., unix:/var/run/backend.sock).
|
with "unix:" (e.g., unix:/var/run/backend.sock).
|
||||||
|
|
||||||
Optionally, if <PATTERN>s are given, the backend address
|
Optionally, if <PATTERN>s are given, the backend address
|
||||||
is only used if request matches the pattern. If
|
is only used if request matches the pattern. The
|
||||||
:option:`--http2-proxy` is used, <PATTERN>s are ignored. The
|
|
||||||
pattern matching is closely designed to ServeMux in
|
pattern matching is closely designed to ServeMux in
|
||||||
net/http package of Go programming language. <PATTERN>
|
net/http package of Go programming language. <PATTERN>
|
||||||
consists of path, host + path or just host. The path
|
consists of path, host + path or just host. The path
|
||||||
@@ -58,11 +57,16 @@ Connections
|
|||||||
which only lacks trailing '*/*' (e.g., path "*/foo/*"
|
which only lacks trailing '*/*' (e.g., path "*/foo/*"
|
||||||
matches request path "*/foo*"). If it does not end with
|
matches request path "*/foo*"). If it does not end with
|
||||||
"*/*", it performs exact match against the request path.
|
"*/*", it performs exact match against the request path.
|
||||||
If host is given, it performs exact match against the
|
If host is given, it performs a match against the
|
||||||
request host. If host alone is given, "*/*" is appended
|
request host. For a request received on the frontend
|
||||||
to it, so that it matches all request paths under the
|
listener with "sni-fwd" parameter enabled, SNI host is
|
||||||
host (e.g., specifying "nghttp2.org" equals to
|
used instead of a request host. If host alone is given,
|
||||||
"nghttp2.org/").
|
"*/*" is appended to it, so that it matches all request
|
||||||
|
paths under the host (e.g., specifying "nghttp2.org"
|
||||||
|
equals to "nghttp2.org/"). CONNECT method is treated
|
||||||
|
specially. It does not have path, and we don't allow
|
||||||
|
empty path. To workaround this, we assume that CONNECT
|
||||||
|
method has "*/*" as path.
|
||||||
|
|
||||||
Patterns with host take precedence over patterns with
|
Patterns with host take precedence over patterns with
|
||||||
just path. Then, longer patterns take precedence over
|
just path. Then, longer patterns take precedence over
|
||||||
@@ -76,6 +80,18 @@ Connections
|
|||||||
match against "nghttp2.org". The exact hosts match
|
match against "nghttp2.org". The exact hosts match
|
||||||
takes precedence over the wildcard hosts match.
|
takes precedence over the wildcard hosts match.
|
||||||
|
|
||||||
|
If path part ends with "\*", it is treated as wildcard
|
||||||
|
path. The wildcard path behaves differently from the
|
||||||
|
normal path. For normal path, match is made around the
|
||||||
|
boundary of path component separator,"*/*". On the other
|
||||||
|
hand, the wildcard path does not take into account the
|
||||||
|
path component separator. All paths which include the
|
||||||
|
wildcard path without last "\*" as prefix, and are
|
||||||
|
strictly longer than wildcard path without last "\*" are
|
||||||
|
matched. "\*" must match at least one character. For
|
||||||
|
example, the pattern "*/foo\**" matches "*/foo/*" and
|
||||||
|
"*/foobar*". But it does not match "*/foo*", or "*/fo*".
|
||||||
|
|
||||||
If <PATTERN> is omitted or empty string, "*/*" is used as
|
If <PATTERN> is omitted or empty string, "*/*" is used as
|
||||||
pattern, which matches all request paths (catch-all
|
pattern, which matches all request paths (catch-all
|
||||||
pattern). The catch-all backend must be given.
|
pattern). The catch-all backend must be given.
|
||||||
@@ -148,16 +164,32 @@ Connections
|
|||||||
The session affinity is enabled using
|
The session affinity is enabled using
|
||||||
"affinity=<METHOD>" parameter. If "ip" is given in
|
"affinity=<METHOD>" parameter. If "ip" is given in
|
||||||
<METHOD>, client IP based session affinity is enabled.
|
<METHOD>, client IP based session affinity is enabled.
|
||||||
If "none" is given in <METHOD>, session affinity is
|
If "cookie" is given in <METHOD>, cookie based session
|
||||||
disabled, and this is the default. The session affinity
|
affinity is enabled. If "none" is given in <METHOD>,
|
||||||
is enabled per <PATTERN>. If at least one backend has
|
session affinity is disabled, and this is the default.
|
||||||
"affinity" parameter, and its <METHOD> is not "none",
|
The session affinity is enabled per <PATTERN>. If at
|
||||||
session affinity is enabled for all backend servers
|
least one backend has "affinity" parameter, and its
|
||||||
sharing the same <PATTERN>. It is advised to set
|
<METHOD> is not "none", session affinity is enabled for
|
||||||
"affinity" parameter to all backend explicitly if
|
all backend servers sharing the same <PATTERN>. It is
|
||||||
session affinity is desired. The session affinity may
|
advised to set "affinity" parameter to all backend
|
||||||
break if one of the backend gets unreachable, or backend
|
explicitly if session affinity is desired. The session
|
||||||
settings are reloaded or replaced by API.
|
affinity may break if one of the backend gets
|
||||||
|
unreachable, or backend settings are reloaded or
|
||||||
|
replaced by API.
|
||||||
|
|
||||||
|
If "affinity=cookie" is used, the additional
|
||||||
|
configuration is required.
|
||||||
|
"affinity-cookie-name=<NAME>" must be used to specify a
|
||||||
|
name of cookie to use. Optionally,
|
||||||
|
"affinity-cookie-path=<PATH>" can be used to specify a
|
||||||
|
path which cookie is applied. The optional
|
||||||
|
"affinity-cookie-secure=<SECURE>" controls the Secure
|
||||||
|
attribute of a cookie. The default value is "auto", and
|
||||||
|
the Secure attribute is determined by a request scheme.
|
||||||
|
If a request scheme is "https", then Secure attribute is
|
||||||
|
set. Otherwise, it is not set. If <SECURE> is "yes",
|
||||||
|
the Secure attribute is always set. If <SECURE> is
|
||||||
|
"no", the Secure attribute is always omitted.
|
||||||
|
|
||||||
By default, name resolution of backend host name is done
|
By default, name resolution of backend host name is done
|
||||||
at start up, or reloading configuration. If "dns"
|
at start up, or reloading configuration. If "dns"
|
||||||
@@ -180,6 +212,13 @@ Connections
|
|||||||
"redirect-if-no-tls" parameter to all backends
|
"redirect-if-no-tls" parameter to all backends
|
||||||
explicitly if this feature is desired.
|
explicitly if this feature is desired.
|
||||||
|
|
||||||
|
If "upgrade-scheme" parameter is used along with "tls"
|
||||||
|
parameter, HTTP/2 :scheme pseudo header field is changed
|
||||||
|
to "https" from "http" when forwarding a request to this
|
||||||
|
particular backend. This is a workaround for a backend
|
||||||
|
server which requires "https" :scheme pseudo header
|
||||||
|
field on TLS encrypted connection.
|
||||||
|
|
||||||
Since ";" and ":" are used as delimiter, <PATTERN> must
|
Since ";" and ":" are used as delimiter, <PATTERN> must
|
||||||
not contain these characters. Since ";" has special
|
not contain these characters. Since ";" has special
|
||||||
meaning in shell, the option value must be quoted.
|
meaning in shell, the option value must be quoted.
|
||||||
@@ -203,6 +242,11 @@ Connections
|
|||||||
Optionally, TLS can be disabled by specifying "no-tls"
|
Optionally, TLS can be disabled by specifying "no-tls"
|
||||||
parameter. TLS is enabled by default.
|
parameter. TLS is enabled by default.
|
||||||
|
|
||||||
|
If "sni-fwd" parameter is used, when performing a match
|
||||||
|
to select a backend server, SNI host name received from
|
||||||
|
the client is used instead of the request host. See
|
||||||
|
:option:`--backend` option about the pattern match.
|
||||||
|
|
||||||
To make this frontend as API endpoint, specify "api"
|
To make this frontend as API endpoint, specify "api"
|
||||||
parameter. This is disabled by default. It is
|
parameter. This is disabled by default. It is
|
||||||
important to limit the access to the API frontend.
|
important to limit the access to the API frontend.
|
||||||
@@ -403,8 +447,7 @@ Timeout
|
|||||||
|
|
||||||
.. option:: --frontend-http2-read-timeout=<DURATION>
|
.. option:: --frontend-http2-read-timeout=<DURATION>
|
||||||
|
|
||||||
Specify read timeout for HTTP/2 and SPDY frontend
|
Specify read timeout for HTTP/2 frontend connection.
|
||||||
connection.
|
|
||||||
|
|
||||||
Default: ``3m``
|
Default: ``3m``
|
||||||
|
|
||||||
@@ -429,15 +472,15 @@ Timeout
|
|||||||
|
|
||||||
.. option:: --stream-read-timeout=<DURATION>
|
.. option:: --stream-read-timeout=<DURATION>
|
||||||
|
|
||||||
Specify read timeout for HTTP/2 and SPDY streams. 0
|
Specify read timeout for HTTP/2 streams. 0 means no
|
||||||
means no timeout.
|
timeout.
|
||||||
|
|
||||||
Default: ``0``
|
Default: ``0``
|
||||||
|
|
||||||
.. option:: --stream-write-timeout=<DURATION>
|
.. option:: --stream-write-timeout=<DURATION>
|
||||||
|
|
||||||
Specify write timeout for HTTP/2 and SPDY streams. 0
|
Specify write timeout for HTTP/2 streams. 0 means no
|
||||||
means no timeout.
|
timeout.
|
||||||
|
|
||||||
Default: ``1m``
|
Default: ``1m``
|
||||||
|
|
||||||
@@ -511,14 +554,14 @@ SSL/TLS
|
|||||||
Set allowed cipher list for frontend connection. The
|
Set allowed cipher list for frontend connection. The
|
||||||
format of the string is described in OpenSSL ciphers(1).
|
format of the string is described in OpenSSL ciphers(1).
|
||||||
|
|
||||||
Default: ``ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS``
|
Default: ``ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256``
|
||||||
|
|
||||||
.. option:: --client-ciphers=<SUITE>
|
.. option:: --client-ciphers=<SUITE>
|
||||||
|
|
||||||
Set allowed cipher list for backend connection. The
|
Set allowed cipher list for backend connection. The
|
||||||
format of the string is described in OpenSSL ciphers(1).
|
format of the string is described in OpenSSL ciphers(1).
|
||||||
|
|
||||||
Default: ``ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS``
|
Default: ``ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256``
|
||||||
|
|
||||||
.. option:: --ecdh-curves=<LIST>
|
.. option:: --ecdh-curves=<LIST>
|
||||||
|
|
||||||
@@ -537,11 +580,14 @@ SSL/TLS
|
|||||||
|
|
||||||
.. option:: --cacert=<PATH>
|
.. option:: --cacert=<PATH>
|
||||||
|
|
||||||
Set path to trusted CA certificate file used in backend
|
Set path to trusted CA certificate file. It is used in
|
||||||
TLS connections. The file must be in PEM format. It
|
backend TLS connections to verify peer's certificate.
|
||||||
can contain multiple certificates. If the linked
|
It is also used to verify OCSP response from the script
|
||||||
OpenSSL is configured to load system wide certificates,
|
set by :option:`--fetch-ocsp-response-file`\. The file must be in
|
||||||
they are loaded at startup regardless of this option.
|
PEM format. It can contain multiple certificates. If
|
||||||
|
the linked OpenSSL is configured to load system wide
|
||||||
|
certificates, they are loaded at startup regardless of
|
||||||
|
this option.
|
||||||
|
|
||||||
.. option:: --private-key-passwd-file=<PATH>
|
.. option:: --private-key-passwd-file=<PATH>
|
||||||
|
|
||||||
@@ -554,12 +600,12 @@ SSL/TLS
|
|||||||
Specify additional certificate and private key file.
|
Specify additional certificate and private key file.
|
||||||
nghttpx will choose certificates based on the hostname
|
nghttpx will choose certificates based on the hostname
|
||||||
indicated by client using TLS SNI extension. If nghttpx
|
indicated by client using TLS SNI extension. If nghttpx
|
||||||
is built with OpenSSL >= 1.0.2, signature algorithms
|
is built with OpenSSL >= 1.0.2, the shared elliptic
|
||||||
(e.g., ECDSA+SHA256, RSA+SHA256) presented by client are
|
curves (e.g., P-256) between client and server are also
|
||||||
also taken into consideration. This allows nghttpx to
|
taken into consideration. This allows nghttpx to send
|
||||||
send ECDSA certificate to modern clients, while sending
|
ECDSA certificate to modern clients, while sending RSA
|
||||||
RSA based certificate to older clients. This option can
|
based certificate to older clients. This option can be
|
||||||
be used multiple times. To make OCSP stapling work,
|
used multiple times. To make OCSP stapling work,
|
||||||
<CERTPATH> must be absolute path.
|
<CERTPATH> must be absolute path.
|
||||||
|
|
||||||
Additional parameter can be specified in <PARAM>. The
|
Additional parameter can be specified in <PARAM>. The
|
||||||
@@ -598,6 +644,13 @@ SSL/TLS
|
|||||||
client certificate. The file must be in PEM format. It
|
client certificate. The file must be in PEM format. It
|
||||||
can contain multiple certificates.
|
can contain multiple certificates.
|
||||||
|
|
||||||
|
.. option:: --verify-client-tolerate-expired
|
||||||
|
|
||||||
|
Accept expired client certificate. Operator should
|
||||||
|
handle the expired client certificate by some means
|
||||||
|
(e.g., mruby script). Otherwise, this option might
|
||||||
|
cause a security risk.
|
||||||
|
|
||||||
.. option:: --client-private-key-file=<PATH>
|
.. option:: --client-private-key-file=<PATH>
|
||||||
|
|
||||||
Path to file that contains client private key used in
|
Path to file that contains client private key used in
|
||||||
@@ -615,10 +668,14 @@ SSL/TLS
|
|||||||
:option:`--tls-min-proto-version` and :option:`\--tls-max-proto-version` are
|
:option:`--tls-min-proto-version` and :option:`\--tls-max-proto-version` are
|
||||||
enabled. If the protocol list advertised by client does
|
enabled. If the protocol list advertised by client does
|
||||||
not overlap this range, you will receive the error
|
not overlap this range, you will receive the error
|
||||||
message "unknown protocol". The available versions are:
|
message "unknown protocol". If a protocol version lower
|
||||||
|
than TLSv1.2 is specified, make sure that the compatible
|
||||||
|
ciphers are included in :option:`--ciphers` option. The default
|
||||||
|
cipher list only includes ciphers compatible with
|
||||||
|
TLSv1.2 or above. The available versions are:
|
||||||
TLSv1.2, TLSv1.1, and TLSv1.0
|
TLSv1.2, TLSv1.1, and TLSv1.0
|
||||||
|
|
||||||
Default: ``TLSv1.1``
|
Default: ``TLSv1.2``
|
||||||
|
|
||||||
.. option:: --tls-max-proto-version=<VER>
|
.. option:: --tls-max-proto-version=<VER>
|
||||||
|
|
||||||
@@ -734,6 +791,18 @@ SSL/TLS
|
|||||||
|
|
||||||
Default: ``4h``
|
Default: ``4h``
|
||||||
|
|
||||||
|
.. option:: --ocsp-startup
|
||||||
|
|
||||||
|
Start accepting connections after initial attempts to
|
||||||
|
get OCSP responses finish. It does not matter some of
|
||||||
|
the attempts fail. This feature is useful if OCSP
|
||||||
|
responses must be available before accepting
|
||||||
|
connections.
|
||||||
|
|
||||||
|
.. option:: --no-verify-ocsp
|
||||||
|
|
||||||
|
nghttpx does not verify OCSP response.
|
||||||
|
|
||||||
.. option:: --no-ocsp
|
.. option:: --no-ocsp
|
||||||
|
|
||||||
Disable OCSP stapling.
|
Disable OCSP stapling.
|
||||||
@@ -847,15 +916,15 @@ SSL/TLS
|
|||||||
option. But be aware its implications.
|
option. But be aware its implications.
|
||||||
|
|
||||||
|
|
||||||
HTTP/2 and SPDY
|
HTTP/2
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
.. option:: -c, --frontend-http2-max-concurrent-streams=<N>
|
.. option:: -c, --frontend-http2-max-concurrent-streams=<N>
|
||||||
|
|
||||||
Set the maximum number of the concurrent streams in one
|
Set the maximum number of the concurrent streams in one
|
||||||
frontend HTTP/2 and SPDY session.
|
frontend HTTP/2 session.
|
||||||
|
|
||||||
Default: `` 100``
|
Default: ``100``
|
||||||
|
|
||||||
.. option:: --backend-http2-max-concurrent-streams=<N>
|
.. option:: --backend-http2-max-concurrent-streams=<N>
|
||||||
|
|
||||||
@@ -868,16 +937,15 @@ HTTP/2 and SPDY
|
|||||||
|
|
||||||
.. option:: --frontend-http2-window-size=<SIZE>
|
.. option:: --frontend-http2-window-size=<SIZE>
|
||||||
|
|
||||||
Sets the per-stream initial window size of HTTP/2 and
|
Sets the per-stream initial window size of HTTP/2
|
||||||
SPDY frontend connection.
|
frontend connection.
|
||||||
|
|
||||||
Default: ``65535``
|
Default: ``65535``
|
||||||
|
|
||||||
.. option:: --frontend-http2-connection-window-size=<SIZE>
|
.. option:: --frontend-http2-connection-window-size=<SIZE>
|
||||||
|
|
||||||
Sets the per-connection window size of HTTP/2 and SPDY
|
Sets the per-connection window size of HTTP/2 frontend
|
||||||
frontend connection. For SPDY connection, the value
|
connection.
|
||||||
less than 64KiB is rounded up to 64KiB.
|
|
||||||
|
|
||||||
Default: ``65535``
|
Default: ``65535``
|
||||||
|
|
||||||
@@ -913,8 +981,7 @@ HTTP/2 and SPDY
|
|||||||
It is also supported if both frontend and backend are
|
It is also supported if both frontend and backend are
|
||||||
HTTP/2 in default mode. In this case, server push from
|
HTTP/2 in default mode. In this case, server push from
|
||||||
backend session is relayed to frontend, and server push
|
backend session is relayed to frontend, and server push
|
||||||
via Link header field is also supported. SPDY frontend
|
via Link header field is also supported.
|
||||||
does not support server push.
|
|
||||||
|
|
||||||
.. option:: --frontend-http2-optimize-write-buffer-size
|
.. option:: --frontend-http2-optimize-write-buffer-size
|
||||||
|
|
||||||
@@ -982,7 +1049,7 @@ Mode
|
|||||||
.. describe:: (default mode)
|
.. describe:: (default mode)
|
||||||
|
|
||||||
|
|
||||||
Accept HTTP/2, SPDY and HTTP/1.1 over SSL/TLS. "no-tls"
|
Accept HTTP/2, and HTTP/1.1 over SSL/TLS. "no-tls"
|
||||||
parameter is used in :option:`--frontend` option, accept HTTP/2
|
parameter is used in :option:`--frontend` option, accept HTTP/2
|
||||||
and HTTP/1.1 over cleartext TCP. The incoming HTTP/1.1
|
and HTTP/1.1 over cleartext TCP. The incoming HTTP/1.1
|
||||||
connection can be upgraded to HTTP/2 through HTTP
|
connection can be upgraded to HTTP/2 through HTTP
|
||||||
@@ -1037,11 +1104,22 @@ Logging
|
|||||||
* $alpn: ALPN identifier of the protocol which generates
|
* $alpn: ALPN identifier of the protocol which generates
|
||||||
the response. For HTTP/1, ALPN is always http/1.1,
|
the response. For HTTP/1, ALPN is always http/1.1,
|
||||||
regardless of minor version.
|
regardless of minor version.
|
||||||
* $ssl_cipher: cipher used for SSL/TLS connection.
|
* $tls_cipher: cipher used for SSL/TLS connection.
|
||||||
* $ssl_protocol: protocol for SSL/TLS connection.
|
* $tls_client_fingerprint_sha256: SHA-256 fingerprint of
|
||||||
* $ssl_session_id: session ID for SSL/TLS connection.
|
client certificate.
|
||||||
* $ssl_session_reused: "r" if SSL/TLS session was
|
* $tls_client_fingerprint_sha1: SHA-1 fingerprint of
|
||||||
|
client certificate.
|
||||||
|
* $tls_client_subject_name: subject name in client
|
||||||
|
certificate.
|
||||||
|
* $tls_client_issuer_name: issuer name in client
|
||||||
|
certificate.
|
||||||
|
* $tls_client_serial: serial number in client
|
||||||
|
certificate.
|
||||||
|
* $tls_protocol: protocol for SSL/TLS connection.
|
||||||
|
* $tls_session_id: session ID for SSL/TLS connection.
|
||||||
|
* $tls_session_reused: "r" if SSL/TLS session was
|
||||||
reused. Otherwise, "."
|
reused. Otherwise, "."
|
||||||
|
* $tls_sni: SNI server name for SSL/TLS connection.
|
||||||
* $backend_host: backend host used to fulfill the
|
* $backend_host: backend host used to fulfill the
|
||||||
request. "-" if backend host is not available.
|
request. "-" if backend host is not available.
|
||||||
* $backend_port: backend port used to fulfill the
|
* $backend_port: backend port used to fulfill the
|
||||||
@@ -1092,6 +1170,19 @@ HTTP
|
|||||||
Strip X-Forwarded-For header field from inbound client
|
Strip X-Forwarded-For header field from inbound client
|
||||||
requests.
|
requests.
|
||||||
|
|
||||||
|
.. option:: --no-add-x-forwarded-proto
|
||||||
|
|
||||||
|
Don't append additional X-Forwarded-Proto header field
|
||||||
|
to the backend request. If inbound client sets
|
||||||
|
X-Forwarded-Proto, and
|
||||||
|
:option:`--no-strip-incoming-x-forwarded-proto` option is used,
|
||||||
|
they are passed to the backend.
|
||||||
|
|
||||||
|
.. option:: --no-strip-incoming-x-forwarded-proto
|
||||||
|
|
||||||
|
Don't strip X-Forwarded-Proto header field from inbound
|
||||||
|
client requests.
|
||||||
|
|
||||||
.. option:: --add-forwarded=<LIST>
|
.. option:: --add-forwarded=<LIST>
|
||||||
|
|
||||||
Append RFC 7239 Forwarded header field with parameters
|
Append RFC 7239 Forwarded header field with parameters
|
||||||
@@ -1248,7 +1339,7 @@ API
|
|||||||
|
|
||||||
Set the maximum size of request body for API request.
|
Set the maximum size of request body for API request.
|
||||||
|
|
||||||
Default: ``16K``
|
Default: ``32M``
|
||||||
|
|
||||||
|
|
||||||
DNS
|
DNS
|
||||||
@@ -1330,6 +1421,16 @@ Process
|
|||||||
Run this program as <USER>. This option is intended to
|
Run this program as <USER>. This option is intended to
|
||||||
be used to drop root privileges.
|
be used to drop root privileges.
|
||||||
|
|
||||||
|
.. option:: --single-process
|
||||||
|
|
||||||
|
Run this program in a single process mode for debugging
|
||||||
|
purpose. Without this option, nghttpx creates at least
|
||||||
|
2 processes: master and worker processes. If this
|
||||||
|
option is used, master and worker are unified into a
|
||||||
|
single process. nghttpx still spawns additional process
|
||||||
|
if neverbleed is used. In the single process mode, the
|
||||||
|
signal handling feature is disabled.
|
||||||
|
|
||||||
|
|
||||||
Scripting
|
Scripting
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
@@ -1344,7 +1445,9 @@ Misc
|
|||||||
|
|
||||||
.. option:: --conf=<PATH>
|
.. option:: --conf=<PATH>
|
||||||
|
|
||||||
Load configuration from <PATH>.
|
Load configuration from <PATH>. Please note that
|
||||||
|
nghttpx always tries to read the default configuration
|
||||||
|
file if :option:`--conf` is not given.
|
||||||
|
|
||||||
Default: ``/etc/nghttpx/nghttpx.conf``
|
Default: ``/etc/nghttpx/nghttpx.conf``
|
||||||
|
|
||||||
@@ -1424,7 +1527,7 @@ Error log
|
|||||||
<datetime> <master-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
|
<datetime> <master-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
|
||||||
|
|
||||||
<datetime>
|
<datetime>
|
||||||
It is a conbination of date and time when the log is written. It
|
It is a combination of date and time when the log is written. It
|
||||||
is in ISO 8601 format.
|
is in ISO 8601 format.
|
||||||
|
|
||||||
<master-pid>
|
<master-pid>
|
||||||
@@ -1546,6 +1649,22 @@ be customized using :option:`--fetch-ocsp-response-file` option.
|
|||||||
If OCSP query is failed, previous OCSP response, if any, is continued
|
If OCSP query is failed, previous OCSP response, if any, is continued
|
||||||
to be used.
|
to be used.
|
||||||
|
|
||||||
|
:option:`--fetch-ocsp-response-file` option provides wide range of
|
||||||
|
possibility to manage OCSP response. It can take an arbitrary script
|
||||||
|
or executable. The requirement is that it supports the command-line
|
||||||
|
interface of ``fetch-ocsp-response`` script, and it must return a
|
||||||
|
valid DER encoded OCSP response on success. It must return exit code
|
||||||
|
0 on success, and 75 for temporary error, and the other error code for
|
||||||
|
generic failure. For large cluster of servers, it is not efficient
|
||||||
|
for each server to perform OCSP query using ``fetch-ocsp-response``.
|
||||||
|
Instead, you can retrieve OCSP response in some way, and store it in a
|
||||||
|
disk or a shared database. Then specify a program in
|
||||||
|
:option:`--fetch-ocsp-response-file` to fetch it from those stores.
|
||||||
|
This could provide a way to share the OCSP response between fleet of
|
||||||
|
servers, and also any OCSP query strategy can be applied which may be
|
||||||
|
beyond the ability of nghttpx itself or ``fetch-ocsp-response``
|
||||||
|
script.
|
||||||
|
|
||||||
TLS SESSION RESUMPTION
|
TLS SESSION RESUMPTION
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@@ -1559,7 +1678,7 @@ By default, session ID is shared by all worker threads.
|
|||||||
|
|
||||||
If :option:`--tls-session-cache-memcached` is given, nghttpx will
|
If :option:`--tls-session-cache-memcached` is given, nghttpx will
|
||||||
insert serialized session data to memcached with
|
insert serialized session data to memcached with
|
||||||
``nghttpx:tls-session-cache:`` + lowercased hex string of session ID
|
``nghttpx:tls-session-cache:`` + lowercase hex string of session ID
|
||||||
as a memcached entry key, with expiry time 12 hours. Session timeout
|
as a memcached entry key, with expiry time 12 hours. Session timeout
|
||||||
is set to 12 hours.
|
is set to 12 hours.
|
||||||
|
|
||||||
@@ -1641,6 +1760,14 @@ MRUBY SCRIPTING
|
|||||||
The current mruby extension API is experimental and not frozen. The
|
The current mruby extension API is experimental and not frozen. The
|
||||||
API is subject to change in the future release.
|
API is subject to change in the future release.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Almost all string value returned from method, or attribute is a
|
||||||
|
fresh new mruby string, which involves memory allocation, and
|
||||||
|
copies. Therefore, it is strongly recommended to store a return
|
||||||
|
value in a local variable, and use it, instead of calling method or
|
||||||
|
accessing attribute repeatedly.
|
||||||
|
|
||||||
nghttpx allows users to extend its capability using mruby scripts.
|
nghttpx allows users to extend its capability using mruby scripts.
|
||||||
nghttpx has 2 hook points to execute mruby script: request phase and
|
nghttpx has 2 hook points to execute mruby script: request phase and
|
||||||
response phase. The request phase hook is invoked after all request
|
response phase. The request phase hook is invoked after all request
|
||||||
@@ -1687,7 +1814,7 @@ respectively.
|
|||||||
.. rb:attr_reader:: ctx
|
.. rb:attr_reader:: ctx
|
||||||
|
|
||||||
Return Ruby hash object. It persists until request finishes.
|
Return Ruby hash object. It persists until request finishes.
|
||||||
So values set in request phase hoo can be retrieved in
|
So values set in request phase hook can be retrieved in
|
||||||
response phase hook.
|
response phase hook.
|
||||||
|
|
||||||
.. rb:attr_reader:: phase
|
.. rb:attr_reader:: phase
|
||||||
@@ -1719,6 +1846,56 @@ respectively.
|
|||||||
|
|
||||||
Return the TLS SNI value which client sent in this connection.
|
Return the TLS SNI value which client sent in this connection.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_fingerprint_sha256
|
||||||
|
|
||||||
|
Return the SHA-256 fingerprint of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_fingerprint_sha1
|
||||||
|
|
||||||
|
Return the SHA-1 fingerprint of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_issuer_name
|
||||||
|
|
||||||
|
Return the issuer name of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_subject_name
|
||||||
|
|
||||||
|
Return the subject name of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_serial
|
||||||
|
|
||||||
|
Return the serial number of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_not_before
|
||||||
|
|
||||||
|
Return the start date of a client certificate in seconds since
|
||||||
|
the epoch.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_not_after
|
||||||
|
|
||||||
|
Return the end date of a client certificate in seconds since
|
||||||
|
the epoch.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_cipher
|
||||||
|
|
||||||
|
Return a TLS cipher negotiated in this connection.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_protocol
|
||||||
|
|
||||||
|
Return a TLS protocol version negotiated in this connection.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_session_id
|
||||||
|
|
||||||
|
Return a session ID for this connection in hex string.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_session_reused
|
||||||
|
|
||||||
|
Return true if, and only if a SSL/TLS session is reused.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: alpn
|
||||||
|
|
||||||
|
Return ALPN identifier negotiated in this connection.
|
||||||
|
|
||||||
.. rb:class:: Request
|
.. rb:class:: Request
|
||||||
|
|
||||||
Object to represent request from client. The modification to
|
Object to represent request from client. The modification to
|
||||||
@@ -1963,7 +2140,7 @@ The replacement is done instantly without breaking existing
|
|||||||
connections or requests. It also avoids any process creation as is
|
connections or requests. It also avoids any process creation as is
|
||||||
the case with hot swapping with signals.
|
the case with hot swapping with signals.
|
||||||
|
|
||||||
The one limitation is that only numeric IP address is allowd in
|
The one limitation is that only numeric IP address is allowed in
|
||||||
:option:`backend <--backend>` in request body unless "dns" parameter
|
:option:`backend <--backend>` in request body unless "dns" parameter
|
||||||
is used while non numeric hostname is allowed in command-line or
|
is used while non numeric hostname is allowed in command-line or
|
||||||
configuration file is read using :option:`--conf`.
|
configuration file is read using :option:`--conf`.
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ Error log
|
|||||||
<datetime> <master-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
|
<datetime> <master-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
|
||||||
|
|
||||||
<datetime>
|
<datetime>
|
||||||
It is a conbination of date and time when the log is written. It
|
It is a combination of date and time when the log is written. It
|
||||||
is in ISO 8601 format.
|
is in ISO 8601 format.
|
||||||
|
|
||||||
<master-pid>
|
<master-pid>
|
||||||
@@ -171,6 +171,22 @@ be customized using :option:`--fetch-ocsp-response-file` option.
|
|||||||
If OCSP query is failed, previous OCSP response, if any, is continued
|
If OCSP query is failed, previous OCSP response, if any, is continued
|
||||||
to be used.
|
to be used.
|
||||||
|
|
||||||
|
:option:`--fetch-ocsp-response-file` option provides wide range of
|
||||||
|
possibility to manage OCSP response. It can take an arbitrary script
|
||||||
|
or executable. The requirement is that it supports the command-line
|
||||||
|
interface of ``fetch-ocsp-response`` script, and it must return a
|
||||||
|
valid DER encoded OCSP response on success. It must return exit code
|
||||||
|
0 on success, and 75 for temporary error, and the other error code for
|
||||||
|
generic failure. For large cluster of servers, it is not efficient
|
||||||
|
for each server to perform OCSP query using ``fetch-ocsp-response``.
|
||||||
|
Instead, you can retrieve OCSP response in some way, and store it in a
|
||||||
|
disk or a shared database. Then specify a program in
|
||||||
|
:option:`--fetch-ocsp-response-file` to fetch it from those stores.
|
||||||
|
This could provide a way to share the OCSP response between fleet of
|
||||||
|
servers, and also any OCSP query strategy can be applied which may be
|
||||||
|
beyond the ability of nghttpx itself or ``fetch-ocsp-response``
|
||||||
|
script.
|
||||||
|
|
||||||
TLS SESSION RESUMPTION
|
TLS SESSION RESUMPTION
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@@ -184,7 +200,7 @@ By default, session ID is shared by all worker threads.
|
|||||||
|
|
||||||
If :option:`--tls-session-cache-memcached` is given, nghttpx will
|
If :option:`--tls-session-cache-memcached` is given, nghttpx will
|
||||||
insert serialized session data to memcached with
|
insert serialized session data to memcached with
|
||||||
``nghttpx:tls-session-cache:`` + lowercased hex string of session ID
|
``nghttpx:tls-session-cache:`` + lowercase hex string of session ID
|
||||||
as a memcached entry key, with expiry time 12 hours. Session timeout
|
as a memcached entry key, with expiry time 12 hours. Session timeout
|
||||||
is set to 12 hours.
|
is set to 12 hours.
|
||||||
|
|
||||||
@@ -266,6 +282,14 @@ MRUBY SCRIPTING
|
|||||||
The current mruby extension API is experimental and not frozen. The
|
The current mruby extension API is experimental and not frozen. The
|
||||||
API is subject to change in the future release.
|
API is subject to change in the future release.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Almost all string value returned from method, or attribute is a
|
||||||
|
fresh new mruby string, which involves memory allocation, and
|
||||||
|
copies. Therefore, it is strongly recommended to store a return
|
||||||
|
value in a local variable, and use it, instead of calling method or
|
||||||
|
accessing attribute repeatedly.
|
||||||
|
|
||||||
nghttpx allows users to extend its capability using mruby scripts.
|
nghttpx allows users to extend its capability using mruby scripts.
|
||||||
nghttpx has 2 hook points to execute mruby script: request phase and
|
nghttpx has 2 hook points to execute mruby script: request phase and
|
||||||
response phase. The request phase hook is invoked after all request
|
response phase. The request phase hook is invoked after all request
|
||||||
@@ -312,7 +336,7 @@ respectively.
|
|||||||
.. rb:attr_reader:: ctx
|
.. rb:attr_reader:: ctx
|
||||||
|
|
||||||
Return Ruby hash object. It persists until request finishes.
|
Return Ruby hash object. It persists until request finishes.
|
||||||
So values set in request phase hoo can be retrieved in
|
So values set in request phase hook can be retrieved in
|
||||||
response phase hook.
|
response phase hook.
|
||||||
|
|
||||||
.. rb:attr_reader:: phase
|
.. rb:attr_reader:: phase
|
||||||
@@ -344,6 +368,56 @@ respectively.
|
|||||||
|
|
||||||
Return the TLS SNI value which client sent in this connection.
|
Return the TLS SNI value which client sent in this connection.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_fingerprint_sha256
|
||||||
|
|
||||||
|
Return the SHA-256 fingerprint of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_fingerprint_sha1
|
||||||
|
|
||||||
|
Return the SHA-1 fingerprint of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_issuer_name
|
||||||
|
|
||||||
|
Return the issuer name of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_subject_name
|
||||||
|
|
||||||
|
Return the subject name of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_serial
|
||||||
|
|
||||||
|
Return the serial number of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_not_before
|
||||||
|
|
||||||
|
Return the start date of a client certificate in seconds since
|
||||||
|
the epoch.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_not_after
|
||||||
|
|
||||||
|
Return the end date of a client certificate in seconds since
|
||||||
|
the epoch.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_cipher
|
||||||
|
|
||||||
|
Return a TLS cipher negotiated in this connection.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_protocol
|
||||||
|
|
||||||
|
Return a TLS protocol version negotiated in this connection.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_session_id
|
||||||
|
|
||||||
|
Return a session ID for this connection in hex string.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_session_reused
|
||||||
|
|
||||||
|
Return true if, and only if a SSL/TLS session is reused.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: alpn
|
||||||
|
|
||||||
|
Return ALPN identifier negotiated in this connection.
|
||||||
|
|
||||||
.. rb:class:: Request
|
.. rb:class:: Request
|
||||||
|
|
||||||
Object to represent request from client. The modification to
|
Object to represent request from client. The modification to
|
||||||
@@ -588,7 +662,7 @@ The replacement is done instantly without breaking existing
|
|||||||
connections or requests. It also avoids any process creation as is
|
connections or requests. It also avoids any process creation as is
|
||||||
the case with hot swapping with signals.
|
the case with hot swapping with signals.
|
||||||
|
|
||||||
The one limitation is that only numeric IP address is allowd in
|
The one limitation is that only numeric IP address is allowed in
|
||||||
:option:`backend <--backend>` in request body unless "dns" parameter
|
:option:`backend <--backend>` in request body unless "dns" parameter
|
||||||
is used while non numeric hostname is allowed in command-line or
|
is used while non numeric hostname is allowed in command-line or
|
||||||
configuration file is read using :option:`--conf`.
|
configuration file is read using :option:`--conf`.
|
||||||
|
|||||||
@@ -116,7 +116,10 @@ briefly describe what the library does in this area. In the following
|
|||||||
description, without loss of generality we omit CONTINUATION frame
|
description, without loss of generality we omit CONTINUATION frame
|
||||||
since they must follow HEADERS frame and are processed atomically. In
|
since they must follow HEADERS frame and are processed atomically. In
|
||||||
other words, they are just one big HEADERS frame. To disable these
|
other words, they are just one big HEADERS frame. To disable these
|
||||||
validations, use `nghttp2_option_set_no_http_messaging()`.
|
validations, use `nghttp2_option_set_no_http_messaging()`. Please
|
||||||
|
note that disabling this feature does not change the fundamental
|
||||||
|
client and server model of HTTP. That is, even if the validation is
|
||||||
|
disabled, only client can send requests.
|
||||||
|
|
||||||
For HTTP request, including those carried by PUSH_PROMISE, HTTP
|
For HTTP request, including those carried by PUSH_PROMISE, HTTP
|
||||||
message starts with one HEADERS frame containing request headers. It
|
message starts with one HEADERS frame containing request headers. It
|
||||||
@@ -149,13 +152,11 @@ header fields must not appear: "Connection", "Keep-Alive",
|
|||||||
Each header field name and value must obey the field-name and
|
Each header field name and value must obey the field-name and
|
||||||
field-value production rules described in `RFC 7230, section
|
field-value production rules described in `RFC 7230, section
|
||||||
3.2. <https://tools.ietf.org/html/rfc7230#section-3.2>`_.
|
3.2. <https://tools.ietf.org/html/rfc7230#section-3.2>`_.
|
||||||
Additionally, all field name must be lower cased. While the pseudo
|
Additionally, all field name must be lower cased. The invalid header
|
||||||
header fields must satisfy these rules, we just ignore illegal regular
|
fields are treated as stream error, and that stream is reset. If
|
||||||
headers (this means that these header fields are not passed to
|
application wants to treat these headers in their own way, use
|
||||||
application callback). This is because these illegal header fields
|
`nghttp2_on_invalid_header_callback
|
||||||
are floating around in existing internet and resetting stream just
|
<https://nghttp2.org/documentation/types.html#c.nghttp2_on_invalid_header_callback>`_.
|
||||||
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
|
For "http" or "https" URIs, ":path" pseudo header fields must start
|
||||||
with "/". The only exception is OPTIONS request, in that case, "*" is
|
with "/". The only exception is OPTIONS request, in that case, "*" is
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Building Android binary
|
|||||||
=======================
|
=======================
|
||||||
|
|
||||||
In this article, we briefly describe how to build Android binary using
|
In this article, we briefly describe how to build Android binary using
|
||||||
`Android NDK <http://developer.android.com/tools/sdk/ndk/index.html>`_
|
`Android NDK <https://developer.android.com/ndk/index.html>`_
|
||||||
cross-compiler on Debian Linux.
|
cross-compiler on Debian Linux.
|
||||||
|
|
||||||
The easiest way to build android binary is use Dockerfile.android.
|
The easiest way to build android binary is use Dockerfile.android.
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ Coding style
|
|||||||
We use clang-format to format source code consistently. The
|
We use clang-format to format source code consistently. The
|
||||||
clang-format configuration file .clang-format is located at the root
|
clang-format configuration file .clang-format is located at the root
|
||||||
directory. Since clang-format produces slightly different results
|
directory. Since clang-format produces slightly different results
|
||||||
between versions, we currently use clang-format which comes with
|
between versions, we currently use clang-format-5.0.
|
||||||
clang-3.9.
|
|
||||||
|
|
||||||
To detect any violation to the coding style, we recommend to setup git
|
To detect any violation to the coding style, we recommend to setup git
|
||||||
pre-commit hook to check coding style of the changes you introduced.
|
pre-commit hook to check coding style of the changes you introduced.
|
||||||
@@ -35,7 +34,7 @@ The pre-commit file is located at the root directory. Copy it under
|
|||||||
.git/hooks and make sure that it is executable. The pre-commit script
|
.git/hooks and make sure that it is executable. The pre-commit script
|
||||||
uses clang-format-diff.py to detect any style errors. If it is not in
|
uses clang-format-diff.py to detect any style errors. If it is not in
|
||||||
your PATH or it exists under different name (e.g.,
|
your PATH or it exists under different name (e.g.,
|
||||||
clang-format-diff-3.9 in debian), either add it to PATH variable or
|
clang-format-diff-5.0 in debian), either add it to PATH variable or
|
||||||
add git option ``clangformatdiff.binary`` to point to the script.
|
add git option ``clangformatdiff.binary`` to point to the script.
|
||||||
|
|
||||||
For emacs users, integrating clang-format to emacs is very easy.
|
For emacs users, integrating clang-format to emacs is very easy.
|
||||||
|
|||||||
@@ -3,16 +3,14 @@
|
|||||||
h2load - HTTP/2 benchmarking tool - HOW-TO
|
h2load - HTTP/2 benchmarking tool - HOW-TO
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
:doc:`h2load.1` is benchmarking tool for HTTP/2 and HTTP/1.1. If
|
:doc:`h2load.1` is benchmarking tool for HTTP/2 and HTTP/1.1. It
|
||||||
built with spdylay (http://tatsuhiro-t.github.io/spdylay/) library, it
|
supports SSL/TLS and clear text for all supported protocols.
|
||||||
also supports SPDY protocol. It supports SSL/TLS and clear text for
|
|
||||||
all supported protocols.
|
|
||||||
|
|
||||||
Compiling from source
|
Compiling from source
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
h2load is compiled alongside nghttp2 and requires that the
|
h2load is compiled alongside nghttp2 and requires that the
|
||||||
``--enable-apps`` flag is passed to ``./configure`` and `required
|
``--enable-app`` flag is passed to ``./configure`` and `required
|
||||||
dependencies <https://github.com/nghttp2/nghttp2#requirements>`_ are
|
dependencies <https://github.com/nghttp2/nghttp2#requirements>`_ are
|
||||||
available during compilation. For details on compiling, see `nghttp2:
|
available during compilation. For details on compiling, see `nghttp2:
|
||||||
Building from Git
|
Building from Git
|
||||||
@@ -64,23 +62,40 @@ The benchmarking result looks like this:
|
|||||||
See the h2load manual page :ref:`h2load-1-output` section for the
|
See the h2load manual page :ref:`h2load-1-output` section for the
|
||||||
explanation of the above numbers.
|
explanation of the above numbers.
|
||||||
|
|
||||||
|
Timing-based load-testing
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
As of v1.26.0, h2load supports timing-based load-testing. This method
|
||||||
|
performs load-testing in terms of a given duration instead of a
|
||||||
|
pre-defined number of requests. The new option :option:`--duration`
|
||||||
|
specifies how long the load-testing takes. For example,
|
||||||
|
``--duration=10`` makes h2load perform load-testing against a server
|
||||||
|
for 10 seconds. You can also specify a “warming-up” period with
|
||||||
|
:option:`--warm-up-time`. If :option:`--duration` is used,
|
||||||
|
:option:`-n` option is ignored.
|
||||||
|
|
||||||
|
The following command performs load-testing for 10 seconds after 5
|
||||||
|
seconds warming up period:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ h2load -c100 -m100 --duration=10 --warm-up-time=5 https://localhost
|
||||||
|
|
||||||
Flow Control
|
Flow Control
|
||||||
------------
|
------------
|
||||||
|
|
||||||
HTTP/2 and SPDY/3 or later employ flow control and it may affect
|
HTTP/2 has flow control and it may affect benchmarking results. By
|
||||||
benchmarking results. By default, h2load uses large enough flow
|
default, h2load uses large enough flow control window, which
|
||||||
control window, which effectively disables flow control. To adjust
|
effectively disables flow control. To adjust receiver flow control
|
||||||
receiver flow control window size, there are following options:
|
window size, there are following options:
|
||||||
|
|
||||||
:option:`-w`
|
:option:`-w`
|
||||||
Sets the stream level initial window size to
|
Sets the stream level initial window size to
|
||||||
(2**<N>)-1. For SPDY, 2**<N> is used instead.
|
(2**<N>)-1.
|
||||||
|
|
||||||
:option:`-W`
|
:option:`-W`
|
||||||
Sets the connection level initial window size to
|
Sets the connection level initial window size to
|
||||||
(2**<N>)-1. For SPDY, if <N> is strictly less
|
(2**<N>)-1.
|
||||||
than 16, this option is ignored. Otherwise
|
|
||||||
2**<N> is used for SPDY.
|
|
||||||
|
|
||||||
Multi-Threading
|
Multi-Threading
|
||||||
---------------
|
---------------
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ Normally, client does not stop even after all requests are done unless
|
|||||||
connection is lost. To stop client, call
|
connection is lost. To stop client, call
|
||||||
``nghttp2::asio_http2::server::session::shutdown()``.
|
``nghttp2::asio_http2::server::session::shutdown()``.
|
||||||
|
|
||||||
Recieve server push and enable SSL/TLS
|
Receive server push and enable SSL/TLS
|
||||||
++++++++++++++++++++++++++++++++++++++
|
++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ nghttpx - HTTP/2 proxy - HOW-TO
|
|||||||
===============================
|
===============================
|
||||||
|
|
||||||
:doc:`nghttpx.1` is a proxy translating protocols between HTTP/2 and
|
:doc:`nghttpx.1` is a proxy translating protocols between HTTP/2 and
|
||||||
other protocols (e.g., HTTP/1, SPDY). It operates in several modes
|
other protocols (e.g., HTTP/1). It operates in several modes and each
|
||||||
and each mode may require additional programs to work with. This
|
mode may require additional programs to work with. This article
|
||||||
article describes each operation mode and explains the intended
|
describes each operation mode and explains the intended use-cases. It
|
||||||
use-cases. It also covers some useful options later.
|
also covers some useful options later.
|
||||||
|
|
||||||
Default mode
|
Default mode
|
||||||
------------
|
------------
|
||||||
@@ -15,9 +15,7 @@ Default mode
|
|||||||
If nghttpx is invoked without :option:`--http2-proxy`, it operates in
|
If nghttpx is invoked without :option:`--http2-proxy`, it operates in
|
||||||
default mode. In this mode, it works as reverse proxy (gateway) for
|
default mode. In this mode, it works as reverse proxy (gateway) for
|
||||||
both HTTP/2 and HTTP/1 clients to backend servers. This is also known
|
both HTTP/2 and HTTP/1 clients to backend servers. This is also known
|
||||||
as "HTTP/2 router". If nghttpx is linked with spdylay library and
|
as "HTTP/2 router".
|
||||||
frontend connection is SSL/TLS, the frontend also supports SPDY
|
|
||||||
protocol.
|
|
||||||
|
|
||||||
By default, frontend connection is encrypted using SSL/TLS. So
|
By default, frontend connection is encrypted using SSL/TLS. So
|
||||||
server's private key and certificate must be supplied to the command
|
server's private key and certificate must be supplied to the command
|
||||||
@@ -25,11 +23,10 @@ line (or through configuration file). In this case, the frontend
|
|||||||
protocol selection will be done via ALPN or NPN.
|
protocol selection will be done via ALPN or NPN.
|
||||||
|
|
||||||
To turn off encryption on frontend connection, use ``no-tls`` keyword
|
To turn off encryption on frontend connection, use ``no-tls`` keyword
|
||||||
in :option:`--frontend` option. In this case, SPDY protocol is not
|
in :option:`--frontend` option. HTTP/2 and HTTP/1 are available on
|
||||||
available even if spdylay library is liked to nghttpx. HTTP/2 and
|
the frontend, and an HTTP/1 connection can be upgraded to HTTP/2 using
|
||||||
HTTP/1 are available on the frontend, and an HTTP/1 connection can be
|
HTTP Upgrade. Starting HTTP/2 connection by sending HTTP/2 connection
|
||||||
upgraded to HTTP/2 using HTTP Upgrade. Starting HTTP/2 connection by
|
preface is also supported.
|
||||||
sending HTTP/2 connection preface is also supported.
|
|
||||||
|
|
||||||
nghttpx can listen on multiple frontend addresses. This is achieved
|
nghttpx can listen on multiple frontend addresses. This is achieved
|
||||||
by using multiple :option:`--frontend` options. For each frontend
|
by using multiple :option:`--frontend` options. For each frontend
|
||||||
@@ -45,17 +42,17 @@ that default backend protocol is HTTP/1.1. To use HTTP/2 in backend,
|
|||||||
you have to specify ``h2`` in ``proto`` keyword in :option:`--backend`
|
you have to specify ``h2`` in ``proto`` keyword in :option:`--backend`
|
||||||
explicitly.
|
explicitly.
|
||||||
|
|
||||||
The backend is supposed to be Web server. For example, to make
|
The backend is supposed to be a Web server. For example, to make
|
||||||
nghttpx listen to encrypted HTTP/2 requests at port 8443, and a
|
nghttpx listen to encrypted HTTP/2 requests at port 8443, and a
|
||||||
backend Web server is configured to listen to HTTP request at port
|
backend Web server is configured to listen to HTTP requests at port
|
||||||
8080 in the same host, run nghttpx command-line like this:
|
8080 on the same host, run nghttpx command-line like this:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
$ nghttpx -f0.0.0.0,8443 -b127.0.0.1,8080 /path/to/server.key /path/to/server.crt
|
$ nghttpx -f0.0.0.0,8443 -b127.0.0.1,8080 /path/to/server.key /path/to/server.crt
|
||||||
|
|
||||||
Then HTTP/2 enabled client can access to the nghttpx in HTTP/2. For
|
Then an HTTP/2 enabled client can access the nghttpx server using HTTP/2. For
|
||||||
example, you can send GET request to the server using nghttp:
|
example, you can send a GET request using nghttp:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
@@ -66,19 +63,18 @@ HTTP/2 proxy mode
|
|||||||
|
|
||||||
If nghttpx is invoked with :option:`--http2-proxy` (or its shorthand
|
If nghttpx is invoked with :option:`--http2-proxy` (or its shorthand
|
||||||
:option:`-s`) option, it operates in HTTP/2 proxy mode. The supported
|
:option:`-s`) option, it operates in HTTP/2 proxy mode. The supported
|
||||||
protocols in frontend and backend connections are the same in `default
|
protocols in frontend and backend connections are the same as in `default
|
||||||
mode`_. The difference is that this mode acts like forward proxy and
|
mode`_. The difference is that this mode acts like a forward proxy and
|
||||||
assumes the backend is HTTP proxy server (e.g., Squid, Apache Traffic
|
assumes the backend is an HTTP proxy server (e.g., Squid, Apache Traffic
|
||||||
Server). HTTP/1 request must include absolute URI in request line.
|
Server). HTTP/1 requests must include an absolute URI in request line.
|
||||||
|
|
||||||
By default, frontend connection is encrypted. So this mode is also
|
By default, the frontend connection is encrypted. So this mode is
|
||||||
called secure proxy. If nghttpx is linked with spdylay, it supports
|
also called secure proxy.
|
||||||
SPDY protocols and it works as so called SPDY proxy.
|
|
||||||
|
|
||||||
To turn off encryption on frontend connection, use ``no-tls`` keyword
|
To turn off encryption on the frontend connection, use ``no-tls`` keyword
|
||||||
in :option:`--frontend` option.
|
in :option:`--frontend` option.
|
||||||
|
|
||||||
The backend must be HTTP proxy server. nghttpx supports multiple
|
The backend must be an HTTP proxy server. nghttpx supports multiple
|
||||||
backend server addresses. It translates incoming requests to HTTP
|
backend server addresses. It translates incoming requests to HTTP
|
||||||
request to backend server. The backend server performs real proxy
|
request to backend server. The backend server performs real proxy
|
||||||
work for each request, for example, dispatching requests to the origin
|
work for each request, for example, dispatching requests to the origin
|
||||||
@@ -92,7 +88,7 @@ connection, use :option:`--backend` option, and specify ``h2`` in
|
|||||||
|
|
||||||
For example, to make nghttpx listen to encrypted HTTP/2 requests at
|
For example, to make nghttpx listen to encrypted HTTP/2 requests at
|
||||||
port 8443, and a backend HTTP proxy server is configured to listen to
|
port 8443, and a backend HTTP proxy server is configured to listen to
|
||||||
HTTP/1 request at port 8080 in the same host, run nghttpx command-line
|
HTTP/1 requests at port 8080 on the same host, run nghttpx command-line
|
||||||
like this:
|
like this:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
@@ -102,8 +98,8 @@ like this:
|
|||||||
At the time of this writing, Firefox 41 and Chromium v46 can use
|
At the time of this writing, Firefox 41 and Chromium v46 can use
|
||||||
nghttpx as HTTP/2 proxy.
|
nghttpx as HTTP/2 proxy.
|
||||||
|
|
||||||
To make Firefox or Chromium use nghttpx as HTTP/2 or SPDY proxy, user
|
To make Firefox or Chromium use nghttpx as HTTP/2 proxy, user has to
|
||||||
has to create proxy.pac script file like this:
|
create proxy.pac script file like this:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
@@ -297,13 +293,31 @@ When you write this option in command-line, you should enclose
|
|||||||
argument with single or double quotes, since the character ``;`` has a
|
argument with single or double quotes, since the character ``;`` has a
|
||||||
special meaning in shell.
|
special meaning in shell.
|
||||||
|
|
||||||
To route, request to request path whose prefix is ``/foo`` to backend
|
To route, request to request path ``/foo`` to backend server
|
||||||
server ``[::1]:8080``, you can write like so:
|
``[::1]:8080``, you can write like so:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
backend=::1,8080;/foo
|
backend=::1,8080;/foo
|
||||||
|
|
||||||
|
If the last character of path pattern is ``/``, all request paths
|
||||||
|
which start with that pattern match:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
backend=::1,8080;/bar/
|
||||||
|
|
||||||
|
The request path ``/bar/buzz`` matches the ``/bar/``.
|
||||||
|
|
||||||
|
You can use ``*`` at the end of the path pattern to make it wildcard
|
||||||
|
pattern. ``*`` must match at least one character:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
backend=::1,8080;/sample*
|
||||||
|
|
||||||
|
The request path ``/sample1/foo`` matches the ``/sample*`` pattern.
|
||||||
|
|
||||||
Of course, you can specify both host and request path at the same
|
Of course, you can specify both host and request path at the same
|
||||||
time:
|
time:
|
||||||
|
|
||||||
@@ -371,7 +385,7 @@ parameter in :option:`--backend` option, like so:
|
|||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
backend=foo.example.com;;dns
|
backend=foo.example.com,80;;dns
|
||||||
|
|
||||||
nghttpx will cache resolved addresses for certain period of time. To
|
nghttpx will cache resolved addresses for certain period of time. To
|
||||||
change this cache period, use :option:`--dns-cache-timeout`.
|
change this cache period, use :option:`--dns-cache-timeout`.
|
||||||
@@ -387,6 +401,28 @@ like so:
|
|||||||
|
|
||||||
frontend=*,443;proxyproto
|
frontend=*,443;proxyproto
|
||||||
|
|
||||||
|
Session affinity
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Two kinds of session affinity are available: client IP, and HTTP
|
||||||
|
Cookie.
|
||||||
|
|
||||||
|
To enable client IP based affinity, specify ``affinity=ip`` parameter
|
||||||
|
in :option:`--backend` option. If PROXY protocol is enabled, then an
|
||||||
|
address obtained from PROXY protocol is taken into consideration.
|
||||||
|
|
||||||
|
To enable HTTP Cookie based affinity, specify ``affinity=cookie``
|
||||||
|
parameter, and specify a name of cookie in ``affinity-cookie-name``
|
||||||
|
parameter. Optionally, a Path attribute can be specified in
|
||||||
|
``affinity-cookie-path`` parameter:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
backend=127.0.0.1,3000;;affinity=cookie;affinity-cookie-name=nghttpxlb;affinity-cookie-path=/
|
||||||
|
|
||||||
|
Secure attribute of cookie is set if client connection is protected by
|
||||||
|
TLS.
|
||||||
|
|
||||||
PSK cipher suites
|
PSK cipher suites
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ remote server. It's defined as::
|
|||||||
bev = bufferevent_openssl_socket_new(
|
bev = bufferevent_openssl_socket_new(
|
||||||
evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
|
evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
|
||||||
BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
|
BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
|
||||||
|
bufferevent_enable(bev, EV_READ | EV_WRITE);
|
||||||
bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
|
bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
|
||||||
rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
|
rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
|
||||||
AF_UNSPEC, host, port);
|
AF_UNSPEC, host, port);
|
||||||
|
|||||||
@@ -7,11 +7,8 @@ if(ENABLE_EXAMPLES)
|
|||||||
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
|
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${CMAKE_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/lib/includes
|
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party"
|
||||||
${CMAKE_BINARY_DIR}/lib/includes
|
|
||||||
${CMAKE_SOURCE_DIR}/src/includes
|
|
||||||
${CMAKE_SOURCE_DIR}/third-party
|
|
||||||
|
|
||||||
${LIBEVENT_INCLUDE_DIRS}
|
${LIBEVENT_INCLUDE_DIRS}
|
||||||
${OPENSSL_INCLUDE_DIRS}
|
${OPENSSL_INCLUDE_DIRS}
|
||||||
|
|||||||
@@ -62,11 +62,11 @@ ASIOCPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
|
|||||||
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
|
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
|
||||||
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
|
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
|
||||||
$(top_builddir)/third-party/libhttp-parser.la \
|
$(top_builddir)/third-party/libhttp-parser.la \
|
||||||
|
@OPENSSL_LIBS@ \
|
||||||
${BOOST_LDFLAGS} \
|
${BOOST_LDFLAGS} \
|
||||||
${BOOST_ASIO_LIB} \
|
${BOOST_ASIO_LIB} \
|
||||||
${BOOST_THREAD_LIB} \
|
${BOOST_THREAD_LIB} \
|
||||||
${BOOST_SYSTEM_LIB} \
|
${BOOST_SYSTEM_LIB} \
|
||||||
@OPENSSL_LIBS@ \
|
|
||||||
@APPLDFLAGS@
|
@APPLDFLAGS@
|
||||||
|
|
||||||
asio_sv_SOURCES = asio-sv.cc
|
asio_sv_SOURCES = asio-sv.cc
|
||||||
|
|||||||
@@ -159,10 +159,13 @@ static void diec(const char *func, int error_code) {
|
|||||||
* bytes actually written. See the documentation of
|
* bytes actually written. See the documentation of
|
||||||
* nghttp2_send_callback for the details.
|
* nghttp2_send_callback for the details.
|
||||||
*/
|
*/
|
||||||
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
|
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
|
||||||
size_t length, int flags _U_, void *user_data) {
|
size_t length, int flags, void *user_data) {
|
||||||
struct Connection *connection;
|
struct Connection *connection;
|
||||||
int rv;
|
int rv;
|
||||||
|
(void)session;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
connection = (struct Connection *)user_data;
|
connection = (struct Connection *)user_data;
|
||||||
connection->want_io = IO_NONE;
|
connection->want_io = IO_NONE;
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
@@ -186,10 +189,13 @@ static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
|
|||||||
* |length| bytes. Returns the number of bytes stored in |buf|. See
|
* |length| bytes. Returns the number of bytes stored in |buf|. See
|
||||||
* the documentation of nghttp2_recv_callback for the details.
|
* the documentation of nghttp2_recv_callback for the details.
|
||||||
*/
|
*/
|
||||||
static ssize_t recv_callback(nghttp2_session *session _U_, uint8_t *buf,
|
static ssize_t recv_callback(nghttp2_session *session, uint8_t *buf,
|
||||||
size_t length, int flags _U_, void *user_data) {
|
size_t length, int flags, void *user_data) {
|
||||||
struct Connection *connection;
|
struct Connection *connection;
|
||||||
int rv;
|
int rv;
|
||||||
|
(void)session;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
connection = (struct Connection *)user_data;
|
connection = (struct Connection *)user_data;
|
||||||
connection->want_io = IO_NONE;
|
connection->want_io = IO_NONE;
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
@@ -210,9 +216,10 @@ static ssize_t recv_callback(nghttp2_session *session _U_, uint8_t *buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int on_frame_send_callback(nghttp2_session *session,
|
static int on_frame_send_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame, void *user_data) {
|
||||||
void *user_data _U_) {
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
switch (frame->hd.type) {
|
switch (frame->hd.type) {
|
||||||
case NGHTTP2_HEADERS:
|
case NGHTTP2_HEADERS:
|
||||||
if (nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
|
if (nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
|
||||||
@@ -237,9 +244,10 @@ static int on_frame_send_callback(nghttp2_session *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int on_frame_recv_callback(nghttp2_session *session,
|
static int on_frame_recv_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame, void *user_data) {
|
||||||
void *user_data _U_) {
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
switch (frame->hd.type) {
|
switch (frame->hd.type) {
|
||||||
case NGHTTP2_HEADERS:
|
case NGHTTP2_HEADERS:
|
||||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
|
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
|
||||||
@@ -274,9 +282,11 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
|||||||
* we submit GOAWAY and close the session.
|
* we submit GOAWAY and close the session.
|
||||||
*/
|
*/
|
||||||
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||||
uint32_t error_code _U_,
|
uint32_t error_code, void *user_data) {
|
||||||
void *user_data _U_) {
|
|
||||||
struct Request *req;
|
struct Request *req;
|
||||||
|
(void)error_code;
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||||
if (req) {
|
if (req) {
|
||||||
int rv;
|
int rv;
|
||||||
@@ -293,11 +303,13 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
|||||||
* The implementation of nghttp2_on_data_chunk_recv_callback type. We
|
* The implementation of nghttp2_on_data_chunk_recv_callback type. We
|
||||||
* use this function to print the received response body.
|
* use this function to print the received response body.
|
||||||
*/
|
*/
|
||||||
static int on_data_chunk_recv_callback(nghttp2_session *session,
|
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||||
uint8_t flags _U_, int32_t stream_id,
|
int32_t stream_id, const uint8_t *data,
|
||||||
const uint8_t *data, size_t len,
|
size_t len, void *user_data) {
|
||||||
void *user_data _U_) {
|
|
||||||
struct Request *req;
|
struct Request *req;
|
||||||
|
(void)flags;
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||||
if (req) {
|
if (req) {
|
||||||
printf("[INFO] C <---------------------------- S (DATA chunk)\n"
|
printf("[INFO] C <---------------------------- S (DATA chunk)\n"
|
||||||
@@ -338,10 +350,13 @@ static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {
|
|||||||
* HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2
|
* HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2
|
||||||
* library supports, we terminate program.
|
* library supports, we terminate program.
|
||||||
*/
|
*/
|
||||||
static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
|
static int select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||||
unsigned char *outlen, const unsigned char *in,
|
unsigned char *outlen, const unsigned char *in,
|
||||||
unsigned int inlen, void *arg _U_) {
|
unsigned int inlen, void *arg) {
|
||||||
int rv;
|
int rv;
|
||||||
|
(void)ssl;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
/* nghttp2_select_next_protocol() selects HTTP/2 protocol the
|
/* nghttp2_select_next_protocol() selects HTTP/2 protocol the
|
||||||
nghttp2 library supports. */
|
nghttp2 library supports. */
|
||||||
rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
|
rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ static void deflate(nghttp2_hd_deflater *deflater,
|
|||||||
static int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
|
static int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
|
||||||
size_t inlen, int final);
|
size_t inlen, int final);
|
||||||
|
|
||||||
int main(int argc _U_, char **argv _U_) {
|
int main() {
|
||||||
int rv;
|
int rv;
|
||||||
nghttp2_hd_deflater *deflater;
|
nghttp2_hd_deflater *deflater;
|
||||||
nghttp2_hd_inflater *inflater;
|
nghttp2_hd_inflater *inflater;
|
||||||
|
|||||||
@@ -199,22 +199,27 @@ static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen) {
|
|||||||
/* nghttp2_send_callback. Here we transmit the |data|, |length| bytes,
|
/* nghttp2_send_callback. Here we transmit the |data|, |length| bytes,
|
||||||
to the network. Because we are using libevent bufferevent, we just
|
to the network. Because we are using libevent bufferevent, we just
|
||||||
write those bytes into bufferevent buffer. */
|
write those bytes into bufferevent buffer. */
|
||||||
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
|
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
|
||||||
size_t length, int flags _U_, void *user_data) {
|
size_t length, int flags, void *user_data) {
|
||||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||||
struct bufferevent *bev = session_data->bev;
|
struct bufferevent *bev = session_data->bev;
|
||||||
|
(void)session;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
bufferevent_write(bev, data, length);
|
bufferevent_write(bev, data, length);
|
||||||
return (ssize_t)length;
|
return (ssize_t)length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* nghttp2_on_header_callback: Called when nghttp2 library emits
|
/* nghttp2_on_header_callback: Called when nghttp2 library emits
|
||||||
single header name/value pair. */
|
single header name/value pair. */
|
||||||
static int on_header_callback(nghttp2_session *session _U_,
|
static int on_header_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame, const uint8_t *name,
|
const nghttp2_frame *frame, const uint8_t *name,
|
||||||
size_t namelen, const uint8_t *value,
|
size_t namelen, const uint8_t *value,
|
||||||
size_t valuelen, uint8_t flags _U_,
|
size_t valuelen, uint8_t flags, void *user_data) {
|
||||||
void *user_data) {
|
|
||||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||||
|
(void)session;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
switch (frame->hd.type) {
|
switch (frame->hd.type) {
|
||||||
case NGHTTP2_HEADERS:
|
case NGHTTP2_HEADERS:
|
||||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||||
@@ -229,10 +234,12 @@ static int on_header_callback(nghttp2_session *session _U_,
|
|||||||
|
|
||||||
/* nghttp2_on_begin_headers_callback: Called when nghttp2 library gets
|
/* nghttp2_on_begin_headers_callback: Called when nghttp2 library gets
|
||||||
started to receive header block. */
|
started to receive header block. */
|
||||||
static int on_begin_headers_callback(nghttp2_session *session _U_,
|
static int on_begin_headers_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame,
|
||||||
void *user_data) {
|
void *user_data) {
|
||||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||||
|
(void)session;
|
||||||
|
|
||||||
switch (frame->hd.type) {
|
switch (frame->hd.type) {
|
||||||
case NGHTTP2_HEADERS:
|
case NGHTTP2_HEADERS:
|
||||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||||
@@ -247,9 +254,11 @@ static int on_begin_headers_callback(nghttp2_session *session _U_,
|
|||||||
|
|
||||||
/* nghttp2_on_frame_recv_callback: Called when nghttp2 library
|
/* nghttp2_on_frame_recv_callback: Called when nghttp2 library
|
||||||
received a complete frame from the remote peer. */
|
received a complete frame from the remote peer. */
|
||||||
static int on_frame_recv_callback(nghttp2_session *session _U_,
|
static int on_frame_recv_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame, void *user_data) {
|
const nghttp2_frame *frame, void *user_data) {
|
||||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||||
|
(void)session;
|
||||||
|
|
||||||
switch (frame->hd.type) {
|
switch (frame->hd.type) {
|
||||||
case NGHTTP2_HEADERS:
|
case NGHTTP2_HEADERS:
|
||||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||||
@@ -266,11 +275,13 @@ static int on_frame_recv_callback(nghttp2_session *session _U_,
|
|||||||
is meant to the stream we initiated, print the received data in
|
is meant to the stream we initiated, print the received data in
|
||||||
stdout, so that the user can redirect its output to the file
|
stdout, so that the user can redirect its output to the file
|
||||||
easily. */
|
easily. */
|
||||||
static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
|
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||||
uint8_t flags _U_, int32_t stream_id,
|
int32_t stream_id, const uint8_t *data,
|
||||||
const uint8_t *data, size_t len,
|
size_t len, void *user_data) {
|
||||||
void *user_data) {
|
|
||||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||||
|
(void)session;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
if (session_data->stream_data->stream_id == stream_id) {
|
if (session_data->stream_data->stream_id == stream_id) {
|
||||||
fwrite(data, 1, len, stdout);
|
fwrite(data, 1, len, stdout);
|
||||||
}
|
}
|
||||||
@@ -300,9 +311,12 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
|||||||
/* NPN TLS extension client callback. We check that server advertised
|
/* NPN TLS extension client callback. We check that server advertised
|
||||||
the HTTP/2 protocol the nghttp2 library supports. If not, exit
|
the HTTP/2 protocol the nghttp2 library supports. If not, exit
|
||||||
the program. */
|
the program. */
|
||||||
static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
|
static int select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||||
unsigned char *outlen, const unsigned char *in,
|
unsigned char *outlen, const unsigned char *in,
|
||||||
unsigned int inlen, void *arg _U_) {
|
unsigned int inlen, void *arg) {
|
||||||
|
(void)ssl;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||||
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
|
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
|
||||||
}
|
}
|
||||||
@@ -461,8 +475,10 @@ static void readcb(struct bufferevent *bev, void *ptr) {
|
|||||||
receiving GOAWAY, we check the some conditions on the nghttp2
|
receiving GOAWAY, we check the some conditions on the nghttp2
|
||||||
library and output buffer of bufferevent. If it indicates we have
|
library and output buffer of bufferevent. If it indicates we have
|
||||||
no business to this session, tear down the connection. */
|
no business to this session, tear down the connection. */
|
||||||
static void writecb(struct bufferevent *bev _U_, void *ptr) {
|
static void writecb(struct bufferevent *bev, void *ptr) {
|
||||||
http2_session_data *session_data = (http2_session_data *)ptr;
|
http2_session_data *session_data = (http2_session_data *)ptr;
|
||||||
|
(void)bev;
|
||||||
|
|
||||||
if (nghttp2_session_want_read(session_data->session) == 0 &&
|
if (nghttp2_session_want_read(session_data->session) == 0 &&
|
||||||
nghttp2_session_want_write(session_data->session) == 0 &&
|
nghttp2_session_want_write(session_data->session) == 0 &&
|
||||||
evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
|
evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
|
||||||
@@ -532,6 +548,7 @@ static void initiate_connection(struct event_base *evbase, SSL_CTX *ssl_ctx,
|
|||||||
bev = bufferevent_openssl_socket_new(
|
bev = bufferevent_openssl_socket_new(
|
||||||
evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
|
evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
|
||||||
BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
|
BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
|
||||||
|
bufferevent_enable(bev, EV_READ | EV_WRITE);
|
||||||
bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
|
bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
|
||||||
rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
|
rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
|
||||||
AF_UNSPEC, host, port);
|
AF_UNSPEC, host, port);
|
||||||
|
|||||||
@@ -109,18 +109,23 @@ struct app_context {
|
|||||||
static unsigned char next_proto_list[256];
|
static unsigned char next_proto_list[256];
|
||||||
static size_t next_proto_list_len;
|
static size_t next_proto_list_len;
|
||||||
|
|
||||||
static int next_proto_cb(SSL *s _U_, const unsigned char **data,
|
static int next_proto_cb(SSL *ssl, const unsigned char **data,
|
||||||
unsigned int *len, void *arg _U_) {
|
unsigned int *len, void *arg) {
|
||||||
|
(void)ssl;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
*data = next_proto_list;
|
*data = next_proto_list;
|
||||||
*len = (unsigned int)next_proto_list_len;
|
*len = (unsigned int)next_proto_list_len;
|
||||||
return SSL_TLSEXT_ERR_OK;
|
return SSL_TLSEXT_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
static int alpn_select_proto_cb(SSL *ssl _U_, const unsigned char **out,
|
static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
|
||||||
unsigned char *outlen, const unsigned char *in,
|
unsigned char *outlen, const unsigned char *in,
|
||||||
unsigned int inlen, void *arg _U_) {
|
unsigned int inlen, void *arg) {
|
||||||
int rv;
|
int rv;
|
||||||
|
(void)ssl;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen);
|
rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen);
|
||||||
|
|
||||||
@@ -197,8 +202,10 @@ static void add_stream(http2_session_data *session_data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_stream(http2_session_data *session_data _U_,
|
static void remove_stream(http2_session_data *session_data,
|
||||||
http2_stream_data *stream_data) {
|
http2_stream_data *stream_data) {
|
||||||
|
(void)session_data;
|
||||||
|
|
||||||
stream_data->prev->next = stream_data->next;
|
stream_data->prev->next = stream_data->next;
|
||||||
if (stream_data->next) {
|
if (stream_data->next) {
|
||||||
stream_data->next->prev = stream_data->prev;
|
stream_data->next->prev = stream_data->prev;
|
||||||
@@ -243,6 +250,7 @@ static http2_session_data *create_http2_session_data(app_context *app_ctx,
|
|||||||
session_data->bev = bufferevent_openssl_socket_new(
|
session_data->bev = bufferevent_openssl_socket_new(
|
||||||
app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
|
app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
|
||||||
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
|
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
|
||||||
|
bufferevent_enable(session_data->bev, EV_READ | EV_WRITE);
|
||||||
rv = getnameinfo(addr, (socklen_t)addrlen, host, sizeof(host), NULL, 0,
|
rv = getnameinfo(addr, (socklen_t)addrlen, host, sizeof(host), NULL, 0,
|
||||||
NI_NUMERICHOST);
|
NI_NUMERICHOST);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
@@ -309,10 +317,13 @@ static int session_recv(http2_session_data *session_data) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
|
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
|
||||||
size_t length, int flags _U_, void *user_data) {
|
size_t length, int flags, void *user_data) {
|
||||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||||
struct bufferevent *bev = session_data->bev;
|
struct bufferevent *bev = session_data->bev;
|
||||||
|
(void)session;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
/* Avoid excessive buffering in server side. */
|
/* Avoid excessive buffering in server side. */
|
||||||
if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
|
if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
|
||||||
OUTPUT_WOULDBLOCK_THRESHOLD) {
|
OUTPUT_WOULDBLOCK_THRESHOLD) {
|
||||||
@@ -375,13 +386,17 @@ static char *percent_decode(const uint8_t *value, size_t valuelen) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t file_read_callback(nghttp2_session *session _U_,
|
static ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
||||||
int32_t stream_id _U_, uint8_t *buf,
|
uint8_t *buf, size_t length,
|
||||||
size_t length, uint32_t *data_flags,
|
uint32_t *data_flags,
|
||||||
nghttp2_data_source *source,
|
nghttp2_data_source *source,
|
||||||
void *user_data _U_) {
|
void *user_data) {
|
||||||
int fd = source->fd;
|
int fd = source->fd;
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
|
(void)session;
|
||||||
|
(void)stream_id;
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
|
while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
|
||||||
;
|
;
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
@@ -454,10 +469,12 @@ static int error_reply(nghttp2_session *session,
|
|||||||
static int on_header_callback(nghttp2_session *session,
|
static int on_header_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame, const uint8_t *name,
|
const nghttp2_frame *frame, const uint8_t *name,
|
||||||
size_t namelen, const uint8_t *value,
|
size_t namelen, const uint8_t *value,
|
||||||
size_t valuelen, uint8_t flags _U_,
|
size_t valuelen, uint8_t flags, void *user_data) {
|
||||||
void *user_data _U_) {
|
|
||||||
http2_stream_data *stream_data;
|
http2_stream_data *stream_data;
|
||||||
const char PATH[] = ":path";
|
const char PATH[] = ":path";
|
||||||
|
(void)flags;
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
switch (frame->hd.type) {
|
switch (frame->hd.type) {
|
||||||
case NGHTTP2_HEADERS:
|
case NGHTTP2_HEADERS:
|
||||||
if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||||
@@ -570,9 +587,10 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||||
uint32_t error_code _U_, void *user_data) {
|
uint32_t error_code, void *user_data) {
|
||||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||||
http2_stream_data *stream_data;
|
http2_stream_data *stream_data;
|
||||||
|
(void)error_code;
|
||||||
|
|
||||||
stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
|
stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||||
if (!stream_data) {
|
if (!stream_data) {
|
||||||
@@ -625,8 +643,10 @@ static int send_server_connection_header(http2_session_data *session_data) {
|
|||||||
|
|
||||||
/* readcb for bufferevent after client connection header was
|
/* readcb for bufferevent after client connection header was
|
||||||
checked. */
|
checked. */
|
||||||
static void readcb(struct bufferevent *bev _U_, void *ptr) {
|
static void readcb(struct bufferevent *bev, void *ptr) {
|
||||||
http2_session_data *session_data = (http2_session_data *)ptr;
|
http2_session_data *session_data = (http2_session_data *)ptr;
|
||||||
|
(void)bev;
|
||||||
|
|
||||||
if (session_recv(session_data) != 0) {
|
if (session_recv(session_data) != 0) {
|
||||||
delete_http2_session_data(session_data);
|
delete_http2_session_data(session_data);
|
||||||
return;
|
return;
|
||||||
@@ -658,12 +678,13 @@ static void writecb(struct bufferevent *bev, void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* eventcb for bufferevent */
|
/* eventcb for bufferevent */
|
||||||
static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
|
static void eventcb(struct bufferevent *bev, short events, void *ptr) {
|
||||||
http2_session_data *session_data = (http2_session_data *)ptr;
|
http2_session_data *session_data = (http2_session_data *)ptr;
|
||||||
if (events & BEV_EVENT_CONNECTED) {
|
if (events & BEV_EVENT_CONNECTED) {
|
||||||
const unsigned char *alpn = NULL;
|
const unsigned char *alpn = NULL;
|
||||||
unsigned int alpnlen = 0;
|
unsigned int alpnlen = 0;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
|
(void)bev;
|
||||||
|
|
||||||
fprintf(stderr, "%s connected\n", session_data->client_addr);
|
fprintf(stderr, "%s connected\n", session_data->client_addr);
|
||||||
|
|
||||||
@@ -703,10 +724,11 @@ static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* callback for evconnlistener */
|
/* callback for evconnlistener */
|
||||||
static void acceptcb(struct evconnlistener *listener _U_, int fd,
|
static void acceptcb(struct evconnlistener *listener, int fd,
|
||||||
struct sockaddr *addr, int addrlen, void *arg) {
|
struct sockaddr *addr, int addrlen, void *arg) {
|
||||||
app_context *app_ctx = (app_context *)arg;
|
app_context *app_ctx = (app_context *)arg;
|
||||||
http2_session_data *session_data;
|
http2_session_data *session_data;
|
||||||
|
(void)listener;
|
||||||
|
|
||||||
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
|
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ following compiler/linker flags:
|
|||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
CPPFLAGS="-fsanitize-coverage=edge -fsanitize=addres"
|
CPPFLAGS="-fsanitize-coverage=edge -fsanitize=address"
|
||||||
LDFLAGS="-fsanitize-coverage=edge -fsanitize=addres"
|
LDFLAGS="-fsanitize-coverage=edge -fsanitize=address"
|
||||||
|
|
||||||
Then, fuzz_target.cc can be built using the following command:
|
Then, fuzz_target.cc can be built using the following command:
|
||||||
|
|
||||||
|
|||||||
@@ -163,6 +163,12 @@ OPTIONS = [
|
|||||||
"redirect-https-port",
|
"redirect-https-port",
|
||||||
"frontend-max-requests",
|
"frontend-max-requests",
|
||||||
"single-thread",
|
"single-thread",
|
||||||
|
"single-process",
|
||||||
|
"no-add-x-forwarded-proto",
|
||||||
|
"no-strip-incoming-x-forwarded-proto",
|
||||||
|
"ocsp-startup",
|
||||||
|
"no-verify-ocsp",
|
||||||
|
"verify-client-tolerate-expired",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGVARS = [
|
LOGVARS = [
|
||||||
@@ -181,6 +187,16 @@ LOGVARS = [
|
|||||||
"ssl_protocol",
|
"ssl_protocol",
|
||||||
"ssl_session_id",
|
"ssl_session_id",
|
||||||
"ssl_session_reused",
|
"ssl_session_reused",
|
||||||
|
"tls_cipher",
|
||||||
|
"tls_protocol",
|
||||||
|
"tls_session_id",
|
||||||
|
"tls_session_reused",
|
||||||
|
"tls_sni",
|
||||||
|
"tls_client_fingerprint_sha256",
|
||||||
|
"tls_client_fingerprint_sha1",
|
||||||
|
"tls_client_subject_name",
|
||||||
|
"tls_client_issuer_name",
|
||||||
|
"tls_client_serial",
|
||||||
"backend_host",
|
"backend_host",
|
||||||
"backend_port",
|
"backend_port",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
GO_FILES = \
|
GO_FILES = \
|
||||||
nghttpx_http1_test.go \
|
nghttpx_http1_test.go \
|
||||||
nghttpx_http2_test.go \
|
nghttpx_http2_test.go \
|
||||||
nghttpx_spdy_test.go \
|
|
||||||
server_tester.go
|
server_tester.go
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
@@ -43,7 +42,6 @@ EXTRA_DIST = \
|
|||||||
itprep:
|
itprep:
|
||||||
go get -d -v golang.org/x/net/http2
|
go get -d -v golang.org/x/net/http2
|
||||||
go get -d -v github.com/tatsuhiro-t/go-nghttp2
|
go get -d -v github.com/tatsuhiro-t/go-nghttp2
|
||||||
go get -d -v github.com/tatsuhiro-t/spdy
|
|
||||||
go get -d -v golang.org/x/net/websocket
|
go get -d -v golang.org/x/net/websocket
|
||||||
|
|
||||||
it:
|
it:
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"golang.org/x/net/websocket"
|
"golang.org/x/net/websocket"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -125,6 +126,54 @@ Content-Length: 0
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// TestH1H1AffinityCookie tests that affinity cookie is sent back in
|
||||||
|
// cleartext http.
|
||||||
|
func TestH1H1AffinityCookie(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--affinity-cookie"}, t, noopHandler)
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http1(requestParam{
|
||||||
|
name: "TestH1H1AffinityCookie",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http1() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar`
|
||||||
|
validCookie := regexp.MustCompile(pattern)
|
||||||
|
if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
|
||||||
|
t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH1H1AffinityCookieTLS tests that affinity cookie is sent back
|
||||||
|
// in https.
|
||||||
|
func TestH1H1AffinityCookieTLS(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--alpn-h1", "--affinity-cookie"}, t, noopHandler)
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http1(requestParam{
|
||||||
|
name: "TestH1H1AffinityCookieTLS",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http1() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure`
|
||||||
|
validCookie := regexp.MustCompile(pattern)
|
||||||
|
if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
|
||||||
|
t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH1H1GracefulShutdown tests graceful shutdown.
|
// TestH1H1GracefulShutdown tests graceful shutdown.
|
||||||
func TestH1H1GracefulShutdown(t *testing.T) {
|
func TestH1H1GracefulShutdown(t *testing.T) {
|
||||||
st := newServerTester(nil, t, noopHandler)
|
st := newServerTester(nil, t, noopHandler)
|
||||||
@@ -162,7 +211,7 @@ func TestH1H1GracefulShutdown(t *testing.T) {
|
|||||||
want := io.EOF
|
want := io.EOF
|
||||||
b := make([]byte, 256)
|
b := make([]byte, 256)
|
||||||
if _, err := st.conn.Read(b); err == nil || err != want {
|
if _, err := st.conn.Read(b); err == nil || err != want {
|
||||||
t.Errorf("st.conn.Read(): %v; want %v, %v", err, want)
|
t.Errorf("st.conn.Read(): %v; want %v", err, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,105 @@ func TestH2H1PlainGET(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H1AddXfp tests that server appends :scheme to the existing
|
||||||
|
// x-forwarded-proto header field.
|
||||||
|
func TestH2H1AddXfp(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
xfp := r.Header.Get("X-Forwarded-Proto")
|
||||||
|
if got, want := xfp, "foo, http"; got != want {
|
||||||
|
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1AddXfp",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("x-forwarded-proto", "foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1NoAddXfp tests that server does not append :scheme to the
|
||||||
|
// existing x-forwarded-proto header field.
|
||||||
|
func TestH2H1NoAddXfp(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--no-add-x-forwarded-proto", "--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
xfp := r.Header.Get("X-Forwarded-Proto")
|
||||||
|
if got, want := xfp, "foo"; got != want {
|
||||||
|
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1NoAddXfp",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("x-forwarded-proto", "foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1StripXfp tests that server strips incoming
|
||||||
|
// x-forwarded-proto header field.
|
||||||
|
func TestH2H1StripXfp(t *testing.T) {
|
||||||
|
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
xfp := r.Header.Get("X-Forwarded-Proto")
|
||||||
|
if got, want := xfp, "http"; got != want {
|
||||||
|
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1StripXfp",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("x-forwarded-proto", "foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1StripNoAddXfp tests that server strips incoming
|
||||||
|
// x-forwarded-proto header field, and does not add another.
|
||||||
|
func TestH2H1StripNoAddXfp(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--no-add-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if got, found := r.Header["X-Forwarded-Proto"]; found {
|
||||||
|
t.Errorf("X-Forwarded-Proto = %q; want nothing", got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1StripNoAddXfp",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("x-forwarded-proto", "foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2H1AddXff tests that server generates X-Forwarded-For header
|
// TestH2H1AddXff tests that server generates X-Forwarded-For header
|
||||||
// field when forwarding request to backend.
|
// field when forwarding request to backend.
|
||||||
func TestH2H1AddXff(t *testing.T) {
|
func TestH2H1AddXff(t *testing.T) {
|
||||||
@@ -1014,14 +1113,45 @@ func TestH2H1Upgrade(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H1ProxyProtocolV1ForwardedForObfuscated tests that Forwarded
|
||||||
|
// header field includes obfuscated address even if PROXY protocol
|
||||||
|
// version 1 containing TCP4 entry is accepted.
|
||||||
|
func TestH2H1ProxyProtocolV1ForwardedForObfuscated(t *testing.T) {
|
||||||
|
pattern := fmt.Sprintf(`^for=_[^;]+$`)
|
||||||
|
validFwd := regexp.MustCompile(pattern)
|
||||||
|
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=obfuscated"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
|
||||||
|
t.Errorf("Forwarded: %v; want pattern %v", got, pattern)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n"))
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1ProxyProtocolV1ForwardedForObfuscated",
|
||||||
|
})
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2H1ProxyProtocolV1TCP4 tests PROXY protocol version 1
|
// TestH2H1ProxyProtocolV1TCP4 tests PROXY protocol version 1
|
||||||
// containing TCP4 entry is accepted and X-Forwarded-For contains
|
// containing TCP4 entry is accepted and X-Forwarded-For contains
|
||||||
// advertised src address.
|
// advertised src address.
|
||||||
func TestH2H1ProxyProtocolV1TCP4(t *testing.T) {
|
func TestH2H1ProxyProtocolV1TCP4(t *testing.T) {
|
||||||
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
|
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
|
if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
|
||||||
t.Errorf("X-Forwarded-For: %v; want %v", got, want)
|
t.Errorf("X-Forwarded-For: %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
|
if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
|
||||||
|
t.Errorf("Forwarded: %v; want %v", got, want)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
|
|
||||||
@@ -1044,10 +1174,13 @@ func TestH2H1ProxyProtocolV1TCP4(t *testing.T) {
|
|||||||
// containing TCP6 entry is accepted and X-Forwarded-For contains
|
// containing TCP6 entry is accepted and X-Forwarded-For contains
|
||||||
// advertised src address.
|
// advertised src address.
|
||||||
func TestH2H1ProxyProtocolV1TCP6(t *testing.T) {
|
func TestH2H1ProxyProtocolV1TCP6(t *testing.T) {
|
||||||
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
|
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want {
|
if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want {
|
||||||
t.Errorf("X-Forwarded-For: %v; want %v", got, want)
|
t.Errorf("X-Forwarded-For: %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
|
if got, want := r.Header.Get("Forwarded"), `for="[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"`; got != want {
|
||||||
|
t.Errorf("Forwarded: %v; want %v", got, want)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
|
|
||||||
@@ -1069,9 +1202,12 @@ func TestH2H1ProxyProtocolV1TCP6(t *testing.T) {
|
|||||||
// TestH2H1ProxyProtocolV1Unknown tests PROXY protocol version 1
|
// TestH2H1ProxyProtocolV1Unknown tests PROXY protocol version 1
|
||||||
// containing UNKNOWN entry is accepted.
|
// containing UNKNOWN entry is accepted.
|
||||||
func TestH2H1ProxyProtocolV1Unknown(t *testing.T) {
|
func TestH2H1ProxyProtocolV1Unknown(t *testing.T) {
|
||||||
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
|
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
if got, notWant := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got == notWant {
|
if got, notWant := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got == notWant {
|
||||||
t.Errorf("X-Forwarded-For: %v")
|
t.Errorf("X-Forwarded-For: %v; want something else", got)
|
||||||
|
}
|
||||||
|
if got, notWant := r.Header.Get("Forwarded"), "for=192.168.0.2"; got == notWant {
|
||||||
|
t.Errorf("Forwarded: %v; want something else", got)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
@@ -1449,6 +1585,175 @@ func TestH2H1HTTPSRedirectPort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H1Code204 tests that 204 response without content-length, and
|
||||||
|
// transfer-encoding is valid.
|
||||||
|
func TestH2H1Code204(t *testing.T) {
|
||||||
|
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1Code204",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 204; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1Code204CL0 tests that 204 response with content-length: 0
|
||||||
|
// is allowed.
|
||||||
|
func TestH2H1Code204CL0(t *testing.T) {
|
||||||
|
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
hj, ok := w.(http.Hijacker)
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn, bufrw, err := hj.Hijack()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 0\r\n\r\n")
|
||||||
|
bufrw.Flush()
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1Code204CL0",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 204; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, found := res.header["Content-Length"]; found {
|
||||||
|
t.Errorf("Content-Length = %v, want nothing", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1Code204CLNonzero tests that 204 response with nonzero
|
||||||
|
// content-length is not allowed.
|
||||||
|
func TestH2H1Code204CLNonzero(t *testing.T) {
|
||||||
|
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
hj, ok := w.(http.Hijacker)
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn, bufrw, err := hj.Hijack()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 1\r\n\r\n")
|
||||||
|
bufrw.Flush()
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1Code204CLNonzero",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 502; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1Code204TE tests that 204 response with transfer-encoding is
|
||||||
|
// not allowed.
|
||||||
|
func TestH2H1Code204TE(t *testing.T) {
|
||||||
|
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
hj, ok := w.(http.Hijacker)
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn, bufrw, err := hj.Hijack()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
bufrw.WriteString("HTTP/1.1 204\r\nTransfer-Encoding: chunked\r\n\r\n")
|
||||||
|
bufrw.Flush()
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1Code204TE",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 502; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1AffinityCookie tests that affinity cookie is sent back in
|
||||||
|
// cleartext http.
|
||||||
|
func TestH2H1AffinityCookie(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--affinity-cookie"}, t, noopHandler)
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1AffinityCookie",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar`
|
||||||
|
validCookie := regexp.MustCompile(pattern)
|
||||||
|
if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
|
||||||
|
t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1AffinityCookieTLS tests that affinity cookie is sent back
|
||||||
|
// in https.
|
||||||
|
func TestH2H1AffinityCookieTLS(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--affinity-cookie"}, t, noopHandler)
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1AffinityCookieTLS",
|
||||||
|
scheme: "https",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure`
|
||||||
|
validCookie := regexp.MustCompile(pattern)
|
||||||
|
if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
|
||||||
|
t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2H1GracefulShutdown tests graceful shutdown.
|
// TestH2H1GracefulShutdown tests graceful shutdown.
|
||||||
func TestH2H1GracefulShutdown(t *testing.T) {
|
func TestH2H1GracefulShutdown(t *testing.T) {
|
||||||
st := newServerTester(nil, t, noopHandler)
|
st := newServerTester(nil, t, noopHandler)
|
||||||
@@ -1653,6 +1958,105 @@ func TestH2H2TLSXfp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H2AddXfp tests that server appends :scheme to the existing
|
||||||
|
// x-forwarded-proto header field.
|
||||||
|
func TestH2H2AddXfp(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--http2-bridge", "--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
xfp := r.Header.Get("X-Forwarded-Proto")
|
||||||
|
if got, want := xfp, "foo, http"; got != want {
|
||||||
|
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H2AddXfp",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("x-forwarded-proto", "foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H2NoAddXfp tests that server does not append :scheme to the
|
||||||
|
// existing x-forwarded-proto header field.
|
||||||
|
func TestH2H2NoAddXfp(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--http2-bridge", "--no-add-x-forwarded-proto", "--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
xfp := r.Header.Get("X-Forwarded-Proto")
|
||||||
|
if got, want := xfp, "foo"; got != want {
|
||||||
|
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H2NoAddXfp",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("x-forwarded-proto", "foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H2StripXfp tests that server strips incoming
|
||||||
|
// x-forwarded-proto header field.
|
||||||
|
func TestH2H2StripXfp(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
xfp := r.Header.Get("X-Forwarded-Proto")
|
||||||
|
if got, want := xfp, "http"; got != want {
|
||||||
|
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H2StripXfp",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("x-forwarded-proto", "foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H2StripNoAddXfp tests that server strips incoming
|
||||||
|
// x-forwarded-proto header field, and does not add another.
|
||||||
|
func TestH2H2StripNoAddXfp(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--http2-bridge", "--no-add-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if got, found := r.Header["X-Forwarded-Proto"]; found {
|
||||||
|
t.Errorf("X-Forwarded-Proto = %q; want nothing", got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H2StripNoAddXfp",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("x-forwarded-proto", "foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2H2AddXff tests that server generates X-Forwarded-For header
|
// TestH2H2AddXff tests that server generates X-Forwarded-For header
|
||||||
// field when forwarding request to backend.
|
// field when forwarding request to backend.
|
||||||
func TestH2H2AddXff(t *testing.T) {
|
func TestH2H2AddXff(t *testing.T) {
|
||||||
@@ -1961,6 +2365,26 @@ func TestH2H2DNS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H2Code204 tests that 204 response without content-length, and
|
||||||
|
// transfer-encoding is valid.
|
||||||
|
func TestH2H2Code204(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H2Code204",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 204; got != want {
|
||||||
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2APIBackendconfig exercise backendconfig API endpoint routine
|
// TestH2APIBackendconfig exercise backendconfig API endpoint routine
|
||||||
// for successful case.
|
// for successful case.
|
||||||
func TestH2APIBackendconfig(t *testing.T) {
|
func TestH2APIBackendconfig(t *testing.T) {
|
||||||
|
|||||||
@@ -1,664 +0,0 @@
|
|||||||
package nghttp2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/tatsuhiro-t/spdy"
|
|
||||||
"golang.org/x/net/http2/hpack"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestS3H1PlainGET tests whether simple SPDY GET request works.
|
|
||||||
func TestS3H1PlainGET(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, noopHandler)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1PlainGET",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
want := 200
|
|
||||||
if got := res.status; got != want {
|
|
||||||
t.Errorf("status = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1BadRequestCL tests that server rejects request whose
|
|
||||||
// content-length header field value does not match its request body
|
|
||||||
// size.
|
|
||||||
func TestS3H1BadRequestCL(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, noopHandler)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
// we set content-length: 1024, but the actual request body is
|
|
||||||
// 3 bytes.
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1BadRequestCL",
|
|
||||||
method: "POST",
|
|
||||||
header: []hpack.HeaderField{
|
|
||||||
pair("content-length", "1024"),
|
|
||||||
},
|
|
||||||
body: []byte("foo"),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
want := spdy.ProtocolError
|
|
||||||
if got := res.spdyRstErrCode; got != want {
|
|
||||||
t.Errorf("res.spdyRstErrCode = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1MultipleRequestCL tests that server rejects request with
|
|
||||||
// multiple Content-Length request header fields.
|
|
||||||
func TestS3H1MultipleRequestCL(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Errorf("server should not forward bad request")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1MultipleRequestCL",
|
|
||||||
header: []hpack.HeaderField{
|
|
||||||
pair("content-length", "1"),
|
|
||||||
pair("content-length", "1"),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
want := 400
|
|
||||||
if got := res.status; got != want {
|
|
||||||
t.Errorf("status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1InvalidRequestCL tests that server rejects request with
|
|
||||||
// Content-Length which cannot be parsed as a number.
|
|
||||||
func TestS3H1InvalidRequestCL(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Errorf("server should not forward bad request")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1InvalidRequestCL",
|
|
||||||
header: []hpack.HeaderField{
|
|
||||||
pair("content-length", ""),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
want := 400
|
|
||||||
if got := res.status; got != want {
|
|
||||||
t.Errorf("status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1GenerateVia tests that server generates Via header field to and
|
|
||||||
// from backend server.
|
|
||||||
func TestS3H1GenerateVia(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want {
|
|
||||||
t.Errorf("Via: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1GenerateVia",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want {
|
|
||||||
t.Errorf("Via: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1AppendVia tests that server adds value to existing Via
|
|
||||||
// header field to and from backend server.
|
|
||||||
func TestS3H1AppendVia(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if got, want := r.Header.Get("Via"), "foo, 1.1 nghttpx"; got != want {
|
|
||||||
t.Errorf("Via: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
w.Header().Add("Via", "bar")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1AppendVia",
|
|
||||||
header: []hpack.HeaderField{
|
|
||||||
pair("via", "foo"),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want {
|
|
||||||
t.Errorf("Via: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1NoVia tests that server does not add value to existing Via
|
|
||||||
// header field to and from backend server.
|
|
||||||
func TestS3H1NoVia(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--no-via"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if got, want := r.Header.Get("Via"), "foo"; got != want {
|
|
||||||
t.Errorf("Via: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
w.Header().Add("Via", "bar")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1NoVia",
|
|
||||||
header: []hpack.HeaderField{
|
|
||||||
pair("via", "foo"),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.header.Get("Via"), "bar"; got != want {
|
|
||||||
t.Errorf("Via: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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", "--request-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-request-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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1InvalidMethod tests that server rejects invalid method with
|
|
||||||
// 501.
|
|
||||||
func TestS3H1InvalidMethod(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Errorf("server should not forward this request")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1InvalidMethod",
|
|
||||||
method: "get",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.status, 501; got != want {
|
|
||||||
t.Errorf("status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1BadHost tests that server rejects request including bad
|
|
||||||
// character in :host header field.
|
|
||||||
func TestS3H1BadHost(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Errorf("server should not forward this request")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1BadHost",
|
|
||||||
authority: `foo\bar`,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.status, 400; got != want {
|
|
||||||
t.Errorf("status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1BadScheme tests that server rejects request including bad
|
|
||||||
// character in :scheme header field.
|
|
||||||
func TestS3H1BadScheme(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Errorf("server should not forward this request")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1BadScheme",
|
|
||||||
scheme: `http*`,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.status, 400; got != want {
|
|
||||||
t.Errorf("status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1ReqPhaseSetHeader tests mruby request phase hook
|
|
||||||
// modifies request header fields.
|
|
||||||
func TestS3H1ReqPhaseSetHeader(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--mruby-file=" + testDir + "/req-set-header.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if got, want := r.Header.Get("User-Agent"), "mruby"; got != want {
|
|
||||||
t.Errorf("User-Agent = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1ReqPhaseSetHeader",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := res.status, 200; got != want {
|
|
||||||
t.Errorf("status = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1ReqPhaseReturn tests mruby request phase hook returns
|
|
||||||
// custom response.
|
|
||||||
func TestS3H1ReqPhaseReturn(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Fatalf("request should not be forwarded")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1ReqPhaseReturn",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := res.status, 404; got != want {
|
|
||||||
t.Errorf("status = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
hdtests := []struct {
|
|
||||||
k, v string
|
|
||||||
}{
|
|
||||||
{"content-length", "20"},
|
|
||||||
{"from", "mruby"},
|
|
||||||
}
|
|
||||||
for _, tt := range hdtests {
|
|
||||||
if got, want := res.header.Get(tt.k), tt.v; got != want {
|
|
||||||
t.Errorf("%v = %v; want %v", tt.k, got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := string(res.body), "Hello World from req"; got != want {
|
|
||||||
t.Errorf("body = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1RespPhaseSetHeader tests mruby response phase hook modifies
|
|
||||||
// response header fields.
|
|
||||||
func TestS3H1RespPhaseSetHeader(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--mruby-file=" + testDir + "/resp-set-header.rb"}, t, noopHandler)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1RespPhaseSetHeader",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := res.status, 200; got != want {
|
|
||||||
t.Errorf("status = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := res.header.Get("alpha"), "bravo"; got != want {
|
|
||||||
t.Errorf("alpha = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H1RespPhaseReturn tests mruby response phase hook returns
|
|
||||||
// custom response.
|
|
||||||
func TestS3H1RespPhaseReturn(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H1RespPhaseReturn",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := res.status, 404; got != want {
|
|
||||||
t.Errorf("status = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
hdtests := []struct {
|
|
||||||
k, v string
|
|
||||||
}{
|
|
||||||
{"content-length", "21"},
|
|
||||||
{"from", "mruby"},
|
|
||||||
}
|
|
||||||
for _, tt := range hdtests {
|
|
||||||
if got, want := res.header.Get(tt.k), tt.v; got != want {
|
|
||||||
t.Errorf("%v = %v; want %v", tt.k, got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := string(res.body), "Hello World from resp"; got != want {
|
|
||||||
t.Errorf("body = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// // TestS3H2ConnectFailure tests that server handles the situation that
|
|
||||||
// // connection attempt to HTTP/2 backend failed.
|
|
||||||
// func TestS3H2ConnectFailure(t *testing.T) {
|
|
||||||
// st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--http2-bridge"}, t, noopHandler)
|
|
||||||
// defer st.Close()
|
|
||||||
|
|
||||||
// // simulate backend connect attempt failure
|
|
||||||
// st.ts.Close()
|
|
||||||
|
|
||||||
// res, err := st.spdy(requestParam{
|
|
||||||
// name: "TestS3H2ConnectFailure",
|
|
||||||
// })
|
|
||||||
// if err != nil {
|
|
||||||
// t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
// }
|
|
||||||
// want := 503
|
|
||||||
// if got := res.status; got != want {
|
|
||||||
// t.Errorf("status: %v; want %v", got, want)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TestS3H2ReqPhaseReturn tests mruby request phase hook returns
|
|
||||||
// custom response.
|
|
||||||
func TestS3H2ReqPhaseReturn(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--http2-bridge", "--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Fatalf("request should not be forwarded")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H2ReqPhaseReturn",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := res.status, 404; got != want {
|
|
||||||
t.Errorf("status = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
hdtests := []struct {
|
|
||||||
k, v string
|
|
||||||
}{
|
|
||||||
{"content-length", "20"},
|
|
||||||
{"from", "mruby"},
|
|
||||||
}
|
|
||||||
for _, tt := range hdtests {
|
|
||||||
if got, want := res.header.Get(tt.k), tt.v; got != want {
|
|
||||||
t.Errorf("%v = %v; want %v", tt.k, got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := string(res.body), "Hello World from req"; got != want {
|
|
||||||
t.Errorf("body = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3H2RespPhaseReturn tests mruby response phase hook returns
|
|
||||||
// custom response.
|
|
||||||
func TestS3H2RespPhaseReturn(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--http2-bridge", "--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3H2RespPhaseReturn",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := res.status, 404; got != want {
|
|
||||||
t.Errorf("status = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
hdtests := []struct {
|
|
||||||
k, v string
|
|
||||||
}{
|
|
||||||
{"content-length", "21"},
|
|
||||||
{"from", "mruby"},
|
|
||||||
}
|
|
||||||
for _, tt := range hdtests {
|
|
||||||
if got, want := res.header.Get(tt.k), tt.v; got != want {
|
|
||||||
t.Errorf("%v = %v; want %v", tt.k, got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := string(res.body), "Hello World from resp"; got != want {
|
|
||||||
t.Errorf("body = %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3APIBackendconfig exercise backendconfig API endpoint routine
|
|
||||||
// for successful case.
|
|
||||||
func TestS3APIBackendconfig(t *testing.T) {
|
|
||||||
st := newServerTesterTLSConnectPort([]string{"--npn-list=spdy/3.1", "-f127.0.0.1,3010;api"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Fatalf("request should not be forwarded")
|
|
||||||
}, 3010)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3APIBackendconfig",
|
|
||||||
path: "/api/v1beta1/backendconfig",
|
|
||||||
method: "PUT",
|
|
||||||
body: []byte(`# comment
|
|
||||||
backend=127.0.0.1,3011
|
|
||||||
|
|
||||||
`),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.status, 200; got != want {
|
|
||||||
t.Errorf("res.status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
var apiResp APIResponse
|
|
||||||
err = json.Unmarshal(res.body, &apiResp)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error unmarshaling API response: %v", err)
|
|
||||||
}
|
|
||||||
if got, want := apiResp.Status, "Success"; got != want {
|
|
||||||
t.Errorf("apiResp.Status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
if got, want := apiResp.Code, 200; got != want {
|
|
||||||
t.Errorf("apiResp.Status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3APIBackendconfigQuery exercise backendconfig API endpoint
|
|
||||||
// routine with query.
|
|
||||||
func TestS3APIBackendconfigQuery(t *testing.T) {
|
|
||||||
st := newServerTesterTLSConnectPort([]string{"--npn-list=spdy/3.1", "-f127.0.0.1,3010;api"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Fatalf("request should not be forwarded")
|
|
||||||
}, 3010)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3APIBackendconfigQuery",
|
|
||||||
path: "/api/v1beta1/backendconfig?foo=bar",
|
|
||||||
method: "PUT",
|
|
||||||
body: []byte(`# comment
|
|
||||||
backend=127.0.0.1,3011
|
|
||||||
|
|
||||||
`),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.status, 200; got != want {
|
|
||||||
t.Errorf("res.status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
var apiResp APIResponse
|
|
||||||
err = json.Unmarshal(res.body, &apiResp)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error unmarshaling API response: %v", err)
|
|
||||||
}
|
|
||||||
if got, want := apiResp.Status, "Success"; got != want {
|
|
||||||
t.Errorf("apiResp.Status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
if got, want := apiResp.Code, 200; got != want {
|
|
||||||
t.Errorf("apiResp.Status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3APIBackendconfigBadMethod exercise backendconfig API endpoint
|
|
||||||
// routine with bad method.
|
|
||||||
func TestS3APIBackendconfigBadMethod(t *testing.T) {
|
|
||||||
st := newServerTesterTLSConnectPort([]string{"--npn-list=spdy/3.1", "-f127.0.0.1,3010;api"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Fatalf("request should not be forwarded")
|
|
||||||
}, 3010)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3APIBackendconfigBadMethod",
|
|
||||||
path: "/api/v1beta1/backendconfig",
|
|
||||||
method: "GET",
|
|
||||||
body: []byte(`# comment
|
|
||||||
backend=127.0.0.1,3011
|
|
||||||
|
|
||||||
`),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.status, 405; got != want {
|
|
||||||
t.Errorf("res.status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
var apiResp APIResponse
|
|
||||||
err = json.Unmarshal(res.body, &apiResp)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error unmarshaling API response: %v", err)
|
|
||||||
}
|
|
||||||
if got, want := apiResp.Status, "Failure"; got != want {
|
|
||||||
t.Errorf("apiResp.Status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
if got, want := apiResp.Code, 405; got != want {
|
|
||||||
t.Errorf("apiResp.Status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3APINotFound exercise backendconfig API endpoint routine when
|
|
||||||
// API endpoint is not found.
|
|
||||||
func TestS3APINotFound(t *testing.T) {
|
|
||||||
st := newServerTesterTLSConnectPort([]string{"--npn-list=spdy/3.1", "-f127.0.0.1,3010;api"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Fatalf("request should not be forwarded")
|
|
||||||
}, 3010)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3APINotFound",
|
|
||||||
path: "/api/notfound",
|
|
||||||
method: "GET",
|
|
||||||
body: []byte(`# comment
|
|
||||||
backend=127.0.0.1,3011
|
|
||||||
|
|
||||||
`),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.status, 404; got != want {
|
|
||||||
t.Errorf("res.status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
var apiResp APIResponse
|
|
||||||
err = json.Unmarshal(res.body, &apiResp)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error unmarshaling API response: %v", err)
|
|
||||||
}
|
|
||||||
if got, want := apiResp.Status, "Failure"; got != want {
|
|
||||||
t.Errorf("apiResp.Status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
if got, want := apiResp.Code, 404; got != want {
|
|
||||||
t.Errorf("apiResp.Status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3Healthmon tests health monitor endpoint.
|
|
||||||
func TestS3Healthmon(t *testing.T) {
|
|
||||||
st := newServerTesterTLSConnectPort([]string{"--npn-list=spdy/3.1", "-f127.0.0.1,3011;healthmon"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Fatalf("request should not be forwarded")
|
|
||||||
}, 3011)
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3Healthmon",
|
|
||||||
path: "/alpha/bravo",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.status, 200; got != want {
|
|
||||||
t.Errorf("res.status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestS3ResponseBeforeRequestEnd tests the situation where response
|
|
||||||
// ends before request body finishes.
|
|
||||||
func TestS3ResponseBeforeRequestEnd(t *testing.T) {
|
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Fatal("request should not be forwarded")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
|
||||||
name: "TestS3ResponseBeforeRequestEnd",
|
|
||||||
noEndStream: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
|
||||||
}
|
|
||||||
if got, want := res.status, 404; got != want {
|
|
||||||
t.Errorf("res.status: %v; want %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -101,7 +101,7 @@ func newServerTesterInternal(src_args []string, t *testing.T, handler http.Handl
|
|||||||
|
|
||||||
args := []string{}
|
args := []string{}
|
||||||
|
|
||||||
var backendTLS, dns, externalDNS, acceptProxyProtocol, redirectIfNotTLS bool
|
var backendTLS, dns, externalDNS, acceptProxyProtocol, redirectIfNotTLS, affinityCookie, alpnH1 bool
|
||||||
|
|
||||||
for _, k := range src_args {
|
for _, k := range src_args {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -116,6 +116,10 @@ func newServerTesterInternal(src_args []string, t *testing.T, handler http.Handl
|
|||||||
acceptProxyProtocol = true
|
acceptProxyProtocol = true
|
||||||
case "--redirect-if-not-tls":
|
case "--redirect-if-not-tls":
|
||||||
redirectIfNotTLS = true
|
redirectIfNotTLS = true
|
||||||
|
case "--affinity-cookie":
|
||||||
|
affinityCookie = true
|
||||||
|
case "--alpn-h1":
|
||||||
|
alpnH1 = true
|
||||||
default:
|
default:
|
||||||
args = append(args, k)
|
args = append(args, k)
|
||||||
}
|
}
|
||||||
@@ -153,8 +157,8 @@ func newServerTesterInternal(src_args []string, t *testing.T, handler http.Handl
|
|||||||
if sep == -1 {
|
if sep == -1 {
|
||||||
t.Fatalf("backendURL.Host %v does not contain separator ':'", backendURL.Host)
|
t.Fatalf("backendURL.Host %v does not contain separator ':'", backendURL.Host)
|
||||||
}
|
}
|
||||||
// We use awesome service xip.io.
|
// We use awesome service nip.io.
|
||||||
b += fmt.Sprintf("%v.xip.io,%v;", backendURL.Host[:sep], backendURL.Host[sep+1:])
|
b += fmt.Sprintf("%v.nip.io,%v;", backendURL.Host[:sep], backendURL.Host[sep+1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
if backendTLS {
|
if backendTLS {
|
||||||
@@ -168,6 +172,10 @@ func newServerTesterInternal(src_args []string, t *testing.T, handler http.Handl
|
|||||||
b += ";redirect-if-not-tls"
|
b += ";redirect-if-not-tls"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if affinityCookie {
|
||||||
|
b += ";affinity=cookie;affinity-cookie-name=affinity;affinity-cookie-path=/foo/bar"
|
||||||
|
}
|
||||||
|
|
||||||
noTLS := ";no-tls"
|
noTLS := ";no-tls"
|
||||||
if frontendTLS {
|
if frontendTLS {
|
||||||
noTLS = ""
|
noTLS = ""
|
||||||
@@ -218,7 +226,11 @@ func newServerTesterInternal(src_args []string, t *testing.T, handler http.Handl
|
|||||||
tlsConfig = clientConfig
|
tlsConfig = clientConfig
|
||||||
}
|
}
|
||||||
tlsConfig.InsecureSkipVerify = true
|
tlsConfig.InsecureSkipVerify = true
|
||||||
tlsConfig.NextProtos = []string{"h2", "spdy/3.1"}
|
if alpnH1 {
|
||||||
|
tlsConfig.NextProtos = []string{"http/1.1"}
|
||||||
|
} else {
|
||||||
|
tlsConfig.NextProtos = []string{"h2", "spdy/3.1"}
|
||||||
|
}
|
||||||
conn, err = tls.Dial("tcp", authority, tlsConfig)
|
conn, err = tls.Dial("tcp", authority, tlsConfig)
|
||||||
} else {
|
} else {
|
||||||
conn, err = net.Dial("tcp", authority)
|
conn, err = net.Dial("tcp", authority)
|
||||||
@@ -266,7 +278,7 @@ func (st *serverTester) Close() {
|
|||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
st.cmd.Wait()
|
st.cmd.Wait()
|
||||||
done <- struct{}{}
|
close(done)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
st.cmd.Process.Signal(syscall.SIGQUIT)
|
st.cmd.Process.Signal(syscall.SIGQUIT)
|
||||||
@@ -769,7 +781,7 @@ type serverResponse struct {
|
|||||||
connErr bool // true if HTTP/2 connection error
|
connErr bool // true if HTTP/2 connection error
|
||||||
spdyGoAwayErrCode spdy.GoAwayStatus // status code received in SPDY RST_STREAM
|
spdyGoAwayErrCode spdy.GoAwayStatus // status code received in SPDY RST_STREAM
|
||||||
spdyRstErrCode spdy.RstStreamStatus // status code received in SPDY GOAWAY
|
spdyRstErrCode spdy.RstStreamStatus // status code received in SPDY GOAWAY
|
||||||
connClose bool // Conection: close is included in response header in HTTP/1 test
|
connClose bool // Connection: close is included in response header in HTTP/1 test
|
||||||
reqHeader http.Header // http request header, currently only sotres pushed request header
|
reqHeader http.Header // http request header, currently only sotres pushed request header
|
||||||
pushResponse []*serverResponse // pushed response
|
pushResponse []*serverResponse // pushed response
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ set_target_properties(nghttp2 PROPERTIES
|
|||||||
VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION}
|
VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION}
|
||||||
C_VISIBILITY_PRESET hidden
|
C_VISIBILITY_PRESET hidden
|
||||||
)
|
)
|
||||||
|
target_include_directories(nghttp2 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/includes"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
||||||
|
)
|
||||||
|
|
||||||
if(HAVE_CUNIT)
|
if(HAVE_CUNIT)
|
||||||
# Static library (for unittests because of symbol visibility)
|
# Static library (for unittests because of symbol visibility)
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ AR := lib
|
|||||||
#LD := xilink
|
#LD := xilink
|
||||||
#AR := xilib
|
#AR := xilib
|
||||||
RC := rc
|
RC := rc
|
||||||
CFLAGS := -I./includes -Dssize_t=long -D_U_=""
|
CFLAGS := -I./includes -Dssize_t=long
|
||||||
|
|
||||||
CFLAGS_R := -nologo -MD -W3 -Z7 -DBUILDING_NGHTTP2
|
CFLAGS_R := -nologo -MD -W3 -Z7 -DBUILDING_NGHTTP2
|
||||||
CFLAGS_D := -nologo -MDd -W3 -Z7 -DBUILDING_NGHTTP2 \
|
CFLAGS_D := -nologo -MDd -W3 -Z7 -DBUILDING_NGHTTP2 \
|
||||||
|
|||||||
@@ -387,6 +387,11 @@ typedef enum {
|
|||||||
* Indicates that a processing was canceled.
|
* Indicates that a processing was canceled.
|
||||||
*/
|
*/
|
||||||
NGHTTP2_ERR_CANCEL = -535,
|
NGHTTP2_ERR_CANCEL = -535,
|
||||||
|
/**
|
||||||
|
* When a local endpoint expects to receive SETTINGS frame, it
|
||||||
|
* receives an other type of frame.
|
||||||
|
*/
|
||||||
|
NGHTTP2_ERR_SETTINGS_EXPECTED = -536,
|
||||||
/**
|
/**
|
||||||
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
|
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
|
||||||
* under unexpected condition and processing was terminated (e.g.,
|
* under unexpected condition and processing was terminated (e.g.,
|
||||||
@@ -469,6 +474,15 @@ NGHTTP2_EXTERN void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf);
|
|||||||
*/
|
*/
|
||||||
NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf);
|
NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Returns nonzero if the underlying buffer is statically allocated,
|
||||||
|
* and 0 otherwise. This can be useful for language bindings that wish
|
||||||
|
* to avoid creating duplicate strings for these buffers.
|
||||||
|
*/
|
||||||
|
NGHTTP2_EXTERN int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @enum
|
* @enum
|
||||||
*
|
*
|
||||||
@@ -1741,11 +1755,12 @@ typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session,
|
|||||||
* The parameter and behaviour are similar to
|
* The parameter and behaviour are similar to
|
||||||
* :type:`nghttp2_on_header_callback`. The difference is that this
|
* :type:`nghttp2_on_header_callback`. The difference is that this
|
||||||
* callback is only invoked when a invalid header name/value pair is
|
* callback is only invoked when a invalid header name/value pair is
|
||||||
* received which is silently ignored if this callback is not set.
|
* received which is treated as stream error if this callback is not
|
||||||
* Only invalid regular header field are passed to this callback. In
|
* set. Only invalid regular header field are passed to this
|
||||||
* other words, invalid pseudo header field is not passed to this
|
* callback. In other words, invalid pseudo header field is not
|
||||||
* callback. Also header fields which includes upper cased latter are
|
* passed to this callback. Also header fields which includes upper
|
||||||
* also treated as error without passing them to this callback.
|
* cased latter are also treated as error without passing them to this
|
||||||
|
* callback.
|
||||||
*
|
*
|
||||||
* This callback is only considered if HTTP messaging validation is
|
* This callback is only considered if HTTP messaging validation is
|
||||||
* turned on (which is on by default, see
|
* turned on (which is on by default, see
|
||||||
@@ -1754,10 +1769,13 @@ typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session,
|
|||||||
* With this callback, application inspects the incoming invalid
|
* With this callback, application inspects the incoming invalid
|
||||||
* field, and it also can reset stream from this callback by returning
|
* field, and it also can reset stream from this callback by returning
|
||||||
* :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the
|
* :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the
|
||||||
* error code is :enum:`NGHTTP2_INTERNAL_ERROR`. To change the error
|
* error code is :enum:`NGHTTP2_PROTOCOL_ERROR`. To change the error
|
||||||
* code, call `nghttp2_submit_rst_stream()` with the error code of
|
* code, call `nghttp2_submit_rst_stream()` with the error code of
|
||||||
* choice in addition to returning
|
* choice in addition to returning
|
||||||
* :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
|
* :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
|
||||||
|
*
|
||||||
|
* If 0 is returned, the header field is ignored, and the stream is
|
||||||
|
* not reset.
|
||||||
*/
|
*/
|
||||||
typedef int (*nghttp2_on_invalid_header_callback)(
|
typedef int (*nghttp2_on_invalid_header_callback)(
|
||||||
nghttp2_session *session, const nghttp2_frame *frame, const uint8_t *name,
|
nghttp2_session *session, const nghttp2_frame *frame, const uint8_t *name,
|
||||||
@@ -1974,6 +1992,9 @@ typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
|
|||||||
* of length |len|. |len| does not include the sentinel NULL
|
* of length |len|. |len| does not include the sentinel NULL
|
||||||
* character.
|
* character.
|
||||||
*
|
*
|
||||||
|
* This function is deprecated. The new application should use
|
||||||
|
* :type:`nghttp2_error_callback2`.
|
||||||
|
*
|
||||||
* The format of error message may change between nghttp2 library
|
* The format of error message may change between nghttp2 library
|
||||||
* versions. The application should not depend on the particular
|
* versions. The application should not depend on the particular
|
||||||
* format.
|
* format.
|
||||||
@@ -1990,6 +2011,33 @@ typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
|
|||||||
typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg,
|
typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg,
|
||||||
size_t len, void *user_data);
|
size_t len, void *user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @functypedef
|
||||||
|
*
|
||||||
|
* Callback function invoked when library provides the error code, and
|
||||||
|
* message. This callback is solely for debugging purpose.
|
||||||
|
* |lib_error_code| is one of error code defined in
|
||||||
|
* :enum:`nghttp2_error`. The |msg| is typically NULL-terminated
|
||||||
|
* string of length |len|, and intended for human consumption. |len|
|
||||||
|
* does not include the sentinel NULL character.
|
||||||
|
*
|
||||||
|
* The format of error message may change between nghttp2 library
|
||||||
|
* versions. The application should not depend on the particular
|
||||||
|
* format.
|
||||||
|
*
|
||||||
|
* Normally, application should return 0 from this callback. If fatal
|
||||||
|
* error occurred while doing something in this callback, application
|
||||||
|
* should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
|
||||||
|
* library will return immediately with return value
|
||||||
|
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value
|
||||||
|
* is returned from this callback, they are treated as
|
||||||
|
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not
|
||||||
|
* rely on this details.
|
||||||
|
*/
|
||||||
|
typedef int (*nghttp2_error_callback2)(nghttp2_session *session,
|
||||||
|
int lib_error_code, const char *msg,
|
||||||
|
size_t len, void *user_data);
|
||||||
|
|
||||||
struct nghttp2_session_callbacks;
|
struct nghttp2_session_callbacks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2254,10 +2302,30 @@ nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
|
|||||||
*
|
*
|
||||||
* Sets callback function invoked when library tells error message to
|
* Sets callback function invoked when library tells error message to
|
||||||
* the application.
|
* the application.
|
||||||
|
*
|
||||||
|
* This function is deprecated. The new application should use
|
||||||
|
* `nghttp2_session_callbacks_set_error_callback2()`.
|
||||||
|
*
|
||||||
|
* If both :type:`nghttp2_error_callback` and
|
||||||
|
* :type:`nghttp2_error_callback2` are set, the latter takes
|
||||||
|
* precedence.
|
||||||
*/
|
*/
|
||||||
NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback(
|
NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback(
|
||||||
nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback);
|
nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Sets callback function invoked when library tells error code, and
|
||||||
|
* message to the application.
|
||||||
|
*
|
||||||
|
* If both :type:`nghttp2_error_callback` and
|
||||||
|
* :type:`nghttp2_error_callback2` are set, the latter takes
|
||||||
|
* precedence.
|
||||||
|
*/
|
||||||
|
NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback2(
|
||||||
|
nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @functypedef
|
* @functypedef
|
||||||
*
|
*
|
||||||
@@ -2448,7 +2516,10 @@ nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val);
|
|||||||
* <https://tools.ietf.org/html/rfc7540#section-8>`_. See
|
* <https://tools.ietf.org/html/rfc7540#section-8>`_. See
|
||||||
* :ref:`http-messaging` section for details. For those applications
|
* :ref:`http-messaging` section for details. For those applications
|
||||||
* who use nghttp2 library as non-HTTP use, give nonzero to |val| to
|
* who use nghttp2 library as non-HTTP use, give nonzero to |val| to
|
||||||
* disable this enforcement.
|
* disable this enforcement. Please note that disabling this feature
|
||||||
|
* does not change the fundamental client and server model of HTTP.
|
||||||
|
* That is, even if the validation is disabled, only client can send
|
||||||
|
* requests.
|
||||||
*/
|
*/
|
||||||
NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option,
|
NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option,
|
||||||
int val);
|
int val);
|
||||||
@@ -3010,6 +3081,16 @@ NGHTTP2_EXTERN int
|
|||||||
nghttp2_session_set_stream_user_data(nghttp2_session *session,
|
nghttp2_session_set_stream_user_data(nghttp2_session *session,
|
||||||
int32_t stream_id, void *stream_user_data);
|
int32_t stream_id, void *stream_user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Sets |user_data| to |session|, overwriting the existing user data
|
||||||
|
* specified in `nghttp2_session_client_new()`, or
|
||||||
|
* `nghttp2_session_server_new()`.
|
||||||
|
*/
|
||||||
|
NGHTTP2_EXTERN void nghttp2_session_set_user_data(nghttp2_session *session,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
@@ -3802,9 +3883,8 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
|
|||||||
* Submits trailer fields HEADERS against the stream |stream_id|.
|
* Submits trailer fields HEADERS against the stream |stream_id|.
|
||||||
*
|
*
|
||||||
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
|
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
|
||||||
* |nvlen| elements. The application is responsible not to include
|
* |nvlen| elements. The application must not include pseudo-header
|
||||||
* pseudo-header fields (header field whose name starts with ":") in
|
* fields (headers whose names starts with ":") in |nva|.
|
||||||
* |nva|.
|
|
||||||
*
|
*
|
||||||
* This function creates copies of all name/value pairs in |nva|. It
|
* This function creates copies of all name/value pairs in |nva|. It
|
||||||
* also lower-cases all names in |nva|. The order of elements in
|
* also lower-cases all names in |nva|. The order of elements in
|
||||||
@@ -4687,8 +4767,8 @@ nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
|
|||||||
*
|
*
|
||||||
* After this function returns, it is safe to delete the |nva|.
|
* After this function returns, it is safe to delete the |nva|.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
* This function returns the number of bytes written to |buf| if it
|
||||||
* negative error codes:
|
* succeeds, or one of the following negative error codes:
|
||||||
*
|
*
|
||||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
@@ -4719,8 +4799,8 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
|
|||||||
*
|
*
|
||||||
* After this function returns, it is safe to delete the |nva|.
|
* After this function returns, it is safe to delete the |nva|.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
* This function returns the number of bytes written to |vec| if it
|
||||||
* negative error codes:
|
* succeeds, or one of the following negative error codes:
|
||||||
*
|
*
|
||||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ int nghttp2_bufs_advance(nghttp2_bufs *bufs);
|
|||||||
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs);
|
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns nonzero if bufs->cur->next is not emtpy.
|
* Returns nonzero if bufs->cur->next is not empty.
|
||||||
*/
|
*/
|
||||||
int nghttp2_bufs_next_present(nghttp2_bufs *bufs);
|
int nghttp2_bufs_next_present(nghttp2_bufs *bufs);
|
||||||
|
|
||||||
|
|||||||
@@ -168,3 +168,8 @@ void nghttp2_session_callbacks_set_error_callback(
|
|||||||
nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback) {
|
nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback) {
|
||||||
cbs->error_callback = error_callback;
|
cbs->error_callback = error_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nghttp2_session_callbacks_set_error_callback2(
|
||||||
|
nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2) {
|
||||||
|
cbs->error_callback2 = error_callback2;
|
||||||
|
}
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ struct nghttp2_session_callbacks {
|
|||||||
nghttp2_unpack_extension_callback unpack_extension_callback;
|
nghttp2_unpack_extension_callback unpack_extension_callback;
|
||||||
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
|
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
|
||||||
nghttp2_error_callback error_callback;
|
nghttp2_error_callback error_callback;
|
||||||
|
nghttp2_error_callback2 error_callback2;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* NGHTTP2_CALLBACKS_H */
|
#endif /* NGHTTP2_CALLBACKS_H */
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ void nghttp2_set_debug_vprintf_callback(
|
|||||||
#else /* !DEBUGBUILD */
|
#else /* !DEBUGBUILD */
|
||||||
|
|
||||||
void nghttp2_set_debug_vprintf_callback(
|
void nghttp2_set_debug_vprintf_callback(
|
||||||
nghttp2_debug_vprintf_callback debug_vprintf_callback _U_) {}
|
nghttp2_debug_vprintf_callback debug_vprintf_callback) {
|
||||||
|
(void)debug_vprintf_callback;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !DEBUGBUILD */
|
#endif /* !DEBUGBUILD */
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
|
|||||||
frame->pri_spec = *pri_spec;
|
frame->pri_spec = *pri_spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_priority_free(nghttp2_priority *frame _U_) {}
|
void nghttp2_frame_priority_free(nghttp2_priority *frame) { (void)frame; }
|
||||||
|
|
||||||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
|
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
|
||||||
uint32_t error_code) {
|
uint32_t error_code) {
|
||||||
@@ -96,7 +96,7 @@ void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
|
|||||||
frame->error_code = error_code;
|
frame->error_code = error_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame _U_) {}
|
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame) { (void)frame; }
|
||||||
|
|
||||||
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
|
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
|
||||||
nghttp2_settings_entry *iv, size_t niv) {
|
nghttp2_settings_entry *iv, size_t niv) {
|
||||||
@@ -137,7 +137,7 @@ void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_ping_free(nghttp2_ping *frame _U_) {}
|
void nghttp2_frame_ping_free(nghttp2_ping *frame) { (void)frame; }
|
||||||
|
|
||||||
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
|
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
|
||||||
uint32_t error_code, uint8_t *opaque_data,
|
uint32_t error_code, uint8_t *opaque_data,
|
||||||
@@ -163,7 +163,9 @@ void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
|
|||||||
frame->reserved = 0;
|
frame->reserved = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame _U_) {}
|
void nghttp2_frame_window_update_free(nghttp2_window_update *frame) {
|
||||||
|
(void)frame;
|
||||||
|
}
|
||||||
|
|
||||||
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen) {
|
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen) {
|
||||||
/* We have iframe->padlen == 0, but iframe->frame.hd.flags may have
|
/* We have iframe->padlen == 0, but iframe->frame.hd.flags may have
|
||||||
@@ -183,7 +185,7 @@ void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
|
|||||||
frame->padlen = 0;
|
frame->padlen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_data_free(nghttp2_data *frame _U_) {}
|
void nghttp2_frame_data_free(nghttp2_data *frame) { (void)frame; }
|
||||||
|
|
||||||
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
|
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
|
||||||
uint8_t flags, int32_t stream_id,
|
uint8_t flags, int32_t stream_id,
|
||||||
@@ -192,7 +194,7 @@ void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
|
|||||||
frame->payload = payload;
|
frame->payload = payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_extension_free(nghttp2_extension *frame _U_) {}
|
void nghttp2_frame_extension_free(nghttp2_extension *frame) { (void)frame; }
|
||||||
|
|
||||||
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||||
uint8_t *origin, size_t origin_len,
|
uint8_t *origin, size_t origin_len,
|
||||||
@@ -346,9 +348,7 @@ void nghttp2_frame_pack_priority_spec(uint8_t *buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||||
uint8_t flags _U_,
|
const uint8_t *payload) {
|
||||||
const uint8_t *payload,
|
|
||||||
size_t payloadlen _U_) {
|
|
||||||
int32_t dep_stream_id;
|
int32_t dep_stream_id;
|
||||||
uint8_t exclusive;
|
uint8_t exclusive;
|
||||||
int32_t weight;
|
int32_t weight;
|
||||||
@@ -361,11 +361,9 @@ void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload) {
|
||||||
size_t payloadlen) {
|
|
||||||
if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags,
|
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
|
||||||
payload, payloadlen);
|
|
||||||
} else {
|
} else {
|
||||||
nghttp2_priority_spec_default_init(&frame->pri_spec);
|
nghttp2_priority_spec_default_init(&frame->pri_spec);
|
||||||
}
|
}
|
||||||
@@ -397,10 +395,8 @@ int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload) {
|
||||||
size_t payloadlen) {
|
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
|
||||||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags, payload,
|
|
||||||
payloadlen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||||
@@ -424,8 +420,7 @@ int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
|
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload) {
|
||||||
size_t payloadlen _U_) {
|
|
||||||
frame->error_code = nghttp2_get_uint32(payload);
|
frame->error_code = nghttp2_get_uint32(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,8 +535,7 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload) {
|
||||||
size_t payloadlen _U_) {
|
|
||||||
frame->promised_stream_id =
|
frame->promised_stream_id =
|
||||||
nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
|
nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
|
||||||
frame->nva = NULL;
|
frame->nva = NULL;
|
||||||
@@ -569,8 +563,7 @@ int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
|
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload) {
|
||||||
size_t payloadlen _U_) {
|
|
||||||
memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
|
memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,7 +600,6 @@ int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame) {
|
|||||||
|
|
||||||
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
|
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload,
|
||||||
size_t payloadlen _U_,
|
|
||||||
uint8_t *var_gift_payload,
|
uint8_t *var_gift_payload,
|
||||||
size_t var_gift_payloadlen) {
|
size_t var_gift_payloadlen) {
|
||||||
frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
|
frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
|
||||||
@@ -643,8 +635,8 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
|||||||
memcpy(var_gift_payload, payload + 8, var_gift_payloadlen);
|
memcpy(var_gift_payload, payload + 8, var_gift_payloadlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_frame_unpack_goaway_payload(frame, payload, payloadlen,
|
nghttp2_frame_unpack_goaway_payload(frame, payload, var_gift_payload,
|
||||||
var_gift_payload, var_gift_payloadlen);
|
var_gift_payloadlen);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -670,8 +662,7 @@ int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload) {
|
||||||
size_t payloadlen _U_) {
|
|
||||||
frame->window_size_increment =
|
frame->window_size_increment =
|
||||||
nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
|
nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
|
||||||
}
|
}
|
||||||
@@ -681,6 +672,9 @@ int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
|
|||||||
nghttp2_buf *buf;
|
nghttp2_buf *buf;
|
||||||
nghttp2_ext_altsvc *altsvc;
|
nghttp2_ext_altsvc *altsvc;
|
||||||
|
|
||||||
|
/* This is required with --disable-assert. */
|
||||||
|
(void)rv;
|
||||||
|
|
||||||
altsvc = frame->payload;
|
altsvc = frame->payload;
|
||||||
|
|
||||||
buf = &bufs->head->buf;
|
buf = &bufs->head->buf;
|
||||||
|
|||||||
@@ -70,7 +70,9 @@
|
|||||||
#define NGHTTP2_MAX_PADLEN 256
|
#define NGHTTP2_MAX_PADLEN 256
|
||||||
|
|
||||||
/* Union of extension frame payload */
|
/* Union of extension frame payload */
|
||||||
typedef union { nghttp2_ext_altsvc altsvc; } nghttp2_ext_frame_payload;
|
typedef union {
|
||||||
|
nghttp2_ext_altsvc altsvc;
|
||||||
|
} nghttp2_ext_frame_payload;
|
||||||
|
|
||||||
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
||||||
|
|
||||||
@@ -104,8 +106,7 @@ void nghttp2_frame_pack_priority_spec(uint8_t *buf,
|
|||||||
* assumes the |payload| contains whole priority specification.
|
* assumes the |payload| contains whole priority specification.
|
||||||
*/
|
*/
|
||||||
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||||
uint8_t flags, const uint8_t *payload,
|
const uint8_t *payload);
|
||||||
size_t payloadlen);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the offset from the HEADERS frame payload where the
|
* Returns the offset from the HEADERS frame payload where the
|
||||||
@@ -144,8 +145,7 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
|
|||||||
* This function always succeeds and returns 0.
|
* This function always succeeds and returns 0.
|
||||||
*/
|
*/
|
||||||
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload);
|
||||||
size_t payloadlen);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Packs PRIORITY frame |frame| in wire format and store it in
|
* Packs PRIORITY frame |frame| in wire format and store it in
|
||||||
@@ -162,8 +162,7 @@ int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
|
|||||||
* Unpacks PRIORITY wire format into |frame|.
|
* Unpacks PRIORITY wire format into |frame|.
|
||||||
*/
|
*/
|
||||||
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload);
|
||||||
size_t payloadlen);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Packs RST_STREAM frame |frame| in wire frame format and store it in
|
* Packs RST_STREAM frame |frame| in wire frame format and store it in
|
||||||
@@ -181,8 +180,7 @@ int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
|||||||
* Unpacks RST_STREAM frame byte sequence into |frame|.
|
* Unpacks RST_STREAM frame byte sequence into |frame|.
|
||||||
*/
|
*/
|
||||||
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
|
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload);
|
||||||
size_t payloadlen);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Packs SETTINGS frame |frame| in wire format and store it in
|
* Packs SETTINGS frame |frame| in wire format and store it in
|
||||||
@@ -273,8 +271,7 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
|
|||||||
* TODO END_HEADERS flag is not set
|
* TODO END_HEADERS flag is not set
|
||||||
*/
|
*/
|
||||||
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload);
|
||||||
size_t payloadlen);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Packs PING frame |frame| in wire format and store it in
|
* Packs PING frame |frame| in wire format and store it in
|
||||||
@@ -291,8 +288,7 @@ int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
|
|||||||
* Unpacks PING wire format into |frame|.
|
* Unpacks PING wire format into |frame|.
|
||||||
*/
|
*/
|
||||||
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
|
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload);
|
||||||
size_t payloadlen);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Packs GOAWAY frame |frame| in wire format and store it in |bufs|.
|
* Packs GOAWAY frame |frame| in wire format and store it in |bufs|.
|
||||||
@@ -321,7 +317,6 @@ int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame);
|
|||||||
*/
|
*/
|
||||||
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
|
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload,
|
||||||
size_t payloadlen,
|
|
||||||
uint8_t *var_gift_payload,
|
uint8_t *var_gift_payload,
|
||||||
size_t var_gift_payloadlen);
|
size_t var_gift_payloadlen);
|
||||||
|
|
||||||
@@ -356,8 +351,7 @@ int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
|||||||
* Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
|
* Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
|
||||||
*/
|
*/
|
||||||
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload);
|
||||||
size_t payloadlen);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Packs ALTSVC frame |frame| in wire frame format and store it in
|
* Packs ALTSVC frame |frame| in wire frame format and store it in
|
||||||
|
|||||||
@@ -662,9 +662,9 @@ static int hd_context_init(nghttp2_hd_context *context, nghttp2_mem *mem) {
|
|||||||
context->mem = mem;
|
context->mem = mem;
|
||||||
context->bad = 0;
|
context->bad = 0;
|
||||||
context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
|
context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
|
||||||
rv = hd_ringbuf_init(&context->hd_table, context->hd_table_bufsize_max /
|
rv = hd_ringbuf_init(
|
||||||
NGHTTP2_HD_ENTRY_OVERHEAD,
|
&context->hd_table,
|
||||||
mem);
|
context->hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD, mem);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@@ -1537,10 +1537,11 @@ ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
|
|||||||
return (ssize_t)buflen;
|
return (ssize_t)buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater _U_,
|
size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
|
||||||
const nghttp2_nv *nva, size_t nvlen) {
|
const nghttp2_nv *nva, size_t nvlen) {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
(void)deflater;
|
||||||
|
|
||||||
/* Possible Maximum Header Table Size Change. Encoding (1u << 31) -
|
/* Possible Maximum Header Table Size Change. Encoding (1u << 31) -
|
||||||
1 using 4 bit prefix requires 6 bytes. We may emit this at most
|
1 using 4 bit prefix requires 6 bytes. We may emit this at most
|
||||||
|
|||||||
@@ -211,7 +211,9 @@ typedef struct {
|
|||||||
|
|
||||||
#define HD_MAP_SIZE 128
|
#define HD_MAP_SIZE 128
|
||||||
|
|
||||||
typedef struct { nghttp2_hd_entry *table[HD_MAP_SIZE]; } nghttp2_hd_map;
|
typedef struct {
|
||||||
|
nghttp2_hd_entry *table[HD_MAP_SIZE];
|
||||||
|
} nghttp2_hd_map;
|
||||||
|
|
||||||
struct nghttp2_hd_deflater {
|
struct nghttp2_hd_deflater {
|
||||||
nghttp2_hd_context ctx;
|
nghttp2_hd_context ctx;
|
||||||
@@ -313,7 +315,7 @@ void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater);
|
|||||||
*
|
*
|
||||||
* This function expands |bufs| as necessary to store the result. If
|
* This function expands |bufs| as necessary to store the result. If
|
||||||
* buffers is full and the process still requires more space, this
|
* buffers is full and the process still requires more space, this
|
||||||
* funtion fails and returns NGHTTP2_ERR_HEADER_COMP.
|
* function fails and returns NGHTTP2_ERR_HEADER_COMP.
|
||||||
*
|
*
|
||||||
* After this function returns, it is safe to delete the |nva|.
|
* After this function returns, it is safe to delete the |nva|.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -322,6 +322,9 @@ const char *nghttp2_strerror(int error_code) {
|
|||||||
return "Internal error";
|
return "Internal error";
|
||||||
case NGHTTP2_ERR_CANCEL:
|
case NGHTTP2_ERR_CANCEL:
|
||||||
return "Cancel";
|
return "Cancel";
|
||||||
|
case NGHTTP2_ERR_SETTINGS_EXPECTED:
|
||||||
|
return "When a local endpoint expects to receive SETTINGS frame, it "
|
||||||
|
"receives an other type of frame";
|
||||||
case NGHTTP2_ERR_NOMEM:
|
case NGHTTP2_ERR_NOMEM:
|
||||||
return "Out of memory";
|
return "Out of memory";
|
||||||
case NGHTTP2_ERR_CALLBACK_FAILURE:
|
case NGHTTP2_ERR_CALLBACK_FAILURE:
|
||||||
|
|||||||
@@ -521,8 +521,10 @@ int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_http_on_trailer_headers(nghttp2_stream *stream _U_,
|
int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
|
||||||
nghttp2_frame *frame) {
|
nghttp2_frame *frame) {
|
||||||
|
(void)stream;
|
||||||
|
|
||||||
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
|
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,18 +24,27 @@
|
|||||||
*/
|
*/
|
||||||
#include "nghttp2_mem.h"
|
#include "nghttp2_mem.h"
|
||||||
|
|
||||||
static void *default_malloc(size_t size, void *mem_user_data _U_) {
|
static void *default_malloc(size_t size, void *mem_user_data) {
|
||||||
|
(void)mem_user_data;
|
||||||
|
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_free(void *ptr, void *mem_user_data _U_) { free(ptr); }
|
static void default_free(void *ptr, void *mem_user_data) {
|
||||||
|
(void)mem_user_data;
|
||||||
|
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *default_calloc(size_t nmemb, size_t size, void *mem_user_data) {
|
||||||
|
(void)mem_user_data;
|
||||||
|
|
||||||
static void *default_calloc(size_t nmemb, size_t size,
|
|
||||||
void *mem_user_data _U_) {
|
|
||||||
return calloc(nmemb, size);
|
return calloc(nmemb, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *default_realloc(void *ptr, size_t size, void *mem_user_data _U_) {
|
static void *default_realloc(void *ptr, size_t size, void *mem_user_data) {
|
||||||
|
(void)mem_user_data;
|
||||||
|
|
||||||
return realloc(ptr, size);
|
return realloc(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ struct nghttp2_outbound_item {
|
|||||||
nghttp2_ext_frame_payload ext_frame_payload;
|
nghttp2_ext_frame_payload ext_frame_payload;
|
||||||
nghttp2_aux_data aux_data;
|
nghttp2_aux_data aux_data;
|
||||||
/* The priority used in priority comparion. Smaller is served
|
/* The priority used in priority comparion. Smaller is served
|
||||||
ealier. For PING, SETTINGS and non-DATA frames (excluding
|
earlier. For PING, SETTINGS and non-DATA frames (excluding
|
||||||
response HEADERS frame) have dedicated cycle value defined above.
|
response HEADERS frame) have dedicated cycle value defined above.
|
||||||
For DATA frame, cycle is computed by taking into account of
|
For DATA frame, cycle is computed by taking into account of
|
||||||
effective weight and frame payload length previously sent, so
|
effective weight and frame payload length previously sent, so
|
||||||
|
|||||||
@@ -35,14 +35,16 @@
|
|||||||
|
|
||||||
/* Implementation of priority queue */
|
/* Implementation of priority queue */
|
||||||
|
|
||||||
typedef struct { size_t index; } nghttp2_pq_entry;
|
typedef struct {
|
||||||
|
size_t index;
|
||||||
|
} nghttp2_pq_entry;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* The pointer to the pointer to the item stored */
|
/* The pointer to the pointer to the item stored */
|
||||||
nghttp2_pq_entry **q;
|
nghttp2_pq_entry **q;
|
||||||
/* Memory allocator */
|
/* Memory allocator */
|
||||||
nghttp2_mem *mem;
|
nghttp2_mem *mem;
|
||||||
/* The number of items sotred */
|
/* The number of items stored */
|
||||||
size_t length;
|
size_t length;
|
||||||
/* The maximum number of items this pq can store. This is
|
/* The maximum number of items this pq can store. This is
|
||||||
automatically extended when length is reached to this value. */
|
automatically extended when length is reached to this value. */
|
||||||
@@ -71,7 +73,7 @@ void nghttp2_pq_free(nghttp2_pq *pq);
|
|||||||
/*
|
/*
|
||||||
* Adds |item| to the priority queue |pq|.
|
* Adds |item| to the priority queue |pq|.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeds, or one of the following
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
* negative error codes:
|
* negative error codes:
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ typedef struct nghttp2_queue_cell {
|
|||||||
struct nghttp2_queue_cell *next;
|
struct nghttp2_queue_cell *next;
|
||||||
} nghttp2_queue_cell;
|
} nghttp2_queue_cell;
|
||||||
|
|
||||||
typedef struct { nghttp2_queue_cell *front, *back; } nghttp2_queue;
|
typedef struct {
|
||||||
|
nghttp2_queue_cell *front, *back;
|
||||||
|
} nghttp2_queue;
|
||||||
|
|
||||||
void nghttp2_queue_init(nghttp2_queue *queue);
|
void nghttp2_queue_init(nghttp2_queue *queue);
|
||||||
void nghttp2_queue_free(nghttp2_queue *queue);
|
void nghttp2_queue_free(nghttp2_queue *queue);
|
||||||
|
|||||||
@@ -96,3 +96,7 @@ nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf) {
|
|||||||
nghttp2_vec res = {rcbuf->base, rcbuf->len};
|
nghttp2_vec res = {rcbuf->base, rcbuf->len};
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf) {
|
||||||
|
return rcbuf->ref == -1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -148,14 +148,16 @@ static int check_ext_type_set(const uint8_t *ext_types, uint8_t type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int session_call_error_callback(nghttp2_session *session,
|
static int session_call_error_callback(nghttp2_session *session,
|
||||||
const char *fmt, ...) {
|
int lib_error_code, const char *fmt,
|
||||||
|
...) {
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char *buf;
|
char *buf;
|
||||||
int rv;
|
int rv;
|
||||||
nghttp2_mem *mem;
|
nghttp2_mem *mem;
|
||||||
|
|
||||||
if (!session->callbacks.error_callback) {
|
if (!session->callbacks.error_callback &&
|
||||||
|
!session->callbacks.error_callback2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,8 +191,13 @@ static int session_call_error_callback(nghttp2_session *session,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = session->callbacks.error_callback(session, buf, (size_t)rv,
|
if (session->callbacks.error_callback2) {
|
||||||
session->user_data);
|
rv = session->callbacks.error_callback2(session, lib_error_code, buf,
|
||||||
|
(size_t)rv, session->user_data);
|
||||||
|
} else {
|
||||||
|
rv = session->callbacks.error_callback(session, buf, (size_t)rv,
|
||||||
|
session->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
nghttp2_mem_free(mem, buf);
|
nghttp2_mem_free(mem, buf);
|
||||||
|
|
||||||
@@ -541,9 +548,8 @@ static int session_new(nghttp2_session **session_ptr,
|
|||||||
if (nghttp2_enable_strict_preface) {
|
if (nghttp2_enable_strict_preface) {
|
||||||
nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe;
|
nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe;
|
||||||
|
|
||||||
if (server &&
|
if (server && ((*session_ptr)->opt_flags &
|
||||||
((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) ==
|
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) == 0) {
|
||||||
0) {
|
|
||||||
iframe->state = NGHTTP2_IB_READ_CLIENT_MAGIC;
|
iframe->state = NGHTTP2_IB_READ_CLIENT_MAGIC;
|
||||||
iframe->payloadleft = NGHTTP2_CLIENT_MAGIC_LEN;
|
iframe->payloadleft = NGHTTP2_CLIENT_MAGIC_LEN;
|
||||||
} else {
|
} else {
|
||||||
@@ -682,6 +688,7 @@ static int inflight_settings_new(nghttp2_inflight_settings **settings_ptr,
|
|||||||
if (niv > 0) {
|
if (niv > 0) {
|
||||||
(*settings_ptr)->iv = nghttp2_frame_iv_copy(iv, niv, mem);
|
(*settings_ptr)->iv = nghttp2_frame_iv_copy(iv, niv, mem);
|
||||||
if (!(*settings_ptr)->iv) {
|
if (!(*settings_ptr)->iv) {
|
||||||
|
nghttp2_mem_free(mem, *settings_ptr);
|
||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1523,13 +1530,14 @@ static int session_predicate_response_headers_send(nghttp2_session *session,
|
|||||||
if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) {
|
if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) {
|
||||||
return NGHTTP2_ERR_INVALID_STREAM_ID;
|
return NGHTTP2_ERR_INVALID_STREAM_ID;
|
||||||
}
|
}
|
||||||
if (stream->state == NGHTTP2_STREAM_OPENING) {
|
switch (stream->state) {
|
||||||
|
case NGHTTP2_STREAM_OPENING:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
case NGHTTP2_STREAM_CLOSING:
|
||||||
if (stream->state == NGHTTP2_STREAM_CLOSING) {
|
|
||||||
return NGHTTP2_ERR_STREAM_CLOSING;
|
return NGHTTP2_ERR_STREAM_CLOSING;
|
||||||
|
default:
|
||||||
|
return NGHTTP2_ERR_INVALID_STREAM_STATE;
|
||||||
}
|
}
|
||||||
return NGHTTP2_ERR_INVALID_STREAM_STATE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1572,9 +1580,6 @@ session_predicate_push_response_headers_send(nghttp2_session *session,
|
|||||||
if (stream->state != NGHTTP2_STREAM_RESERVED) {
|
if (stream->state != NGHTTP2_STREAM_RESERVED) {
|
||||||
return NGHTTP2_ERR_PROTO;
|
return NGHTTP2_ERR_PROTO;
|
||||||
}
|
}
|
||||||
if (stream->state == NGHTTP2_STREAM_CLOSING) {
|
|
||||||
return NGHTTP2_ERR_STREAM_CLOSING;
|
|
||||||
}
|
|
||||||
if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) {
|
if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) {
|
||||||
return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED;
|
return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
@@ -1609,19 +1614,18 @@ static int session_predicate_headers_send(nghttp2_session *session,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
assert(stream);
|
assert(stream);
|
||||||
if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) {
|
|
||||||
if (stream->state == NGHTTP2_STREAM_CLOSING) {
|
switch (stream->state) {
|
||||||
return NGHTTP2_ERR_STREAM_CLOSING;
|
case NGHTTP2_STREAM_OPENED:
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
case NGHTTP2_STREAM_CLOSING:
|
||||||
if (stream->state == NGHTTP2_STREAM_OPENED) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (stream->state == NGHTTP2_STREAM_CLOSING) {
|
|
||||||
return NGHTTP2_ERR_STREAM_CLOSING;
|
return NGHTTP2_ERR_STREAM_CLOSING;
|
||||||
|
default:
|
||||||
|
if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return NGHTTP2_ERR_INVALID_STREAM_STATE;
|
||||||
}
|
}
|
||||||
return NGHTTP2_ERR_INVALID_STREAM_STATE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2067,14 +2071,6 @@ static int session_prep_frame(nghttp2_session *session,
|
|||||||
/* We don't call nghttp2_session_adjust_closed_stream() here,
|
/* We don't call nghttp2_session_adjust_closed_stream() here,
|
||||||
since we don't keep closed stream in client side */
|
since we don't keep closed stream in client side */
|
||||||
|
|
||||||
estimated_payloadlen = session_estimate_headers_payload(
|
|
||||||
session, frame->headers.nva, frame->headers.nvlen,
|
|
||||||
NGHTTP2_PRIORITY_SPECLEN);
|
|
||||||
|
|
||||||
if (estimated_payloadlen > session->max_send_header_block_length) {
|
|
||||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = session_predicate_request_headers_send(session, item);
|
rv = session_predicate_request_headers_send(session, item);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
@@ -2086,14 +2082,6 @@ static int session_prep_frame(nghttp2_session *session,
|
|||||||
} else {
|
} else {
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
estimated_payloadlen = session_estimate_headers_payload(
|
|
||||||
session, frame->headers.nva, frame->headers.nvlen,
|
|
||||||
NGHTTP2_PRIORITY_SPECLEN);
|
|
||||||
|
|
||||||
if (estimated_payloadlen > session->max_send_header_block_length) {
|
|
||||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||||
|
|
||||||
if (stream && stream->state == NGHTTP2_STREAM_RESERVED) {
|
if (stream && stream->state == NGHTTP2_STREAM_RESERVED) {
|
||||||
@@ -2120,6 +2108,14 @@ static int session_prep_frame(nghttp2_session *session,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
estimated_payloadlen = session_estimate_headers_payload(
|
||||||
|
session, frame->headers.nva, frame->headers.nvlen,
|
||||||
|
NGHTTP2_PRIORITY_SPECLEN);
|
||||||
|
|
||||||
|
if (estimated_payloadlen > session->max_send_header_block_length) {
|
||||||
|
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
rv = nghttp2_frame_pack_headers(&session->aob.framebufs, &frame->headers,
|
rv = nghttp2_frame_pack_headers(&session->aob.framebufs, &frame->headers,
|
||||||
&session->hd_deflater);
|
&session->hd_deflater);
|
||||||
|
|
||||||
@@ -2189,18 +2185,11 @@ static int session_prep_frame(nghttp2_session *session,
|
|||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
size_t estimated_payloadlen;
|
size_t estimated_payloadlen;
|
||||||
|
|
||||||
estimated_payloadlen = session_estimate_headers_payload(
|
|
||||||
session, frame->push_promise.nva, frame->push_promise.nvlen, 0);
|
|
||||||
|
|
||||||
if (estimated_payloadlen > session->max_send_header_block_length) {
|
|
||||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stream could be NULL if associated stream was already
|
/* stream could be NULL if associated stream was already
|
||||||
closed. */
|
closed. */
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||||
|
|
||||||
/* predicte should fail if stream is NULL. */
|
/* predicate should fail if stream is NULL. */
|
||||||
rv = session_predicate_push_promise_send(session, stream);
|
rv = session_predicate_push_promise_send(session, stream);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
@@ -2208,6 +2197,13 @@ static int session_prep_frame(nghttp2_session *session,
|
|||||||
|
|
||||||
assert(stream);
|
assert(stream);
|
||||||
|
|
||||||
|
estimated_payloadlen = session_estimate_headers_payload(
|
||||||
|
session, frame->push_promise.nva, frame->push_promise.nvlen, 0);
|
||||||
|
|
||||||
|
if (estimated_payloadlen > session->max_send_header_block_length) {
|
||||||
|
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
rv = nghttp2_frame_pack_push_promise(
|
rv = nghttp2_frame_pack_push_promise(
|
||||||
&session->aob.framebufs, &frame->push_promise, &session->hd_deflater);
|
&session->aob.framebufs, &frame->push_promise, &session->hd_deflater);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
@@ -2229,8 +2225,9 @@ static int session_prep_frame(nghttp2_session *session,
|
|||||||
assert(session->obq_flood_counter_ > 0);
|
assert(session->obq_flood_counter_ > 0);
|
||||||
--session->obq_flood_counter_;
|
--session->obq_flood_counter_;
|
||||||
}
|
}
|
||||||
|
/* PING frame is allowed to be sent unless termination GOAWAY is
|
||||||
if (session_is_closing(session)) {
|
sent */
|
||||||
|
if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) {
|
||||||
return NGHTTP2_ERR_SESSION_CLOSING;
|
return NGHTTP2_ERR_SESSION_CLOSING;
|
||||||
}
|
}
|
||||||
nghttp2_frame_pack_ping(&session->aob.framebufs, &frame->ping);
|
nghttp2_frame_pack_ping(&session->aob.framebufs, &frame->ping);
|
||||||
@@ -2421,19 +2418,16 @@ static int session_close_stream_on_goaway(nghttp2_session *session,
|
|||||||
nghttp2_stream *stream, *next_stream;
|
nghttp2_stream *stream, *next_stream;
|
||||||
nghttp2_close_stream_on_goaway_arg arg = {session, NULL, last_stream_id,
|
nghttp2_close_stream_on_goaway_arg arg = {session, NULL, last_stream_id,
|
||||||
incoming};
|
incoming};
|
||||||
uint32_t error_code;
|
|
||||||
|
|
||||||
rv = nghttp2_map_each(&session->streams, find_stream_on_goaway_func, &arg);
|
rv = nghttp2_map_each(&session->streams, find_stream_on_goaway_func, &arg);
|
||||||
assert(rv == 0);
|
assert(rv == 0);
|
||||||
|
|
||||||
error_code =
|
|
||||||
session->server && incoming ? NGHTTP2_REFUSED_STREAM : NGHTTP2_CANCEL;
|
|
||||||
|
|
||||||
stream = arg.head;
|
stream = arg.head;
|
||||||
while (stream) {
|
while (stream) {
|
||||||
next_stream = stream->closed_next;
|
next_stream = stream->closed_next;
|
||||||
stream->closed_next = NULL;
|
stream->closed_next = NULL;
|
||||||
rv = nghttp2_session_close_stream(session, stream->stream_id, error_code);
|
rv = nghttp2_session_close_stream(session, stream->stream_id,
|
||||||
|
NGHTTP2_REFUSED_STREAM);
|
||||||
|
|
||||||
/* stream may be deleted here */
|
/* stream may be deleted here */
|
||||||
|
|
||||||
@@ -3331,7 +3325,7 @@ static int session_call_on_invalid_header(nghttp2_session *session,
|
|||||||
session, frame, nv->name->base, nv->name->len, nv->value->base,
|
session, frame, nv->name->base, nv->name->len, nv->value->base,
|
||||||
nv->value->len, nv->flags, session->user_data);
|
nv->value->len, nv->flags, session->user_data);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||||
@@ -3394,8 +3388,7 @@ static int session_call_unpack_extension_callback(nghttp2_session *session) {
|
|||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
*/
|
*/
|
||||||
static int session_handle_frame_size_error(nghttp2_session *session,
|
static int session_handle_frame_size_error(nghttp2_session *session) {
|
||||||
nghttp2_frame *frame _U_) {
|
|
||||||
/* TODO Currently no callback is called for this error, because we
|
/* TODO Currently no callback is called for this error, because we
|
||||||
call this callback before reading any payload */
|
call this callback before reading any payload */
|
||||||
return nghttp2_session_terminate_session(session, NGHTTP2_FRAME_SIZE_ERROR);
|
return nghttp2_session_terminate_session(session, NGHTTP2_FRAME_SIZE_ERROR);
|
||||||
@@ -3422,6 +3415,27 @@ static uint32_t get_error_code_from_lib_error_code(int lib_error_code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calls on_invalid_frame_recv_callback if it is set to |session|.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* User defined callback function fails.
|
||||||
|
*/
|
||||||
|
static int session_call_on_invalid_frame_recv_callback(nghttp2_session *session,
|
||||||
|
nghttp2_frame *frame,
|
||||||
|
int lib_error_code) {
|
||||||
|
if (session->callbacks.on_invalid_frame_recv_callback) {
|
||||||
|
if (session->callbacks.on_invalid_frame_recv_callback(
|
||||||
|
session, frame, lib_error_code, session->user_data) != 0) {
|
||||||
|
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int session_handle_invalid_stream2(nghttp2_session *session,
|
static int session_handle_invalid_stream2(nghttp2_session *session,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
nghttp2_frame *frame,
|
nghttp2_frame *frame,
|
||||||
@@ -3579,14 +3593,46 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
|
|||||||
if (subject_stream && session_enforce_http_messaging(session)) {
|
if (subject_stream && session_enforce_http_messaging(session)) {
|
||||||
rv = nghttp2_http_on_header(session, subject_stream, frame, &nv,
|
rv = nghttp2_http_on_header(session, subject_stream, frame, &nv,
|
||||||
trailer);
|
trailer);
|
||||||
|
|
||||||
|
if (rv == NGHTTP2_ERR_IGN_HTTP_HEADER) {
|
||||||
|
/* Don't overwrite rv here */
|
||||||
|
int rv2;
|
||||||
|
|
||||||
|
rv2 = session_call_on_invalid_header(session, frame, &nv);
|
||||||
|
if (rv2 == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||||
|
rv = NGHTTP2_ERR_HTTP_HEADER;
|
||||||
|
} else {
|
||||||
|
if (rv2 != 0) {
|
||||||
|
return rv2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* header is ignored */
|
||||||
|
DEBUGF("recv: HTTP ignored: type=%u, id=%d, header %.*s: %.*s\n",
|
||||||
|
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
||||||
|
nv.name->base, (int)nv.value->len, nv.value->base);
|
||||||
|
|
||||||
|
rv2 = session_call_error_callback(
|
||||||
|
session, NGHTTP2_ERR_HTTP_HEADER,
|
||||||
|
"Ignoring received invalid HTTP header field: frame type: "
|
||||||
|
"%u, stream: %d, name: [%.*s], value: [%.*s]",
|
||||||
|
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
||||||
|
nv.name->base, (int)nv.value->len, nv.value->base);
|
||||||
|
|
||||||
|
if (nghttp2_is_fatal(rv2)) {
|
||||||
|
return rv2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rv == NGHTTP2_ERR_HTTP_HEADER) {
|
if (rv == NGHTTP2_ERR_HTTP_HEADER) {
|
||||||
DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n",
|
DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n",
|
||||||
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
||||||
nv.name->base, (int)nv.value->len, nv.value->base);
|
nv.name->base, (int)nv.value->len, nv.value->base);
|
||||||
|
|
||||||
rv = session_call_error_callback(
|
rv = session_call_error_callback(
|
||||||
session, "Invalid HTTP header field was received: frame type: "
|
session, NGHTTP2_ERR_HTTP_HEADER,
|
||||||
"%u, stream: %d, name: [%.*s], value: [%.*s]",
|
"Invalid HTTP header field was received: frame type: "
|
||||||
|
"%u, stream: %d, name: [%.*s], value: [%.*s]",
|
||||||
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
||||||
nv.name->base, (int)nv.value->len, nv.value->base);
|
nv.name->base, (int)nv.value->len, nv.value->base);
|
||||||
|
|
||||||
@@ -3602,34 +3648,6 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
|
|||||||
}
|
}
|
||||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv == NGHTTP2_ERR_IGN_HTTP_HEADER) {
|
|
||||||
/* Don't overwrite rv here */
|
|
||||||
int rv2;
|
|
||||||
|
|
||||||
rv2 = session_call_on_invalid_header(session, frame, &nv);
|
|
||||||
/* This handles NGHTTP2_ERR_PAUSE and
|
|
||||||
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */
|
|
||||||
if (rv2 != 0) {
|
|
||||||
return rv2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* header is ignored */
|
|
||||||
DEBUGF("recv: HTTP ignored: type=%u, id=%d, header %.*s: %.*s\n",
|
|
||||||
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
|
||||||
nv.name->base, (int)nv.value->len, nv.value->base);
|
|
||||||
|
|
||||||
rv2 = session_call_error_callback(
|
|
||||||
session,
|
|
||||||
"Ignoring received invalid HTTP header field: frame type: "
|
|
||||||
"%u, stream: %d, name: [%.*s], value: [%.*s]",
|
|
||||||
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
|
||||||
nv.name->base, (int)nv.value->len, nv.value->base);
|
|
||||||
|
|
||||||
if (nghttp2_is_fatal(rv2)) {
|
|
||||||
return rv2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (rv == 0) {
|
if (rv == 0) {
|
||||||
rv = session_call_on_header(session, frame, &nv);
|
rv = session_call_on_header(session, frame, &nv);
|
||||||
@@ -3768,7 +3786,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
|||||||
session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: stream_id == 0");
|
session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: stream_id == 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If client recieves idle stream from server, it is invalid
|
/* If client receives idle stream from server, it is invalid
|
||||||
regardless stream ID is even or odd. This is because client is
|
regardless stream ID is even or odd. This is because client is
|
||||||
not expected to receive request from server. */
|
not expected to receive request from server. */
|
||||||
if (!session->server) {
|
if (!session->server) {
|
||||||
@@ -3991,8 +4009,7 @@ static int session_process_headers_frame(nghttp2_session *session) {
|
|||||||
nghttp2_frame *frame = &iframe->frame;
|
nghttp2_frame *frame = &iframe->frame;
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
rv = nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos,
|
rv = nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos);
|
||||||
nghttp2_buf_len(&iframe->sbuf));
|
|
||||||
|
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return nghttp2_session_terminate_session_with_reason(
|
return nghttp2_session_terminate_session_with_reason(
|
||||||
@@ -4082,8 +4099,7 @@ static int session_process_priority_frame(nghttp2_session *session) {
|
|||||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||||
nghttp2_frame *frame = &iframe->frame;
|
nghttp2_frame *frame = &iframe->frame;
|
||||||
|
|
||||||
nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos,
|
nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos);
|
||||||
nghttp2_buf_len(&iframe->sbuf));
|
|
||||||
|
|
||||||
return nghttp2_session_on_priority_received(session, frame);
|
return nghttp2_session_on_priority_received(session, frame);
|
||||||
}
|
}
|
||||||
@@ -4124,8 +4140,7 @@ static int session_process_rst_stream_frame(nghttp2_session *session) {
|
|||||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||||
nghttp2_frame *frame = &iframe->frame;
|
nghttp2_frame *frame = &iframe->frame;
|
||||||
|
|
||||||
nghttp2_frame_unpack_rst_stream_payload(&frame->rst_stream, iframe->sbuf.pos,
|
nghttp2_frame_unpack_rst_stream_payload(&frame->rst_stream, iframe->sbuf.pos);
|
||||||
nghttp2_buf_len(&iframe->sbuf));
|
|
||||||
|
|
||||||
return nghttp2_session_on_rst_stream_received(session, frame);
|
return nghttp2_session_on_rst_stream_received(session, frame);
|
||||||
}
|
}
|
||||||
@@ -4597,8 +4612,8 @@ static int session_process_push_promise_frame(nghttp2_session *session) {
|
|||||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||||
nghttp2_frame *frame = &iframe->frame;
|
nghttp2_frame *frame = &iframe->frame;
|
||||||
|
|
||||||
rv = nghttp2_frame_unpack_push_promise_payload(
|
rv = nghttp2_frame_unpack_push_promise_payload(&frame->push_promise,
|
||||||
&frame->push_promise, iframe->sbuf.pos, nghttp2_buf_len(&iframe->sbuf));
|
iframe->sbuf.pos);
|
||||||
|
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return nghttp2_session_terminate_session_with_reason(
|
return nghttp2_session_terminate_session_with_reason(
|
||||||
@@ -4632,8 +4647,7 @@ static int session_process_ping_frame(nghttp2_session *session) {
|
|||||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||||
nghttp2_frame *frame = &iframe->frame;
|
nghttp2_frame *frame = &iframe->frame;
|
||||||
|
|
||||||
nghttp2_frame_unpack_ping_payload(&frame->ping, iframe->sbuf.pos,
|
nghttp2_frame_unpack_ping_payload(&frame->ping, iframe->sbuf.pos);
|
||||||
nghttp2_buf_len(&iframe->sbuf));
|
|
||||||
|
|
||||||
return nghttp2_session_on_ping_received(session, frame);
|
return nghttp2_session_on_ping_received(session, frame);
|
||||||
}
|
}
|
||||||
@@ -4674,9 +4688,9 @@ static int session_process_goaway_frame(nghttp2_session *session) {
|
|||||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||||
nghttp2_frame *frame = &iframe->frame;
|
nghttp2_frame *frame = &iframe->frame;
|
||||||
|
|
||||||
nghttp2_frame_unpack_goaway_payload(
|
nghttp2_frame_unpack_goaway_payload(&frame->goaway, iframe->sbuf.pos,
|
||||||
&frame->goaway, iframe->sbuf.pos, nghttp2_buf_len(&iframe->sbuf),
|
iframe->lbuf.pos,
|
||||||
iframe->lbuf.pos, nghttp2_buf_len(&iframe->lbuf));
|
nghttp2_buf_len(&iframe->lbuf));
|
||||||
|
|
||||||
nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0);
|
nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0);
|
||||||
|
|
||||||
@@ -4759,8 +4773,8 @@ static int session_process_window_update_frame(nghttp2_session *session) {
|
|||||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||||
nghttp2_frame *frame = &iframe->frame;
|
nghttp2_frame *frame = &iframe->frame;
|
||||||
|
|
||||||
nghttp2_frame_unpack_window_update_payload(
|
nghttp2_frame_unpack_window_update_payload(&frame->window_update,
|
||||||
&frame->window_update, iframe->sbuf.pos, nghttp2_buf_len(&iframe->sbuf));
|
iframe->sbuf.pos);
|
||||||
|
|
||||||
return nghttp2_session_on_window_update_received(session, frame);
|
return nghttp2_session_on_window_update_received(session, frame);
|
||||||
}
|
}
|
||||||
@@ -4776,11 +4790,13 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session,
|
|||||||
|
|
||||||
if (frame->hd.stream_id == 0) {
|
if (frame->hd.stream_id == 0) {
|
||||||
if (altsvc->origin_len == 0) {
|
if (altsvc->origin_len == 0) {
|
||||||
return 0;
|
return session_call_on_invalid_frame_recv_callback(session, frame,
|
||||||
|
NGHTTP2_ERR_PROTO);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (altsvc->origin_len > 0) {
|
if (altsvc->origin_len > 0) {
|
||||||
return 0;
|
return session_call_on_invalid_frame_recv_callback(session, frame,
|
||||||
|
NGHTTP2_ERR_PROTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||||
@@ -4793,6 +4809,11 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (altsvc->field_value_len == 0) {
|
||||||
|
return session_call_on_invalid_frame_recv_callback(session, frame,
|
||||||
|
NGHTTP2_ERR_PROTO);
|
||||||
|
}
|
||||||
|
|
||||||
return session_call_on_frame_received(session, frame);
|
return session_call_on_frame_received(session, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5289,6 +5310,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!nghttp2_session_want_read(session)) {
|
||||||
|
return (ssize_t)inlen;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch (iframe->state) {
|
switch (iframe->state) {
|
||||||
case NGHTTP2_IB_READ_CLIENT_MAGIC:
|
case NGHTTP2_IB_READ_CLIENT_MAGIC:
|
||||||
@@ -5325,9 +5350,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||||||
iframe->state = NGHTTP2_IB_IGN_ALL;
|
iframe->state = NGHTTP2_IB_IGN_ALL;
|
||||||
|
|
||||||
rv = session_call_error_callback(
|
rv = session_call_error_callback(
|
||||||
session, "Remote peer returned unexpected data while we expected "
|
session, NGHTTP2_ERR_SETTINGS_EXPECTED,
|
||||||
"SETTINGS frame. Perhaps, peer does not support HTTP/2 "
|
"Remote peer returned unexpected data while we expected "
|
||||||
"properly.");
|
"SETTINGS frame. Perhaps, peer does not support HTTP/2 "
|
||||||
|
"properly.");
|
||||||
|
|
||||||
if (nghttp2_is_fatal(rv)) {
|
if (nghttp2_is_fatal(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
@@ -5568,7 +5594,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||||||
if (iframe->payloadleft) {
|
if (iframe->payloadleft) {
|
||||||
nghttp2_settings_entry *min_header_table_size_entry;
|
nghttp2_settings_entry *min_header_table_size_entry;
|
||||||
|
|
||||||
/* We allocate iv with addtional one entry, to store the
|
/* We allocate iv with additional one entry, to store the
|
||||||
minimum header table size. */
|
minimum header table size. */
|
||||||
iframe->max_niv =
|
iframe->max_niv =
|
||||||
iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
|
iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
|
||||||
@@ -5951,7 +5977,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||||||
|
|
||||||
DEBUGF("recv: origin_len=%zu\n", origin_len);
|
DEBUGF("recv: origin_len=%zu\n", origin_len);
|
||||||
|
|
||||||
if (2 + origin_len > iframe->payloadleft) {
|
if (origin_len > iframe->payloadleft) {
|
||||||
busy = 1;
|
busy = 1;
|
||||||
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
|
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
|
||||||
break;
|
break;
|
||||||
@@ -6037,9 +6063,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||||||
|
|
||||||
/* Use promised stream ID for PUSH_PROMISE */
|
/* Use promised stream ID for PUSH_PROMISE */
|
||||||
rv = nghttp2_session_add_rst_stream(
|
rv = nghttp2_session_add_rst_stream(
|
||||||
session, iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE
|
session,
|
||||||
? iframe->frame.push_promise.promised_stream_id
|
iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE
|
||||||
: iframe->frame.hd.stream_id,
|
? iframe->frame.push_promise.promised_stream_id
|
||||||
|
: iframe->frame.hd.stream_id,
|
||||||
NGHTTP2_INTERNAL_ERROR);
|
NGHTTP2_INTERNAL_ERROR);
|
||||||
if (nghttp2_is_fatal(rv)) {
|
if (nghttp2_is_fatal(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
@@ -6124,7 +6151,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||||||
case NGHTTP2_IB_FRAME_SIZE_ERROR:
|
case NGHTTP2_IB_FRAME_SIZE_ERROR:
|
||||||
DEBUGF("recv: [IB_FRAME_SIZE_ERROR]\n");
|
DEBUGF("recv: [IB_FRAME_SIZE_ERROR]\n");
|
||||||
|
|
||||||
rv = session_handle_frame_size_error(session, &iframe->frame);
|
rv = session_handle_frame_size_error(session);
|
||||||
if (nghttp2_is_fatal(rv)) {
|
if (nghttp2_is_fatal(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@@ -6609,21 +6636,12 @@ int nghttp2_session_want_write(nghttp2_session *session) {
|
|||||||
* response HEADERS and concurrent stream limit is reached, we don't
|
* response HEADERS and concurrent stream limit is reached, we don't
|
||||||
* want to write them.
|
* want to write them.
|
||||||
*/
|
*/
|
||||||
|
return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) ||
|
||||||
if (session->aob.item == NULL &&
|
nghttp2_outbound_queue_top(&session->ob_reg) ||
|
||||||
nghttp2_outbound_queue_top(&session->ob_urgent) == NULL &&
|
(!nghttp2_pq_empty(&session->root.obq) &&
|
||||||
nghttp2_outbound_queue_top(&session->ob_reg) == NULL &&
|
session->remote_window_size > 0) ||
|
||||||
(nghttp2_pq_empty(&session->root.obq) ||
|
(nghttp2_outbound_queue_top(&session->ob_syn) &&
|
||||||
session->remote_window_size == 0) &&
|
!session_is_outgoing_concurrent_streams_max(session));
|
||||||
(nghttp2_outbound_queue_top(&session->ob_syn) == NULL ||
|
|
||||||
session_is_outgoing_concurrent_streams_max(session))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there is no active streams and GOAWAY has been sent or
|
|
||||||
received, we are done with this session. */
|
|
||||||
return (session->goaway_flags &
|
|
||||||
(NGHTTP2_GOAWAY_SENT | NGHTTP2_GOAWAY_RECV)) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
|
int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
|
||||||
@@ -7138,6 +7156,7 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
|
abort(); /* if NDEBUG is set */
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
|
uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
|
||||||
@@ -7158,6 +7177,7 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
|
abort(); /* if NDEBUG is set */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nghttp2_session_upgrade_internal(nghttp2_session *session,
|
static int nghttp2_session_upgrade_internal(nghttp2_session *session,
|
||||||
@@ -7501,3 +7521,7 @@ size_t
|
|||||||
nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) {
|
nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) {
|
||||||
return nghttp2_hd_deflate_get_dynamic_table_size(&session->hd_deflater);
|
return nghttp2_hd_deflate_get_dynamic_table_size(&session->hd_deflater);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) {
|
||||||
|
session->user_data = user_data;
|
||||||
|
}
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ struct nghttp2_session {
|
|||||||
/* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
|
/* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
|
||||||
to refuse the incoming stream if it exceeds this value. */
|
to refuse the incoming stream if it exceeds this value. */
|
||||||
uint32_t pending_local_max_concurrent_stream;
|
uint32_t pending_local_max_concurrent_stream;
|
||||||
/* The bitwose OR of zero or more of nghttp2_typemask to indicate
|
/* The bitwise OR of zero or more of nghttp2_typemask to indicate
|
||||||
that the default handling of extension frame is enabled. */
|
that the default handling of extension frame is enabled. */
|
||||||
uint32_t builtin_recv_ext_types;
|
uint32_t builtin_recv_ext_types;
|
||||||
/* Unacked local ENABLE_PUSH value. We use this to refuse
|
/* Unacked local ENABLE_PUSH value. We use this to refuse
|
||||||
@@ -319,7 +319,7 @@ struct nghttp2_session {
|
|||||||
uint8_t pending_enable_push;
|
uint8_t pending_enable_push;
|
||||||
/* Nonzero if the session is server side. */
|
/* Nonzero if the session is server side. */
|
||||||
uint8_t server;
|
uint8_t server;
|
||||||
/* Flags indicating GOAWAY is sent and/or recieved. The flags are
|
/* Flags indicating GOAWAY is sent and/or received. The flags are
|
||||||
composed by bitwise OR-ing nghttp2_goaway_flag. */
|
composed by bitwise OR-ing nghttp2_goaway_flag. */
|
||||||
uint8_t goaway_flags;
|
uint8_t goaway_flags;
|
||||||
/* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
|
/* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
|
||||||
@@ -722,7 +722,7 @@ int nghttp2_session_on_goaway_received(nghttp2_session *session,
|
|||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when WINDOW_UPDATE is recieved, assuming |frame| is properly
|
* Called when WINDOW_UPDATE is received, assuming |frame| is properly
|
||||||
* initialized.
|
* initialized.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
@@ -737,7 +737,7 @@ int nghttp2_session_on_window_update_received(nghttp2_session *session,
|
|||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when ALTSVC is recieved, assuming |frame| is properly
|
* Called when ALTSVC is received, assuming |frame| is properly
|
||||||
* initialized.
|
* initialized.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
|||||||
@@ -366,8 +366,9 @@ static void check_queued(nghttp2_stream *stream) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (queued == 0) {
|
if (queued == 0) {
|
||||||
fprintf(stderr, "stream(%p)=%d, stream->queued == 1, and "
|
fprintf(stderr,
|
||||||
"!stream_active(), but no descendants is queued\n",
|
"stream(%p)=%d, stream->queued == 1, and "
|
||||||
|
"!stream_active(), but no descendants is queued\n",
|
||||||
stream, stream->stream_id);
|
stream, stream->stream_id);
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
@@ -378,9 +379,10 @@ static void check_queued(nghttp2_stream *stream) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) {
|
if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) {
|
||||||
fprintf(stderr, "stream(%p) = %d, stream->queued == 0, but "
|
fprintf(stderr,
|
||||||
"stream_active(stream) == %d and "
|
"stream(%p) = %d, stream->queued == 0, but "
|
||||||
"nghttp2_pq_size(&stream->obq) = %zu\n",
|
"stream_active(stream) == %d and "
|
||||||
|
"nghttp2_pq_size(&stream->obq) = %zu\n",
|
||||||
stream, stream->stream_id, stream_active(stream),
|
stream, stream->stream_id, stream_active(stream),
|
||||||
nghttp2_pq_size(&stream->obq));
|
nghttp2_pq_size(&stream->obq));
|
||||||
assert(0);
|
assert(0);
|
||||||
@@ -449,8 +451,8 @@ static void validate_tree(nghttp2_stream *stream) {
|
|||||||
check_sum_dep(stream);
|
check_sum_dep(stream);
|
||||||
check_dep_prev(stream);
|
check_dep_prev(stream);
|
||||||
}
|
}
|
||||||
#else /* !STREAM_DEP_DEBUG */
|
#else /* !STREAM_DEP_DEBUG */
|
||||||
static void validate_tree(nghttp2_stream *stream _U_) {}
|
static void validate_tree(nghttp2_stream *stream) { (void)stream; }
|
||||||
#endif /* !STREAM_DEP_DEBUG*/
|
#endif /* !STREAM_DEP_DEBUG*/
|
||||||
|
|
||||||
static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
|
static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
|
|||||||
return nghttp2_session_add_ping(session, flags, opaque_data);
|
return nghttp2_session_add_ping(session, flags, opaque_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
|
int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
const nghttp2_priority_spec *pri_spec) {
|
const nghttp2_priority_spec *pri_spec) {
|
||||||
int rv;
|
int rv;
|
||||||
@@ -225,6 +225,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
|
|||||||
nghttp2_frame *frame;
|
nghttp2_frame *frame;
|
||||||
nghttp2_priority_spec copy_pri_spec;
|
nghttp2_priority_spec copy_pri_spec;
|
||||||
nghttp2_mem *mem;
|
nghttp2_mem *mem;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
mem = &session->mem;
|
mem = &session->mem;
|
||||||
|
|
||||||
@@ -264,8 +265,10 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags _U_,
|
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id, uint32_t error_code) {
|
int32_t stream_id, uint32_t error_code) {
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
if (stream_id == 0) {
|
if (stream_id == 0) {
|
||||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
@@ -273,9 +276,11 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags _U_,
|
|||||||
return nghttp2_session_add_rst_stream(session, stream_id, error_code);
|
return nghttp2_session_add_rst_stream(session, stream_id, error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags _U_,
|
int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t last_stream_id, uint32_t error_code,
|
int32_t last_stream_id, uint32_t error_code,
|
||||||
const uint8_t *opaque_data, size_t opaque_data_len) {
|
const uint8_t *opaque_data, size_t opaque_data_len) {
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) {
|
if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -296,12 +301,13 @@ int nghttp2_submit_shutdown_notice(nghttp2_session *session) {
|
|||||||
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE);
|
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags _U_,
|
int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
|
||||||
const nghttp2_settings_entry *iv, size_t niv) {
|
const nghttp2_settings_entry *iv, size_t niv) {
|
||||||
|
(void)flags;
|
||||||
return nghttp2_session_add_settings(session, NGHTTP2_FLAG_NONE, iv, niv);
|
return nghttp2_session_add_settings(session, NGHTTP2_FLAG_NONE, iv, niv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id, const nghttp2_nv *nva,
|
int32_t stream_id, const nghttp2_nv *nva,
|
||||||
size_t nvlen,
|
size_t nvlen,
|
||||||
void *promised_stream_user_data) {
|
void *promised_stream_user_data) {
|
||||||
@@ -312,6 +318,7 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
|||||||
int32_t promised_stream_id;
|
int32_t promised_stream_id;
|
||||||
int rv;
|
int rv;
|
||||||
nghttp2_mem *mem;
|
nghttp2_mem *mem;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
mem = &session->mem;
|
mem = &session->mem;
|
||||||
|
|
||||||
@@ -365,11 +372,13 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
|||||||
return promised_stream_id;
|
return promised_stream_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags _U_,
|
int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
int32_t window_size_increment) {
|
int32_t window_size_increment) {
|
||||||
int rv;
|
int rv;
|
||||||
nghttp2_stream *stream = 0;
|
nghttp2_stream *stream = 0;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
if (window_size_increment == 0) {
|
if (window_size_increment == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -410,11 +419,12 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags _U_,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
||||||
uint8_t flags _U_, int32_t stream_id,
|
uint8_t flags, int32_t stream_id,
|
||||||
int32_t window_size) {
|
int32_t window_size) {
|
||||||
int32_t window_size_increment;
|
int32_t window_size_increment;
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
int rv;
|
int rv;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
if (window_size < 0) {
|
if (window_size < 0) {
|
||||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
@@ -476,7 +486,7 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id, const uint8_t *origin,
|
int32_t stream_id, const uint8_t *origin,
|
||||||
size_t origin_len, const uint8_t *field_value,
|
size_t origin_len, const uint8_t *field_value,
|
||||||
size_t field_value_len) {
|
size_t field_value_len) {
|
||||||
@@ -488,6 +498,7 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
|||||||
nghttp2_frame *frame;
|
nghttp2_frame *frame;
|
||||||
nghttp2_ext_altsvc *altsvc;
|
nghttp2_ext_altsvc *altsvc;
|
||||||
int rv;
|
int rv;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
mem = &session->mem;
|
mem = &session->mem;
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,8 @@ set_source_files_properties(${cxx_sources} PROPERTIES
|
|||||||
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
|
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
"${CMAKE_SOURCE_DIR}/lib/includes"
|
"${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
||||||
"${CMAKE_BINARY_DIR}/lib/includes"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party"
|
||||||
"${CMAKE_SOURCE_DIR}/lib"
|
|
||||||
"${CMAKE_SOURCE_DIR}/src/includes"
|
|
||||||
"${CMAKE_SOURCE_DIR}/third-party"
|
|
||||||
|
|
||||||
${JEMALLOC_INCLUDE_DIRS}
|
${JEMALLOC_INCLUDE_DIRS}
|
||||||
${SPDYLAY_INCLUDE_DIRS}
|
${SPDYLAY_INCLUDE_DIRS}
|
||||||
@@ -48,7 +45,7 @@ if(ENABLE_APP)
|
|||||||
set(NGHTTP_SOURCES
|
set(NGHTTP_SOURCES
|
||||||
${HELPER_OBJECTS}
|
${HELPER_OBJECTS}
|
||||||
nghttp.cc
|
nghttp.cc
|
||||||
ssl.cc
|
tls.cc
|
||||||
)
|
)
|
||||||
if(HAVE_LIBXML2)
|
if(HAVE_LIBXML2)
|
||||||
list(APPEND NGHTTP_SOURCES HtmlParser.cc)
|
list(APPEND NGHTTP_SOURCES HtmlParser.cc)
|
||||||
@@ -58,7 +55,7 @@ if(ENABLE_APP)
|
|||||||
set(NGHTTPD_SOURCES
|
set(NGHTTPD_SOURCES
|
||||||
${HELPER_OBJECTS}
|
${HELPER_OBJECTS}
|
||||||
nghttpd.cc
|
nghttpd.cc
|
||||||
ssl.cc
|
tls.cc
|
||||||
HttpServer.cc
|
HttpServer.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,7 +64,7 @@ if(ENABLE_APP)
|
|||||||
util.cc
|
util.cc
|
||||||
http2.cc h2load.cc
|
http2.cc h2load.cc
|
||||||
timegm.c
|
timegm.c
|
||||||
ssl.cc
|
tls.cc
|
||||||
h2load_http2_session.cc
|
h2load_http2_session.cc
|
||||||
h2load_http1_session.cc
|
h2load_http1_session.cc
|
||||||
)
|
)
|
||||||
@@ -82,7 +79,7 @@ if(ENABLE_APP)
|
|||||||
set(NGHTTPX_SRCS
|
set(NGHTTPX_SRCS
|
||||||
util.cc http2.cc timegm.c
|
util.cc http2.cc timegm.c
|
||||||
app_helper.cc
|
app_helper.cc
|
||||||
ssl.cc
|
tls.cc
|
||||||
shrpx_config.cc
|
shrpx_config.cc
|
||||||
shrpx_accept_handler.cc
|
shrpx_accept_handler.cc
|
||||||
shrpx_connection_handler.cc
|
shrpx_connection_handler.cc
|
||||||
@@ -98,7 +95,7 @@ if(ENABLE_APP)
|
|||||||
shrpx_log.cc
|
shrpx_log.cc
|
||||||
shrpx_http.cc
|
shrpx_http.cc
|
||||||
shrpx_io_control.cc
|
shrpx_io_control.cc
|
||||||
shrpx_ssl.cc
|
shrpx_tls.cc
|
||||||
shrpx_worker.cc
|
shrpx_worker.cc
|
||||||
shrpx_log_config.cc
|
shrpx_log_config.cc
|
||||||
shrpx_connect_blocker.cc
|
shrpx_connect_blocker.cc
|
||||||
@@ -152,7 +149,7 @@ if(ENABLE_APP)
|
|||||||
if(HAVE_CUNIT)
|
if(HAVE_CUNIT)
|
||||||
set(NGHTTPX_UNITTEST_SOURCES
|
set(NGHTTPX_UNITTEST_SOURCES
|
||||||
shrpx-unittest.cc
|
shrpx-unittest.cc
|
||||||
shrpx_ssl_test.cc
|
shrpx_tls_test.cc
|
||||||
shrpx_downstream_test.cc
|
shrpx_downstream_test.cc
|
||||||
shrpx_config_test.cc
|
shrpx_config_test.cc
|
||||||
shrpx_worker_test.cc
|
shrpx_worker_test.cc
|
||||||
@@ -216,7 +213,7 @@ endif()
|
|||||||
if(ENABLE_ASIO_LIB)
|
if(ENABLE_ASIO_LIB)
|
||||||
set(NGHTTP2_ASIO_SOURCES
|
set(NGHTTP2_ASIO_SOURCES
|
||||||
util.cc http2.cc
|
util.cc http2.cc
|
||||||
ssl.cc
|
tls.cc
|
||||||
timegm.c
|
timegm.c
|
||||||
asio_common.cc
|
asio_common.cc
|
||||||
asio_io_service_pool.cc
|
asio_io_service_pool.cc
|
||||||
@@ -252,6 +249,11 @@ if(ENABLE_ASIO_LIB)
|
|||||||
${OPENSSL_INCLUDE_DIRS}
|
${OPENSSL_INCLUDE_DIRS}
|
||||||
${Boost_INCLUDE_DIRS}
|
${Boost_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
target_include_directories(nghttp2_asio INTERFACE
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/../lib/includes"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/../lib/includes"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
||||||
|
)
|
||||||
target_link_libraries(nghttp2_asio
|
target_link_libraries(nghttp2_asio
|
||||||
nghttp2
|
nghttp2
|
||||||
${OPENSSL_LIBRARIES}
|
${OPENSSL_LIBRARIES}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
#include "app_helper.h"
|
#include "app_helper.h"
|
||||||
#include "http2.h"
|
#include "http2.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ssl.h"
|
#include "tls.h"
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
|
|
||||||
#ifndef O_BINARY
|
#ifndef O_BINARY
|
||||||
@@ -877,7 +877,7 @@ int Http2Handler::connection_made() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssl_ && !nghttp2::ssl::check_http2_requirement(ssl_)) {
|
if (ssl_ && !nghttp2::tls::check_http2_requirement(ssl_)) {
|
||||||
terminate_session(NGHTTP2_INADEQUATE_SECURITY);
|
terminate_session(NGHTTP2_INADEQUATE_SECURITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1749,8 +1749,8 @@ void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config) {
|
|||||||
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
|
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
|
||||||
callbacks, verbose_on_invalid_frame_recv_callback);
|
callbacks, verbose_on_invalid_frame_recv_callback);
|
||||||
|
|
||||||
nghttp2_session_callbacks_set_error_callback(callbacks,
|
nghttp2_session_callbacks_set_error_callback2(callbacks,
|
||||||
verbose_error_callback);
|
verbose_error_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||||
@@ -1779,7 +1779,7 @@ struct ClientInfo {
|
|||||||
struct Worker {
|
struct Worker {
|
||||||
std::unique_ptr<Sessions> sessions;
|
std::unique_ptr<Sessions> sessions;
|
||||||
ev_async w;
|
ev_async w;
|
||||||
// protectes q
|
// protects q
|
||||||
std::mutex m;
|
std::mutex m;
|
||||||
std::deque<ClientInfo> q;
|
std::deque<ClientInfo> q;
|
||||||
};
|
};
|
||||||
@@ -2122,14 +2122,14 @@ int HttpServer::run() {
|
|||||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||||
|
|
||||||
if (nghttp2::ssl::ssl_ctx_set_proto_versions(
|
if (nghttp2::tls::ssl_ctx_set_proto_versions(
|
||||||
ssl_ctx, nghttp2::ssl::NGHTTP2_TLS_MIN_VERSION,
|
ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
|
||||||
nghttp2::ssl::NGHTTP2_TLS_MAX_VERSION) != 0) {
|
nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
|
||||||
std::cerr << "Could not set TLS versions" << std::endl;
|
std::cerr << "Could not set TLS versions" << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST) == 0) {
|
if (SSL_CTX_set_cipher_list(ssl_ctx, tls::DEFAULT_CIPHER_LIST) == 0) {
|
||||||
std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -2156,7 +2156,7 @@ int HttpServer::run() {
|
|||||||
}
|
}
|
||||||
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
|
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
|
||||||
EC_KEY_free(ecdh);
|
EC_KEY_free(ecdh);
|
||||||
// #endif // OPENSSL_VERSION_NUBMER < 0x10002000L
|
// #endif // OPENSSL_VERSION_NUBMER < 0x10002000L
|
||||||
|
|
||||||
#endif // OPENSSL_NO_EC
|
#endif // OPENSSL_NO_EC
|
||||||
|
|
||||||
@@ -2197,8 +2197,9 @@ int HttpServer::run() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (config_->verify_client) {
|
if (config_->verify_client) {
|
||||||
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE |
|
SSL_CTX_set_verify(ssl_ctx,
|
||||||
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE |
|
||||||
|
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||||
verify_callback);
|
verify_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ AM_CPPFLAGS = \
|
|||||||
-I$(top_srcdir)/lib \
|
-I$(top_srcdir)/lib \
|
||||||
-I$(top_srcdir)/src/includes \
|
-I$(top_srcdir)/src/includes \
|
||||||
-I$(top_srcdir)/third-party \
|
-I$(top_srcdir)/third-party \
|
||||||
@LIBSPDYLAY_CFLAGS@ \
|
|
||||||
@LIBXML2_CFLAGS@ \
|
@LIBXML2_CFLAGS@ \
|
||||||
@LIBEV_CFLAGS@ \
|
@LIBEV_CFLAGS@ \
|
||||||
@OPENSSL_CFLAGS@ \
|
@OPENSSL_CFLAGS@ \
|
||||||
@@ -52,7 +51,6 @@ AM_CPPFLAGS = \
|
|||||||
LDADD = $(top_builddir)/lib/libnghttp2.la \
|
LDADD = $(top_builddir)/lib/libnghttp2.la \
|
||||||
$(top_builddir)/third-party/libhttp-parser.la \
|
$(top_builddir)/third-party/libhttp-parser.la \
|
||||||
@JEMALLOC_LIBS@ \
|
@JEMALLOC_LIBS@ \
|
||||||
@LIBSPDYLAY_LIBS@ \
|
|
||||||
@LIBXML2_LIBS@ \
|
@LIBXML2_LIBS@ \
|
||||||
@LIBEV_LIBS@ \
|
@LIBEV_LIBS@ \
|
||||||
@OPENSSL_LIBS@ \
|
@OPENSSL_LIBS@ \
|
||||||
@@ -81,10 +79,10 @@ endif # HAVE_LIBXML2
|
|||||||
|
|
||||||
nghttp_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttp.cc nghttp.h \
|
nghttp_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttp.cc nghttp.h \
|
||||||
${HTML_PARSER_OBJECTS} ${HTML_PARSER_HFILES} \
|
${HTML_PARSER_OBJECTS} ${HTML_PARSER_HFILES} \
|
||||||
ssl.cc ssl.h
|
tls.cc tls.h
|
||||||
|
|
||||||
nghttpd_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttpd.cc \
|
nghttpd_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttpd.cc \
|
||||||
ssl.cc ssl.h \
|
tls.cc tls.h \
|
||||||
HttpServer.cc HttpServer.h
|
HttpServer.cc HttpServer.h
|
||||||
|
|
||||||
bin_PROGRAMS += h2load
|
bin_PROGRAMS += h2load
|
||||||
@@ -92,19 +90,15 @@ bin_PROGRAMS += h2load
|
|||||||
h2load_SOURCES = util.cc util.h \
|
h2load_SOURCES = util.cc util.h \
|
||||||
http2.cc http2.h h2load.cc h2load.h \
|
http2.cc http2.h h2load.cc h2load.h \
|
||||||
timegm.c timegm.h \
|
timegm.c timegm.h \
|
||||||
ssl.cc ssl.h \
|
tls.cc tls.h \
|
||||||
h2load_session.h \
|
h2load_session.h \
|
||||||
h2load_http2_session.cc h2load_http2_session.h \
|
h2load_http2_session.cc h2load_http2_session.h \
|
||||||
h2load_http1_session.cc h2load_http1_session.h
|
h2load_http1_session.cc h2load_http1_session.h
|
||||||
|
|
||||||
if HAVE_SPDYLAY
|
|
||||||
h2load_SOURCES += h2load_spdy_session.cc h2load_spdy_session.h
|
|
||||||
endif # HAVE_SPDYLAY
|
|
||||||
|
|
||||||
NGHTTPX_SRCS = \
|
NGHTTPX_SRCS = \
|
||||||
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \
|
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \
|
||||||
app_helper.cc app_helper.h \
|
app_helper.cc app_helper.h \
|
||||||
ssl.cc ssl.h \
|
tls.cc tls.h \
|
||||||
shrpx_config.cc shrpx_config.h \
|
shrpx_config.cc shrpx_config.h \
|
||||||
shrpx_error.h \
|
shrpx_error.h \
|
||||||
shrpx_accept_handler.cc shrpx_accept_handler.h \
|
shrpx_accept_handler.cc shrpx_accept_handler.h \
|
||||||
@@ -122,7 +116,7 @@ NGHTTPX_SRCS = \
|
|||||||
shrpx_log.cc shrpx_log.h \
|
shrpx_log.cc shrpx_log.h \
|
||||||
shrpx_http.cc shrpx_http.h \
|
shrpx_http.cc shrpx_http.h \
|
||||||
shrpx_io_control.cc shrpx_io_control.h \
|
shrpx_io_control.cc shrpx_io_control.h \
|
||||||
shrpx_ssl.cc shrpx_ssl.h \
|
shrpx_tls.cc shrpx_tls.h \
|
||||||
shrpx_worker.cc shrpx_worker.h \
|
shrpx_worker.cc shrpx_worker.h \
|
||||||
shrpx_log_config.cc shrpx_log_config.h \
|
shrpx_log_config.cc shrpx_log_config.h \
|
||||||
shrpx_connect_blocker.cc shrpx_connect_blocker.h \
|
shrpx_connect_blocker.cc shrpx_connect_blocker.h \
|
||||||
@@ -148,10 +142,6 @@ NGHTTPX_SRCS = \
|
|||||||
buffer.h memchunk.h template.h allocator.h \
|
buffer.h memchunk.h template.h allocator.h \
|
||||||
xsi_strerror.c xsi_strerror.h
|
xsi_strerror.c xsi_strerror.h
|
||||||
|
|
||||||
if HAVE_SPDYLAY
|
|
||||||
NGHTTPX_SRCS += shrpx_spdy_upstream.cc shrpx_spdy_upstream.h
|
|
||||||
endif # HAVE_SPDYLAY
|
|
||||||
|
|
||||||
if HAVE_MRUBY
|
if HAVE_MRUBY
|
||||||
NGHTTPX_SRCS += \
|
NGHTTPX_SRCS += \
|
||||||
shrpx_mruby.cc shrpx_mruby.h \
|
shrpx_mruby.cc shrpx_mruby.h \
|
||||||
@@ -183,7 +173,7 @@ endif # HAVE_NEVERBLEED
|
|||||||
if HAVE_CUNIT
|
if HAVE_CUNIT
|
||||||
check_PROGRAMS += nghttpx-unittest
|
check_PROGRAMS += nghttpx-unittest
|
||||||
nghttpx_unittest_SOURCES = shrpx-unittest.cc \
|
nghttpx_unittest_SOURCES = shrpx-unittest.cc \
|
||||||
shrpx_ssl_test.cc shrpx_ssl_test.h \
|
shrpx_tls_test.cc shrpx_tls_test.h \
|
||||||
shrpx_downstream_test.cc shrpx_downstream_test.h \
|
shrpx_downstream_test.cc shrpx_downstream_test.h \
|
||||||
shrpx_config_test.cc shrpx_config_test.h \
|
shrpx_config_test.cc shrpx_config_test.h \
|
||||||
shrpx_worker_test.cc shrpx_worker_test.h \
|
shrpx_worker_test.cc shrpx_worker_test.h \
|
||||||
@@ -240,7 +230,7 @@ lib_LTLIBRARIES = libnghttp2_asio.la
|
|||||||
|
|
||||||
libnghttp2_asio_la_SOURCES = \
|
libnghttp2_asio_la_SOURCES = \
|
||||||
util.cc util.h http2.cc http2.h \
|
util.cc util.h http2.cc http2.h \
|
||||||
ssl.cc ssl.h \
|
tls.cc tls.h \
|
||||||
ssl_compat.h \
|
ssl_compat.h \
|
||||||
timegm.c timegm.h \
|
timegm.c timegm.h \
|
||||||
asio_common.cc asio_common.h \
|
asio_common.cc asio_common.h \
|
||||||
|
|||||||
@@ -27,7 +27,9 @@
|
|||||||
|
|
||||||
#include "nghttp2_config.h"
|
#include "nghttp2_config.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
#endif // !_WIN32
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
@@ -271,6 +273,6 @@ ByteRef make_byte_ref(BlockAllocator &alloc, size_t size) {
|
|||||||
return {dst, size};
|
return {dst, size};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace nghttp2
|
||||||
|
|
||||||
#endif // ALLOCATOR_H
|
#endif // ALLOCATOR_H
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ void print_nv(nghttp2_nv *nva, size_t nvlen) {
|
|||||||
print_nv(nva);
|
print_nv(nva);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namelen
|
} // namespace
|
||||||
|
|
||||||
void print_timer() {
|
void print_timer() {
|
||||||
auto millis = get_timer();
|
auto millis = get_timer();
|
||||||
@@ -327,8 +327,9 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) {
|
|||||||
break;
|
break;
|
||||||
case NGHTTP2_GOAWAY:
|
case NGHTTP2_GOAWAY:
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
fprintf(outfile, "(last_stream_id=%d, error_code=%s(0x%02x), "
|
fprintf(outfile,
|
||||||
"opaque_data(%u)=[%s])\n",
|
"(last_stream_id=%d, error_code=%s(0x%02x), "
|
||||||
|
"opaque_data(%u)=[%s])\n",
|
||||||
frame->goaway.last_stream_id,
|
frame->goaway.last_stream_id,
|
||||||
nghttp2_http2_strerror(frame->goaway.error_code),
|
nghttp2_http2_strerror(frame->goaway.error_code),
|
||||||
frame->goaway.error_code,
|
frame->goaway.error_code,
|
||||||
@@ -425,8 +426,8 @@ int verbose_on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int verbose_error_callback(nghttp2_session *session, const char *msg,
|
int verbose_error_callback(nghttp2_session *session, int lib_error_code,
|
||||||
size_t len, void *user_data) {
|
const char *msg, size_t len, void *user_data) {
|
||||||
print_timer();
|
print_timer();
|
||||||
fprintf(outfile, " [ERROR] %.*s\n", (int)len, msg);
|
fprintf(outfile, " [ERROR] %.*s\n", (int)len, msg);
|
||||||
fflush(outfile);
|
fflush(outfile);
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ int verbose_on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
|||||||
int32_t stream_id, const uint8_t *data,
|
int32_t stream_id, const uint8_t *data,
|
||||||
size_t len, void *user_data);
|
size_t len, void *user_data);
|
||||||
|
|
||||||
int verbose_error_callback(nghttp2_session *session, const char *msg,
|
int verbose_error_callback(nghttp2_session *session, int lib_error_code,
|
||||||
size_t len, void *user_data);
|
const char *msg, size_t len, void *user_data);
|
||||||
|
|
||||||
// Returns difference between |a| and |b| in milliseconds, assuming
|
// Returns difference between |a| and |b| in milliseconds, assuming
|
||||||
// |a| is more recent than |b|.
|
// |a| is more recent than |b|.
|
||||||
|
|||||||
@@ -96,29 +96,48 @@ boost::asio::io_service &session::io_service() const {
|
|||||||
|
|
||||||
const request *session::submit(boost::system::error_code &ec,
|
const request *session::submit(boost::system::error_code &ec,
|
||||||
const std::string &method,
|
const std::string &method,
|
||||||
const std::string &uri, header_map h) const {
|
const std::string &uri, header_map h,
|
||||||
return impl_->submit(ec, method, uri, generator_cb(), std::move(h));
|
priority_spec prio) const {
|
||||||
|
return impl_->submit(ec, method, uri, generator_cb(), std::move(h),
|
||||||
|
std::move(prio));
|
||||||
}
|
}
|
||||||
|
|
||||||
const request *session::submit(boost::system::error_code &ec,
|
const request *session::submit(boost::system::error_code &ec,
|
||||||
const std::string &method,
|
const std::string &method,
|
||||||
const std::string &uri, std::string data,
|
const std::string &uri, std::string data,
|
||||||
header_map h) const {
|
header_map h, priority_spec prio) const {
|
||||||
return impl_->submit(ec, method, uri, string_generator(std::move(data)),
|
return impl_->submit(ec, method, uri, string_generator(std::move(data)),
|
||||||
std::move(h));
|
std::move(h), std::move(prio));
|
||||||
}
|
}
|
||||||
|
|
||||||
const request *session::submit(boost::system::error_code &ec,
|
const request *session::submit(boost::system::error_code &ec,
|
||||||
const std::string &method,
|
const std::string &method,
|
||||||
const std::string &uri, generator_cb cb,
|
const std::string &uri, generator_cb cb,
|
||||||
header_map h) const {
|
header_map h, priority_spec prio) const {
|
||||||
return impl_->submit(ec, method, uri, std::move(cb), std::move(h));
|
return impl_->submit(ec, method, uri, std::move(cb), std::move(h),
|
||||||
|
std::move(prio));
|
||||||
}
|
}
|
||||||
|
|
||||||
void session::read_timeout(const boost::posix_time::time_duration &t) {
|
void session::read_timeout(const boost::posix_time::time_duration &t) {
|
||||||
impl_->read_timeout(t);
|
impl_->read_timeout(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priority_spec::priority_spec(const int32_t stream_id, const int32_t weight,
|
||||||
|
const bool exclusive)
|
||||||
|
: valid_(true) {
|
||||||
|
nghttp2_priority_spec_init(&spec_, stream_id, weight, exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nghttp2_priority_spec *priority_spec::get() const {
|
||||||
|
if (!valid_) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &spec_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool priority_spec::valid() const { return valid_; }
|
||||||
|
|
||||||
} // namespace client
|
} // namespace client
|
||||||
} // namespace asio_http2
|
} // namespace asio_http2
|
||||||
} // nghttp2
|
} // namespace nghttp2
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ session_impl::session_impl(
|
|||||||
deadline_(io_service),
|
deadline_(io_service),
|
||||||
connect_timeout_(connect_timeout),
|
connect_timeout_(connect_timeout),
|
||||||
read_timeout_(boost::posix_time::seconds(60)),
|
read_timeout_(boost::posix_time::seconds(60)),
|
||||||
|
ping_(io_service),
|
||||||
session_(nullptr),
|
session_(nullptr),
|
||||||
data_pending_(nullptr),
|
data_pending_(nullptr),
|
||||||
data_pendinglen_(0),
|
data_pendinglen_(0),
|
||||||
@@ -102,6 +103,27 @@ void session_impl::handle_deadline() {
|
|||||||
std::bind(&session_impl::handle_deadline, this->shared_from_this()));
|
std::bind(&session_impl::handle_deadline, this->shared_from_this()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handle_ping2(const boost::system::error_code &ec, int) {}
|
||||||
|
|
||||||
|
void session_impl::start_ping() {
|
||||||
|
ping_.expires_from_now(boost::posix_time::seconds(30));
|
||||||
|
ping_.async_wait(std::bind(&session_impl::handle_ping, shared_from_this(),
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_impl::handle_ping(const boost::system::error_code &ec) {
|
||||||
|
if (stopped_ || ec == boost::asio::error::operation_aborted ||
|
||||||
|
!streams_.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_submit_ping(session_, NGHTTP2_FLAG_NONE, nullptr);
|
||||||
|
|
||||||
|
signal_write();
|
||||||
|
|
||||||
|
start_ping();
|
||||||
|
}
|
||||||
|
|
||||||
void session_impl::connected(tcp::resolver::iterator endpoint_it) {
|
void session_impl::connected(tcp::resolver::iterator endpoint_it) {
|
||||||
if (!setup_session()) {
|
if (!setup_session()) {
|
||||||
return;
|
return;
|
||||||
@@ -112,6 +134,8 @@ void session_impl::connected(tcp::resolver::iterator endpoint_it) {
|
|||||||
do_write();
|
do_write();
|
||||||
do_read();
|
do_read();
|
||||||
|
|
||||||
|
start_ping();
|
||||||
|
|
||||||
auto &connect_cb = on_connect();
|
auto &connect_cb = on_connect();
|
||||||
if (connect_cb) {
|
if (connect_cb) {
|
||||||
connect_cb(endpoint_it);
|
connect_cb(endpoint_it);
|
||||||
@@ -433,6 +457,9 @@ std::unique_ptr<stream> session_impl::pop_stream(int32_t stream_id) {
|
|||||||
}
|
}
|
||||||
auto strm = std::move((*it).second);
|
auto strm = std::move((*it).second);
|
||||||
streams_.erase(it);
|
streams_.erase(it);
|
||||||
|
if (streams_.empty()) {
|
||||||
|
start_ping();
|
||||||
|
}
|
||||||
return strm;
|
return strm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,6 +468,7 @@ stream *session_impl::create_push_stream(int32_t stream_id) {
|
|||||||
strm->stream_id(stream_id);
|
strm->stream_id(stream_id);
|
||||||
auto p = streams_.emplace(stream_id, std::move(strm));
|
auto p = streams_.emplace(stream_id, std::move(strm));
|
||||||
assert(p.second);
|
assert(p.second);
|
||||||
|
ping_.cancel();
|
||||||
return (*p.first).second.get();
|
return (*p.first).second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,7 +479,7 @@ std::unique_ptr<stream> session_impl::create_stream() {
|
|||||||
const request *session_impl::submit(boost::system::error_code &ec,
|
const request *session_impl::submit(boost::system::error_code &ec,
|
||||||
const std::string &method,
|
const std::string &method,
|
||||||
const std::string &uri, generator_cb cb,
|
const std::string &uri, generator_cb cb,
|
||||||
header_map h) {
|
header_map h, priority_spec prio) {
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
|
||||||
if (stopped_) {
|
if (stopped_) {
|
||||||
@@ -531,7 +559,7 @@ const request *session_impl::submit(boost::system::error_code &ec,
|
|||||||
prdptr = &prd;
|
prdptr = &prd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto stream_id = nghttp2_submit_request(session_, nullptr, nva.data(),
|
auto stream_id = nghttp2_submit_request(session_, prio.get(), nva.data(),
|
||||||
nva.size(), prdptr, strm.get());
|
nva.size(), prdptr, strm.get());
|
||||||
if (stream_id < 0) {
|
if (stream_id < 0) {
|
||||||
ec = make_error_code(static_cast<nghttp2_error>(stream_id));
|
ec = make_error_code(static_cast<nghttp2_error>(stream_id));
|
||||||
@@ -544,6 +572,7 @@ const request *session_impl::submit(boost::system::error_code &ec,
|
|||||||
|
|
||||||
auto p = streams_.emplace(stream_id, std::move(strm));
|
auto p = streams_.emplace(stream_id, std::move(strm));
|
||||||
assert(p.second);
|
assert(p.second);
|
||||||
|
ping_.cancel();
|
||||||
return &(*p.first).second->request();
|
return &(*p.first).second->request();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -715,6 +744,7 @@ void session_impl::stop() {
|
|||||||
|
|
||||||
shutdown_socket();
|
shutdown_socket();
|
||||||
deadline_.cancel();
|
deadline_.cancel();
|
||||||
|
ping_.cancel();
|
||||||
stopped_ = true;
|
stopped_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -726,4 +756,4 @@ void session_impl::read_timeout(const boost::posix_time::time_duration &t) {
|
|||||||
|
|
||||||
} // namespace client
|
} // namespace client
|
||||||
} // namespace asio_http2
|
} // namespace asio_http2
|
||||||
} // nghttp2
|
} // namespace nghttp2
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public:
|
|||||||
|
|
||||||
const request *submit(boost::system::error_code &ec,
|
const request *submit(boost::system::error_code &ec,
|
||||||
const std::string &method, const std::string &uri,
|
const std::string &method, const std::string &uri,
|
||||||
generator_cb cb, header_map h);
|
generator_cb cb, header_map h, priority_spec spec);
|
||||||
|
|
||||||
virtual void start_connect(tcp::resolver::iterator endpoint_it) = 0;
|
virtual void start_connect(tcp::resolver::iterator endpoint_it) = 0;
|
||||||
virtual tcp::socket &socket() = 0;
|
virtual tcp::socket &socket() = 0;
|
||||||
@@ -109,6 +109,8 @@ private:
|
|||||||
bool setup_session();
|
bool setup_session();
|
||||||
void call_error_cb(const boost::system::error_code &ec);
|
void call_error_cb(const boost::system::error_code &ec);
|
||||||
void handle_deadline();
|
void handle_deadline();
|
||||||
|
void start_ping();
|
||||||
|
void handle_ping(const boost::system::error_code &ec);
|
||||||
|
|
||||||
boost::asio::io_service &io_service_;
|
boost::asio::io_service &io_service_;
|
||||||
tcp::resolver resolver_;
|
tcp::resolver resolver_;
|
||||||
@@ -122,6 +124,8 @@ private:
|
|||||||
boost::posix_time::time_duration connect_timeout_;
|
boost::posix_time::time_duration connect_timeout_;
|
||||||
boost::posix_time::time_duration read_timeout_;
|
boost::posix_time::time_duration read_timeout_;
|
||||||
|
|
||||||
|
boost::asio::deadline_timer ping_;
|
||||||
|
|
||||||
nghttp2_session *session_;
|
nghttp2_session *session_;
|
||||||
|
|
||||||
const uint8_t *data_pending_;
|
const uint8_t *data_pending_;
|
||||||
|
|||||||
@@ -45,8 +45,9 @@ session_tls_impl::~session_tls_impl() {}
|
|||||||
void session_tls_impl::start_connect(tcp::resolver::iterator endpoint_it) {
|
void session_tls_impl::start_connect(tcp::resolver::iterator endpoint_it) {
|
||||||
auto self = std::static_pointer_cast<session_tls_impl>(shared_from_this());
|
auto self = std::static_pointer_cast<session_tls_impl>(shared_from_this());
|
||||||
boost::asio::async_connect(
|
boost::asio::async_connect(
|
||||||
socket(), endpoint_it, [self](const boost::system::error_code &ec,
|
socket(), endpoint_it,
|
||||||
tcp::resolver::iterator endpoint_it) {
|
[self](const boost::system::error_code &ec,
|
||||||
|
tcp::resolver::iterator endpoint_it) {
|
||||||
if (self->stopped()) {
|
if (self->stopped()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
#include <boost/asio/ssl.hpp>
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
#include "ssl.h"
|
#include "tls.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "asio_common.h"
|
#include "asio_common.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|||||||
@@ -169,6 +169,6 @@ private:
|
|||||||
|
|
||||||
} // namespace server
|
} // namespace server
|
||||||
} // namespace asio_http2
|
} // namespace asio_http2
|
||||||
} // namespace nghttp
|
} // namespace nghttp2
|
||||||
|
|
||||||
#endif // ASIO_SERVER_HTTP2_HANDLER_H
|
#endif // ASIO_SERVER_HTTP2_HANDLER_H
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
#include "asio_server.h"
|
#include "asio_server.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ssl.h"
|
#include "tls.h"
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
#include <boost/asio/ssl.hpp>
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
#include "ssl.h"
|
#include "tls.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
@@ -72,7 +72,7 @@ configure_tls_context_easy(boost::system::error_code &ec,
|
|||||||
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
|
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
|
||||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||||
|
|
||||||
SSL_CTX_set_cipher_list(ctx, ssl::DEFAULT_CIPHER_LIST);
|
SSL_CTX_set_cipher_list(ctx, tls::DEFAULT_CIPHER_LIST);
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_EC
|
#ifndef OPENSSL_NO_EC
|
||||||
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||||
|
|||||||
584
src/h2load.cc
584
src/h2load.cc
File diff suppressed because it is too large
Load Diff
49
src/h2load.h
49
src/h2load.h
@@ -64,7 +64,6 @@ struct Worker;
|
|||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
std::vector<std::vector<nghttp2_nv>> nva;
|
std::vector<std::vector<nghttp2_nv>> nva;
|
||||||
std::vector<std::vector<const char *>> nv;
|
|
||||||
std::vector<std::string> h1reqs;
|
std::vector<std::string> h1reqs;
|
||||||
std::vector<ev_tstamp> timings;
|
std::vector<ev_tstamp> timings;
|
||||||
nghttp2::Headers custom_headers;
|
nghttp2::Headers custom_headers;
|
||||||
@@ -85,17 +84,15 @@ struct Config {
|
|||||||
// rate at which connections should be made
|
// rate at which connections should be made
|
||||||
size_t rate;
|
size_t rate;
|
||||||
ev_tstamp rate_period;
|
ev_tstamp rate_period;
|
||||||
|
// amount of time for main measurements in timing-based test
|
||||||
|
ev_tstamp duration;
|
||||||
|
// amount of time to wait before starting measurements in timing-based test
|
||||||
|
ev_tstamp warm_up_time;
|
||||||
// amount of time to wait for activity on a given connection
|
// amount of time to wait for activity on a given connection
|
||||||
ev_tstamp conn_active_timeout;
|
ev_tstamp conn_active_timeout;
|
||||||
// amount of time to wait after the last request is made on a connection
|
// amount of time to wait after the last request is made on a connection
|
||||||
ev_tstamp conn_inactivity_timeout;
|
ev_tstamp conn_inactivity_timeout;
|
||||||
enum {
|
enum { PROTO_HTTP2, PROTO_HTTP1_1 } no_tls_proto;
|
||||||
PROTO_HTTP2,
|
|
||||||
PROTO_SPDY2,
|
|
||||||
PROTO_SPDY3,
|
|
||||||
PROTO_SPDY3_1,
|
|
||||||
PROTO_HTTP1_1
|
|
||||||
} no_tls_proto;
|
|
||||||
uint32_t header_table_size;
|
uint32_t header_table_size;
|
||||||
uint32_t encoder_header_table_size;
|
uint32_t encoder_header_table_size;
|
||||||
// file descriptor for upload data
|
// file descriptor for upload data
|
||||||
@@ -118,6 +115,7 @@ struct Config {
|
|||||||
~Config();
|
~Config();
|
||||||
|
|
||||||
bool is_rate_mode() const;
|
bool is_rate_mode() const;
|
||||||
|
bool is_timing_based_mode() const;
|
||||||
bool has_base_uri() const;
|
bool has_base_uri() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -139,7 +137,7 @@ struct ClientStat {
|
|||||||
// time client end (i.e., client somehow processed all requests it
|
// time client end (i.e., client somehow processed all requests it
|
||||||
// is responsible for, and disconnected)
|
// is responsible for, and disconnected)
|
||||||
std::chrono::steady_clock::time_point client_end_time;
|
std::chrono::steady_clock::time_point client_end_time;
|
||||||
// The number of requests completed successfull, but not necessarily
|
// The number of requests completed successful, but not necessarily
|
||||||
// means successful HTTP status code.
|
// means successful HTTP status code.
|
||||||
size_t req_success;
|
size_t req_success;
|
||||||
|
|
||||||
@@ -180,7 +178,7 @@ struct Stats {
|
|||||||
size_t req_started;
|
size_t req_started;
|
||||||
// The number of requests finished
|
// The number of requests finished
|
||||||
size_t req_done;
|
size_t req_done;
|
||||||
// The number of requests completed successfull, but not necessarily
|
// The number of requests completed successful, but not necessarily
|
||||||
// means successful HTTP status code.
|
// means successful HTTP status code.
|
||||||
size_t req_success;
|
size_t req_success;
|
||||||
// The number of requests marked as success. HTTP status code is
|
// The number of requests marked as success. HTTP status code is
|
||||||
@@ -215,15 +213,21 @@ struct Stats {
|
|||||||
|
|
||||||
enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
|
enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
|
||||||
|
|
||||||
|
// This type tells whether the client is in warmup phase or not or is over
|
||||||
|
enum class Phase {
|
||||||
|
INITIAL_IDLE, // Initial idle state before warm-up phase
|
||||||
|
WARM_UP, // Warm up phase when no measurements are done
|
||||||
|
MAIN_DURATION, // Main measurement phase; if timing-based
|
||||||
|
// test is not run, this is the default phase
|
||||||
|
DURATION_OVER // This phase occurs after the measurements are over
|
||||||
|
};
|
||||||
|
|
||||||
struct Client;
|
struct Client;
|
||||||
|
|
||||||
// We use systematic sampling method
|
// We use reservoir sampling method
|
||||||
struct Sampling {
|
struct Sampling {
|
||||||
// sampling interval
|
// maximum number of samples
|
||||||
double interval;
|
size_t max_samples;
|
||||||
// cumulative value of interval, and the next point is the integer
|
|
||||||
// rounded up from this value.
|
|
||||||
double point;
|
|
||||||
// number of samples seen, including discarded samples.
|
// number of samples seen, including discarded samples.
|
||||||
size_t n;
|
size_t n;
|
||||||
};
|
};
|
||||||
@@ -253,6 +257,15 @@ struct Worker {
|
|||||||
ev_timer timeout_watcher;
|
ev_timer timeout_watcher;
|
||||||
// The next client ID this worker assigns
|
// The next client ID this worker assigns
|
||||||
uint32_t next_client_id;
|
uint32_t next_client_id;
|
||||||
|
// Keeps track of the current phase (for timing-based experiment) for the
|
||||||
|
// worker
|
||||||
|
Phase current_phase;
|
||||||
|
// We need to keep track of the clients in order to stop them when needed
|
||||||
|
std::vector<Client *> clients;
|
||||||
|
// This is only active when there is not a bounded number of requests
|
||||||
|
// specified
|
||||||
|
ev_timer duration_watcher;
|
||||||
|
ev_timer warmup_watcher;
|
||||||
|
|
||||||
Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t nreq_todo, size_t nclients,
|
Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t nreq_todo, size_t nclients,
|
||||||
size_t rate, size_t max_samples, Config *config);
|
size_t rate, size_t max_samples, Config *config);
|
||||||
@@ -263,6 +276,10 @@ struct Worker {
|
|||||||
void sample_client_stat(ClientStat *cstat);
|
void sample_client_stat(ClientStat *cstat);
|
||||||
void report_progress();
|
void report_progress();
|
||||||
void report_rate_progress();
|
void report_rate_progress();
|
||||||
|
// This function calls the destructors of all the clients.
|
||||||
|
void stop_all_clients();
|
||||||
|
// This function frees a client from the list of clients for this Worker.
|
||||||
|
void free_client(Client *);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stream {
|
struct Stream {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "h2load.h"
|
#include "h2load.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -52,6 +53,15 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
|||||||
}
|
}
|
||||||
client->on_header(frame->hd.stream_id, name, namelen, value, valuelen);
|
client->on_header(frame->hd.stream_id, name, namelen, value, valuelen);
|
||||||
client->worker->stats.bytes_head_decomp += namelen + valuelen;
|
client->worker->stats.bytes_head_decomp += namelen + valuelen;
|
||||||
|
|
||||||
|
if (client->worker->config->verbose) {
|
||||||
|
std::cout << "[stream_id=" << frame->hd.stream_id << "] ";
|
||||||
|
std::cout.write(reinterpret_cast<const char *>(name), namelen);
|
||||||
|
std::cout << ": ";
|
||||||
|
std::cout.write(reinterpret_cast<const char *>(value), valuelen);
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -180,6 +190,9 @@ ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
|
|||||||
void Http2Session::on_connect() {
|
void Http2Session::on_connect() {
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
|
// This is required with --disable-assert.
|
||||||
|
(void)rv;
|
||||||
|
|
||||||
nghttp2_session_callbacks *callbacks;
|
nghttp2_session_callbacks *callbacks;
|
||||||
|
|
||||||
nghttp2_session_callbacks_new(&callbacks);
|
nghttp2_session_callbacks_new(&callbacks);
|
||||||
|
|||||||
@@ -1,289 +0,0 @@
|
|||||||
/*
|
|
||||||
* nghttp2 - HTTP/2 C Library
|
|
||||||
*
|
|
||||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "h2load_spdy_session.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cerrno>
|
|
||||||
|
|
||||||
#include "h2load.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
using namespace nghttp2;
|
|
||||||
|
|
||||||
namespace h2load {
|
|
||||||
|
|
||||||
SpdySession::SpdySession(Client *client, uint16_t spdy_version)
|
|
||||||
: client_(client), session_(nullptr), spdy_version_(spdy_version) {}
|
|
||||||
|
|
||||||
SpdySession::~SpdySession() { spdylay_session_del(session_); }
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
void before_ctrl_send_callback(spdylay_session *session,
|
|
||||||
spdylay_frame_type type, spdylay_frame *frame,
|
|
||||||
void *user_data) {
|
|
||||||
auto client = static_cast<Client *>(user_data);
|
|
||||||
if (type != SPDYLAY_SYN_STREAM) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
client->on_request(frame->syn_stream.stream_id);
|
|
||||||
auto req_stat = client->get_req_stat(frame->syn_stream.stream_id);
|
|
||||||
client->record_request_time(req_stat);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
|
|
||||||
spdylay_frame *frame, void *user_data) {
|
|
||||||
auto client = static_cast<Client *>(user_data);
|
|
||||||
if (type != SPDYLAY_SYN_REPLY) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (auto p = frame->syn_reply.nv; *p; p += 2) {
|
|
||||||
auto name = *p;
|
|
||||||
auto value = *(p + 1);
|
|
||||||
auto namelen = strlen(name);
|
|
||||||
auto valuelen = strlen(value);
|
|
||||||
client->on_header(frame->syn_reply.stream_id,
|
|
||||||
reinterpret_cast<const uint8_t *>(name), namelen,
|
|
||||||
reinterpret_cast<const uint8_t *>(value), valuelen);
|
|
||||||
client->worker->stats.bytes_head_decomp += namelen + valuelen;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strictly speaking, we have to subtract 2 (unused field) if SPDY
|
|
||||||
// version is 2. But it is already deprecated, and we don't do
|
|
||||||
// extra work for it.
|
|
||||||
client->worker->stats.bytes_head += frame->syn_reply.hd.length - 4;
|
|
||||||
|
|
||||||
if (frame->syn_stream.hd.flags & SPDYLAY_CTRL_FLAG_FIN) {
|
|
||||||
client->record_ttfb();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags,
|
|
||||||
int32_t stream_id, const uint8_t *data,
|
|
||||||
size_t len, void *user_data) {
|
|
||||||
auto client = static_cast<Client *>(user_data);
|
|
||||||
|
|
||||||
client->record_ttfb();
|
|
||||||
client->worker->stats.bytes_body += len;
|
|
||||||
|
|
||||||
auto spdy_session = static_cast<SpdySession *>(client->session.get());
|
|
||||||
|
|
||||||
spdy_session->handle_window_update(stream_id, len);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
void on_stream_close_callback(spdylay_session *session, int32_t stream_id,
|
|
||||||
spdylay_status_code status_code,
|
|
||||||
void *user_data) {
|
|
||||||
auto client = static_cast<Client *>(user_data);
|
|
||||||
client->on_stream_close(stream_id, status_code == SPDYLAY_OK);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
ssize_t send_callback(spdylay_session *session, const uint8_t *data,
|
|
||||||
size_t length, int flags, void *user_data) {
|
|
||||||
auto client = static_cast<Client *>(user_data);
|
|
||||||
auto &wb = client->wb;
|
|
||||||
|
|
||||||
if (wb.rleft() >= BACKOFF_WRITE_BUFFER_THRES) {
|
|
||||||
return SPDYLAY_ERR_WOULDBLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wb.append(data, length);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
ssize_t file_read_callback(spdylay_session *session, int32_t stream_id,
|
|
||||||
uint8_t *buf, size_t length, int *eof,
|
|
||||||
spdylay_data_source *source, void *user_data) {
|
|
||||||
auto client = static_cast<Client *>(user_data);
|
|
||||||
auto config = client->worker->config;
|
|
||||||
auto req_stat = client->get_req_stat(stream_id);
|
|
||||||
|
|
||||||
ssize_t nread;
|
|
||||||
while ((nread = pread(config->data_fd, buf, length, req_stat->data_offset)) ==
|
|
||||||
-1 &&
|
|
||||||
errno == EINTR)
|
|
||||||
;
|
|
||||||
|
|
||||||
if (nread == -1) {
|
|
||||||
return SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
req_stat->data_offset += nread;
|
|
||||||
|
|
||||||
if (nread == 0 || req_stat->data_offset == config->data_length) {
|
|
||||||
*eof = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nread;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void SpdySession::on_connect() {
|
|
||||||
spdylay_session_callbacks callbacks = {0};
|
|
||||||
callbacks.send_callback = send_callback;
|
|
||||||
callbacks.before_ctrl_send_callback = before_ctrl_send_callback;
|
|
||||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
|
||||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
|
||||||
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
|
|
||||||
|
|
||||||
spdylay_session_client_new(&session_, spdy_version_, &callbacks, client_);
|
|
||||||
|
|
||||||
int val = 1;
|
|
||||||
spdylay_session_set_option(session_, SPDYLAY_OPT_NO_AUTO_WINDOW_UPDATE, &val,
|
|
||||||
sizeof(val));
|
|
||||||
|
|
||||||
spdylay_settings_entry iv;
|
|
||||||
iv.settings_id = SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE;
|
|
||||||
iv.flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
|
||||||
iv.value = (1 << client_->worker->config->window_bits);
|
|
||||||
spdylay_submit_settings(session_, SPDYLAY_FLAG_SETTINGS_NONE, &iv, 1);
|
|
||||||
|
|
||||||
auto config = client_->worker->config;
|
|
||||||
|
|
||||||
if (spdy_version_ >= SPDYLAY_PROTO_SPDY3_1 &&
|
|
||||||
config->connection_window_bits > 16) {
|
|
||||||
auto delta =
|
|
||||||
(1 << config->connection_window_bits) - SPDYLAY_INITIAL_WINDOW_SIZE;
|
|
||||||
spdylay_submit_window_update(session_, 0, delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
client_->signal_write();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SpdySession::submit_request() {
|
|
||||||
int rv;
|
|
||||||
auto config = client_->worker->config;
|
|
||||||
auto &nv = config->nv[client_->reqidx++];
|
|
||||||
|
|
||||||
if (client_->reqidx == config->nv.size()) {
|
|
||||||
client_->reqidx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
spdylay_data_provider prd{{0}, file_read_callback};
|
|
||||||
|
|
||||||
rv = spdylay_submit_request(session_, 0, nv.data(),
|
|
||||||
config->data_fd == -1 ? nullptr : &prd, nullptr);
|
|
||||||
|
|
||||||
if (rv != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SpdySession::on_read(const uint8_t *data, size_t len) {
|
|
||||||
auto rv = spdylay_session_mem_recv(session_, data, len);
|
|
||||||
if (rv < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(static_cast<size_t>(rv) == len);
|
|
||||||
|
|
||||||
if (spdylay_session_want_read(session_) == 0 &&
|
|
||||||
spdylay_session_want_write(session_) == 0 && client_->wb.rleft() == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
client_->signal_write();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SpdySession::on_write() {
|
|
||||||
auto rv = spdylay_session_send(session_);
|
|
||||||
if (rv != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spdylay_session_want_read(session_) == 0 &&
|
|
||||||
spdylay_session_want_write(session_) == 0 && client_->wb.rleft() == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpdySession::terminate() {
|
|
||||||
spdylay_session_fail_session(session_, SPDYLAY_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
int32_t determine_window_update_transmission(spdylay_session *session,
|
|
||||||
int32_t stream_id,
|
|
||||||
size_t window_bits) {
|
|
||||||
int32_t recv_length;
|
|
||||||
|
|
||||||
if (stream_id == 0) {
|
|
||||||
recv_length = spdylay_session_get_recv_data_length(session);
|
|
||||||
} else {
|
|
||||||
recv_length =
|
|
||||||
spdylay_session_get_stream_recv_data_length(session, stream_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto window_size = 1 << window_bits;
|
|
||||||
|
|
||||||
if (recv_length != -1 && recv_length >= window_size / 2) {
|
|
||||||
return recv_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void SpdySession::handle_window_update(int32_t stream_id, size_t recvlen) {
|
|
||||||
auto config = client_->worker->config;
|
|
||||||
size_t connection_window_bits;
|
|
||||||
|
|
||||||
if (config->connection_window_bits > 16) {
|
|
||||||
connection_window_bits = config->connection_window_bits;
|
|
||||||
} else {
|
|
||||||
connection_window_bits = 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto delta =
|
|
||||||
determine_window_update_transmission(session_, 0, connection_window_bits);
|
|
||||||
if (delta > 0) {
|
|
||||||
spdylay_submit_window_update(session_, 0, delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
delta = determine_window_update_transmission(session_, stream_id,
|
|
||||||
config->window_bits);
|
|
||||||
if (delta > 0) {
|
|
||||||
spdylay_submit_window_update(session_, stream_id, delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SpdySession::max_concurrent_streams() {
|
|
||||||
return (size_t)client_->worker->config->max_concurrent_streams;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace h2load
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* nghttp2 - HTTP/2 C Library
|
|
||||||
*
|
|
||||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef H2LOAD_SPDY_SESSION_H
|
|
||||||
#define H2LOAD_SPDY_SESSION_H
|
|
||||||
|
|
||||||
#include "h2load_session.h"
|
|
||||||
|
|
||||||
#include <spdylay/spdylay.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
namespace h2load {
|
|
||||||
|
|
||||||
struct Client;
|
|
||||||
|
|
||||||
class SpdySession : public Session {
|
|
||||||
public:
|
|
||||||
SpdySession(Client *client, uint16_t spdy_version);
|
|
||||||
virtual ~SpdySession();
|
|
||||||
virtual void on_connect();
|
|
||||||
virtual int submit_request();
|
|
||||||
virtual int on_read(const uint8_t *data, size_t len);
|
|
||||||
virtual int on_write();
|
|
||||||
virtual void terminate();
|
|
||||||
virtual size_t max_concurrent_streams();
|
|
||||||
void handle_window_update(int32_t stream_id, size_t recvlen);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Client *client_;
|
|
||||||
spdylay_session *session_;
|
|
||||||
uint16_t spdy_version_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace h2load
|
|
||||||
|
|
||||||
#endif // H2LOAD_SPDY_SESSION_H
|
|
||||||
166
src/http2.cc
166
src/http2.cc
@@ -36,6 +36,8 @@ StringRef get_reason_phrase(unsigned int status_code) {
|
|||||||
return StringRef::from_lit("Continue");
|
return StringRef::from_lit("Continue");
|
||||||
case 101:
|
case 101:
|
||||||
return StringRef::from_lit("Switching Protocols");
|
return StringRef::from_lit("Switching Protocols");
|
||||||
|
case 103:
|
||||||
|
return StringRef::from_lit("Early Hints");
|
||||||
case 200:
|
case 200:
|
||||||
return StringRef::from_lit("OK");
|
return StringRef::from_lit("OK");
|
||||||
case 201:
|
case 201:
|
||||||
@@ -140,6 +142,8 @@ StringRef stringify_status(BlockAllocator &balloc, unsigned int status_code) {
|
|||||||
return StringRef::from_lit("100");
|
return StringRef::from_lit("100");
|
||||||
case 101:
|
case 101:
|
||||||
return StringRef::from_lit("101");
|
return StringRef::from_lit("101");
|
||||||
|
case 103:
|
||||||
|
return StringRef::from_lit("103");
|
||||||
case 200:
|
case 200:
|
||||||
return StringRef::from_lit("200");
|
return StringRef::from_lit("200");
|
||||||
case 201:
|
case 201:
|
||||||
@@ -358,15 +362,21 @@ nghttp2_nv make_nv_nocopy(const StringRef &name, const StringRef &value,
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void copy_headers_to_nva_internal(std::vector<nghttp2_nv> &nva,
|
void copy_headers_to_nva_internal(std::vector<nghttp2_nv> &nva,
|
||||||
const HeaderRefs &headers, uint8_t nv_flags) {
|
const HeaderRefs &headers, uint8_t nv_flags,
|
||||||
for (auto &kv : headers) {
|
uint32_t flags) {
|
||||||
if (kv.name.empty() || kv.name[0] == ':') {
|
auto it_forwarded = std::end(headers);
|
||||||
|
auto it_xff = std::end(headers);
|
||||||
|
auto it_xfp = std::end(headers);
|
||||||
|
auto it_via = std::end(headers);
|
||||||
|
|
||||||
|
for (auto it = std::begin(headers); it != std::end(headers); ++it) {
|
||||||
|
auto kv = &(*it);
|
||||||
|
if (kv->name.empty() || kv->name[0] == ':') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (kv.token) {
|
switch (kv->token) {
|
||||||
case HD_COOKIE:
|
case HD_COOKIE:
|
||||||
case HD_CONNECTION:
|
case HD_CONNECTION:
|
||||||
case HD_FORWARDED:
|
|
||||||
case HD_HOST:
|
case HD_HOST:
|
||||||
case HD_HTTP2_SETTINGS:
|
case HD_HTTP2_SETTINGS:
|
||||||
case HD_KEEP_ALIVE:
|
case HD_KEEP_ALIVE:
|
||||||
@@ -375,51 +385,157 @@ void copy_headers_to_nva_internal(std::vector<nghttp2_nv> &nva,
|
|||||||
case HD_TE:
|
case HD_TE:
|
||||||
case HD_TRANSFER_ENCODING:
|
case HD_TRANSFER_ENCODING:
|
||||||
case HD_UPGRADE:
|
case HD_UPGRADE:
|
||||||
case HD_VIA:
|
|
||||||
case HD_X_FORWARDED_FOR:
|
|
||||||
case HD_X_FORWARDED_PROTO:
|
|
||||||
continue;
|
continue;
|
||||||
|
case HD_FORWARDED:
|
||||||
|
if (flags & HDOP_STRIP_FORWARDED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_forwarded == std::end(headers)) {
|
||||||
|
it_forwarded = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_forwarded);
|
||||||
|
it_forwarded = it;
|
||||||
|
break;
|
||||||
|
case HD_X_FORWARDED_FOR:
|
||||||
|
if (flags & HDOP_STRIP_X_FORWARDED_FOR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_xff == std::end(headers)) {
|
||||||
|
it_xff = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_xff);
|
||||||
|
it_xff = it;
|
||||||
|
break;
|
||||||
|
case HD_X_FORWARDED_PROTO:
|
||||||
|
if (flags & HDOP_STRIP_X_FORWARDED_PROTO) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_xfp == std::end(headers)) {
|
||||||
|
it_xfp = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_xfp);
|
||||||
|
it_xfp = it;
|
||||||
|
break;
|
||||||
|
case HD_VIA:
|
||||||
|
if (flags & HDOP_STRIP_VIA) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_via == std::end(headers)) {
|
||||||
|
it_via = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_via);
|
||||||
|
it_via = it;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
nva.push_back(make_nv_internal(kv.name, kv.value, kv.no_index, nv_flags));
|
nva.push_back(
|
||||||
|
make_nv_internal(kv->name, kv->value, kv->no_index, nv_flags));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void copy_headers_to_nva(std::vector<nghttp2_nv> &nva,
|
void copy_headers_to_nva(std::vector<nghttp2_nv> &nva,
|
||||||
const HeaderRefs &headers) {
|
const HeaderRefs &headers, uint32_t flags) {
|
||||||
copy_headers_to_nva_internal(nva, headers, NGHTTP2_NV_FLAG_NONE);
|
copy_headers_to_nva_internal(nva, headers, NGHTTP2_NV_FLAG_NONE, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> &nva,
|
void copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> &nva,
|
||||||
const HeaderRefs &headers) {
|
const HeaderRefs &headers, uint32_t flags) {
|
||||||
copy_headers_to_nva_internal(nva, headers, NGHTTP2_NV_FLAG_NO_COPY_NAME |
|
copy_headers_to_nva_internal(
|
||||||
NGHTTP2_NV_FLAG_NO_COPY_VALUE);
|
nva, headers,
|
||||||
|
NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void build_http1_headers_from_headers(DefaultMemchunks *buf,
|
void build_http1_headers_from_headers(DefaultMemchunks *buf,
|
||||||
const HeaderRefs &headers) {
|
const HeaderRefs &headers,
|
||||||
for (auto &kv : headers) {
|
uint32_t flags) {
|
||||||
if (kv.name.empty() || kv.name[0] == ':') {
|
auto it_forwarded = std::end(headers);
|
||||||
|
auto it_xff = std::end(headers);
|
||||||
|
auto it_xfp = std::end(headers);
|
||||||
|
auto it_via = std::end(headers);
|
||||||
|
|
||||||
|
for (auto it = std::begin(headers); it != std::end(headers); ++it) {
|
||||||
|
auto kv = &(*it);
|
||||||
|
if (kv->name.empty() || kv->name[0] == ':') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (kv.token) {
|
switch (kv->token) {
|
||||||
case HD_CONNECTION:
|
case HD_CONNECTION:
|
||||||
case HD_COOKIE:
|
case HD_COOKIE:
|
||||||
case HD_FORWARDED:
|
|
||||||
case HD_HOST:
|
case HD_HOST:
|
||||||
case HD_HTTP2_SETTINGS:
|
case HD_HTTP2_SETTINGS:
|
||||||
case HD_KEEP_ALIVE:
|
case HD_KEEP_ALIVE:
|
||||||
case HD_PROXY_CONNECTION:
|
case HD_PROXY_CONNECTION:
|
||||||
case HD_SERVER:
|
case HD_SERVER:
|
||||||
case HD_UPGRADE:
|
case HD_UPGRADE:
|
||||||
case HD_VIA:
|
|
||||||
case HD_X_FORWARDED_FOR:
|
|
||||||
case HD_X_FORWARDED_PROTO:
|
|
||||||
continue;
|
continue;
|
||||||
|
case HD_FORWARDED:
|
||||||
|
if (flags & HDOP_STRIP_FORWARDED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_forwarded == std::end(headers)) {
|
||||||
|
it_forwarded = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_forwarded);
|
||||||
|
it_forwarded = it;
|
||||||
|
break;
|
||||||
|
case HD_X_FORWARDED_FOR:
|
||||||
|
if (flags & HDOP_STRIP_X_FORWARDED_FOR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_xff == std::end(headers)) {
|
||||||
|
it_xff = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_xff);
|
||||||
|
it_xff = it;
|
||||||
|
break;
|
||||||
|
case HD_X_FORWARDED_PROTO:
|
||||||
|
if (flags & HDOP_STRIP_X_FORWARDED_PROTO) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_xfp == std::end(headers)) {
|
||||||
|
it_xfp = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_xfp);
|
||||||
|
it_xfp = it;
|
||||||
|
break;
|
||||||
|
case HD_VIA:
|
||||||
|
if (flags & HDOP_STRIP_VIA) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_via == std::end(headers)) {
|
||||||
|
it_via = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_via);
|
||||||
|
it_via = it;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
capitalize(buf, kv.name);
|
capitalize(buf, kv->name);
|
||||||
buf->append(": ");
|
buf->append(": ");
|
||||||
buf->append(kv.value);
|
buf->append(kv->value);
|
||||||
buf->append("\r\n");
|
buf->append("\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1486,7 +1602,7 @@ template <typename InputIt> InputIt eat_file(InputIt first, InputIt last) {
|
|||||||
for (; p != first && *(p - 1) != '/'; --p)
|
for (; p != first && *(p - 1) != '/'; --p)
|
||||||
;
|
;
|
||||||
if (p == first) {
|
if (p == first) {
|
||||||
// this should not happend in normal case, where we expect path
|
// this should not happened in normal case, where we expect path
|
||||||
// starts with '/'
|
// starts with '/'
|
||||||
*first++ = '/';
|
*first++ = '/';
|
||||||
return first;
|
return first;
|
||||||
|
|||||||
36
src/http2.h
36
src/http2.h
@@ -187,24 +187,50 @@ nghttp2_nv make_nv_ls_nocopy(const char (&name)[N], const StringRef &value) {
|
|||||||
NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
|
NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum HeaderBuildOp {
|
||||||
|
HDOP_NONE,
|
||||||
|
// Forwarded header fields must be stripped. If this flag is not
|
||||||
|
// set, all Forwarded header fields other than last one are added.
|
||||||
|
HDOP_STRIP_FORWARDED = 1,
|
||||||
|
// X-Forwarded-For header fields must be stripped. If this flag is
|
||||||
|
// not set, all X-Forwarded-For header fields other than last one
|
||||||
|
// are added.
|
||||||
|
HDOP_STRIP_X_FORWARDED_FOR = 1 << 1,
|
||||||
|
// X-Forwarded-Proto header fields must be stripped. If this flag
|
||||||
|
// is not set, all X-Forwarded-Proto header fields other than last
|
||||||
|
// one are added.
|
||||||
|
HDOP_STRIP_X_FORWARDED_PROTO = 1 << 2,
|
||||||
|
// Via header fields must be stripped. If this flag is not set, all
|
||||||
|
// Via header fields other than last one are added.
|
||||||
|
HDOP_STRIP_VIA = 1 << 3,
|
||||||
|
// Strip above all header fields.
|
||||||
|
HDOP_STRIP_ALL = HDOP_STRIP_FORWARDED | HDOP_STRIP_X_FORWARDED_FOR |
|
||||||
|
HDOP_STRIP_X_FORWARDED_PROTO | HDOP_STRIP_VIA,
|
||||||
|
};
|
||||||
|
|
||||||
// Appends headers in |headers| to |nv|. |headers| must be indexed
|
// Appends headers in |headers| to |nv|. |headers| must be indexed
|
||||||
// before this call (its element's token field is assigned). Certain
|
// before this call (its element's token field is assigned). Certain
|
||||||
// headers, including disallowed headers in HTTP/2 spec and headers
|
// headers, including disallowed headers in HTTP/2 spec and headers
|
||||||
// which require special handling (i.e. via), are not copied.
|
// which require special handling (i.e. via), are not copied. |flags|
|
||||||
|
// is one or more of HeaderBuildOp flags. They tell function that
|
||||||
|
// certain header fields should not be added.
|
||||||
void copy_headers_to_nva(std::vector<nghttp2_nv> &nva,
|
void copy_headers_to_nva(std::vector<nghttp2_nv> &nva,
|
||||||
const HeaderRefs &headers);
|
const HeaderRefs &headers, uint32_t flags);
|
||||||
|
|
||||||
// Just like copy_headers_to_nva(), but this adds
|
// Just like copy_headers_to_nva(), but this adds
|
||||||
// NGHTTP2_NV_FLAG_NO_COPY_NAME and NGHTTP2_NV_FLAG_NO_COPY_VALUE.
|
// NGHTTP2_NV_FLAG_NO_COPY_NAME and NGHTTP2_NV_FLAG_NO_COPY_VALUE.
|
||||||
void copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> &nva,
|
void copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> &nva,
|
||||||
const HeaderRefs &headers);
|
const HeaderRefs &headers, uint32_t flags);
|
||||||
|
|
||||||
// Appends HTTP/1.1 style header lines to |buf| from headers in
|
// Appends HTTP/1.1 style header lines to |buf| from headers in
|
||||||
// |headers|. |headers| must be indexed before this call (its
|
// |headers|. |headers| must be indexed before this call (its
|
||||||
// element's token field is assigned). Certain headers, which
|
// element's token field is assigned). Certain headers, which
|
||||||
// requires special handling (i.e. via and cookie), are not appended.
|
// requires special handling (i.e. via and cookie), are not appended.
|
||||||
|
// |flags| is one or more of HeaderBuildOp flags. They tell function
|
||||||
|
// that certain header fields should not be added.
|
||||||
void build_http1_headers_from_headers(DefaultMemchunks *buf,
|
void build_http1_headers_from_headers(DefaultMemchunks *buf,
|
||||||
const HeaderRefs &headers);
|
const HeaderRefs &headers,
|
||||||
|
uint32_t flags);
|
||||||
|
|
||||||
// Return positive window_size_increment if WINDOW_UPDATE should be
|
// Return positive window_size_increment if WINDOW_UPDATE should be
|
||||||
// sent for the stream |stream_id|. If |stream_id| == 0, this function
|
// sent for the stream |stream_id|. If |stream_id| == 0, this function
|
||||||
@@ -242,7 +268,7 @@ void erase_header(HeaderRef *hd);
|
|||||||
//
|
//
|
||||||
// This function returns the new rewritten URI on success. If the
|
// This function returns the new rewritten URI on success. If the
|
||||||
// location URI is not subject to the rewrite, this function returns
|
// location URI is not subject to the rewrite, this function returns
|
||||||
// emtpy string.
|
// empty string.
|
||||||
StringRef rewrite_location_uri(BlockAllocator &balloc, const StringRef &uri,
|
StringRef rewrite_location_uri(BlockAllocator &balloc, const StringRef &uri,
|
||||||
const http_parser_url &u,
|
const http_parser_url &u,
|
||||||
const StringRef &match_host,
|
const StringRef &match_host,
|
||||||
|
|||||||
@@ -150,11 +150,33 @@ auto headers = HeaderRefs{
|
|||||||
{StringRef::from_lit("zulu"), StringRef::from_lit("12")}};
|
{StringRef::from_lit("zulu"), StringRef::from_lit("12")}};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
auto headers2 = HeaderRefs{
|
||||||
|
{StringRef::from_lit("x-forwarded-for"), StringRef::from_lit("xff1"), false,
|
||||||
|
http2::HD_X_FORWARDED_FOR},
|
||||||
|
{StringRef::from_lit("x-forwarded-for"), StringRef::from_lit("xff2"), false,
|
||||||
|
http2::HD_X_FORWARDED_FOR},
|
||||||
|
{StringRef::from_lit("x-forwarded-proto"), StringRef::from_lit("xfp1"),
|
||||||
|
false, http2::HD_X_FORWARDED_PROTO},
|
||||||
|
{StringRef::from_lit("x-forwarded-proto"), StringRef::from_lit("xfp2"),
|
||||||
|
false, http2::HD_X_FORWARDED_PROTO},
|
||||||
|
{StringRef::from_lit("forwarded"), StringRef::from_lit("fwd1"), false,
|
||||||
|
http2::HD_FORWARDED},
|
||||||
|
{StringRef::from_lit("forwarded"), StringRef::from_lit("fwd2"), false,
|
||||||
|
http2::HD_FORWARDED},
|
||||||
|
{StringRef::from_lit("via"), StringRef::from_lit("via1"), false,
|
||||||
|
http2::HD_VIA},
|
||||||
|
{StringRef::from_lit("via"), StringRef::from_lit("via2"), false,
|
||||||
|
http2::HD_VIA},
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void test_http2_copy_headers_to_nva(void) {
|
void test_http2_copy_headers_to_nva(void) {
|
||||||
auto ans = std::vector<int>{0, 1, 4, 5, 6, 7, 12};
|
auto ans = std::vector<int>{0, 1, 4, 5, 6, 7, 12};
|
||||||
std::vector<nghttp2_nv> nva;
|
std::vector<nghttp2_nv> nva;
|
||||||
|
|
||||||
http2::copy_headers_to_nva_nocopy(nva, headers);
|
http2::copy_headers_to_nva_nocopy(nva, headers,
|
||||||
|
http2::HDOP_STRIP_X_FORWARDED_FOR);
|
||||||
CU_ASSERT(7 == nva.size());
|
CU_ASSERT(7 == nva.size());
|
||||||
for (size_t i = 0; i < ans.size(); ++i) {
|
for (size_t i = 0; i < ans.size(); ++i) {
|
||||||
check_nv(headers[ans[i]], &nva[i]);
|
check_nv(headers[ans[i]], &nva[i]);
|
||||||
@@ -169,7 +191,7 @@ void test_http2_copy_headers_to_nva(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nva.clear();
|
nva.clear();
|
||||||
http2::copy_headers_to_nva(nva, headers);
|
http2::copy_headers_to_nva(nva, headers, http2::HDOP_STRIP_X_FORWARDED_FOR);
|
||||||
CU_ASSERT(7 == nva.size());
|
CU_ASSERT(7 == nva.size());
|
||||||
for (size_t i = 0; i < ans.size(); ++i) {
|
for (size_t i = 0; i < ans.size(); ++i) {
|
||||||
check_nv(headers[ans[i]], &nva[i]);
|
check_nv(headers[ans[i]], &nva[i]);
|
||||||
@@ -180,12 +202,27 @@ void test_http2_copy_headers_to_nva(void) {
|
|||||||
CU_ASSERT(NGHTTP2_NV_FLAG_NONE == nva[i].flags);
|
CU_ASSERT(NGHTTP2_NV_FLAG_NONE == nva[i].flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nva.clear();
|
||||||
|
|
||||||
|
auto ans2 = std::vector<int>{0, 2, 4, 6};
|
||||||
|
http2::copy_headers_to_nva(nva, headers2, http2::HDOP_NONE);
|
||||||
|
CU_ASSERT(ans2.size() == nva.size());
|
||||||
|
for (size_t i = 0; i < ans2.size(); ++i) {
|
||||||
|
check_nv(headers2[ans2[i]], &nva[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
nva.clear();
|
||||||
|
|
||||||
|
http2::copy_headers_to_nva(nva, headers2, http2::HDOP_STRIP_ALL);
|
||||||
|
CU_ASSERT(nva.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_http2_build_http1_headers_from_headers(void) {
|
void test_http2_build_http1_headers_from_headers(void) {
|
||||||
MemchunkPool pool;
|
MemchunkPool pool;
|
||||||
DefaultMemchunks buf(&pool);
|
DefaultMemchunks buf(&pool);
|
||||||
http2::build_http1_headers_from_headers(&buf, headers);
|
http2::build_http1_headers_from_headers(&buf, headers,
|
||||||
|
http2::HDOP_STRIP_X_FORWARDED_FOR);
|
||||||
auto hdrs = std::string(buf.head->pos, buf.head->last);
|
auto hdrs = std::string(buf.head->pos, buf.head->last);
|
||||||
CU_ASSERT("Alpha: 0\r\n"
|
CU_ASSERT("Alpha: 0\r\n"
|
||||||
"Bravo: 1\r\n"
|
"Bravo: 1\r\n"
|
||||||
@@ -196,6 +233,21 @@ void test_http2_build_http1_headers_from_headers(void) {
|
|||||||
"Te: 8\r\n"
|
"Te: 8\r\n"
|
||||||
"Te: 9\r\n"
|
"Te: 9\r\n"
|
||||||
"Zulu: 12\r\n" == hdrs);
|
"Zulu: 12\r\n" == hdrs);
|
||||||
|
|
||||||
|
buf.reset();
|
||||||
|
|
||||||
|
http2::build_http1_headers_from_headers(&buf, headers2, http2::HDOP_NONE);
|
||||||
|
hdrs = std::string(buf.head->pos, buf.head->last);
|
||||||
|
CU_ASSERT("X-Forwarded-For: xff1\r\n"
|
||||||
|
"X-Forwarded-Proto: xfp1\r\n"
|
||||||
|
"Forwarded: fwd1\r\n"
|
||||||
|
"Via: via1\r\n" == hdrs);
|
||||||
|
|
||||||
|
buf.reset();
|
||||||
|
|
||||||
|
http2::build_http1_headers_from_headers(&buf, headers2,
|
||||||
|
http2::HDOP_STRIP_ALL);
|
||||||
|
CU_ASSERT(0 == buf.rleft());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_http2_lws(void) {
|
void test_http2_lws(void) {
|
||||||
|
|||||||
@@ -118,6 +118,28 @@ private:
|
|||||||
std::unique_ptr<request_impl> impl_;
|
std::unique_ptr<request_impl> impl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Wrapper around an nghttp2_priority_spec.
|
||||||
|
class priority_spec {
|
||||||
|
public:
|
||||||
|
// The default ctor is used only by sentinel values.
|
||||||
|
priority_spec() = default;
|
||||||
|
|
||||||
|
// Create a priority spec with the given priority settings.
|
||||||
|
explicit priority_spec(const int32_t stream_id, const int32_t weight,
|
||||||
|
const bool exclusive = false);
|
||||||
|
|
||||||
|
// Return a pointer to a valid nghttp2 priority spec, or null.
|
||||||
|
const nghttp2_priority_spec *get() const;
|
||||||
|
|
||||||
|
// Indicates whether or not this spec is valid (i.e. was constructed with
|
||||||
|
// values).
|
||||||
|
const bool valid() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
nghttp2_priority_spec spec_;
|
||||||
|
bool valid_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
class session_impl;
|
class session_impl;
|
||||||
|
|
||||||
class session {
|
class session {
|
||||||
@@ -177,7 +199,8 @@ public:
|
|||||||
// succeeds, or nullptr and |ec| contains error message.
|
// succeeds, or nullptr and |ec| contains error message.
|
||||||
const request *submit(boost::system::error_code &ec,
|
const request *submit(boost::system::error_code &ec,
|
||||||
const std::string &method, const std::string &uri,
|
const std::string &method, const std::string &uri,
|
||||||
header_map h = header_map{}) const;
|
header_map h = header_map{},
|
||||||
|
priority_spec prio = priority_spec()) const;
|
||||||
|
|
||||||
// Submits request to server using |method| (e.g., "GET"), |uri|
|
// Submits request to server using |method| (e.g., "GET"), |uri|
|
||||||
// (e.g., "http://localhost/") and optionally additional header
|
// (e.g., "http://localhost/") and optionally additional header
|
||||||
@@ -186,7 +209,8 @@ public:
|
|||||||
// contains error message.
|
// contains error message.
|
||||||
const request *submit(boost::system::error_code &ec,
|
const request *submit(boost::system::error_code &ec,
|
||||||
const std::string &method, const std::string &uri,
|
const std::string &method, const std::string &uri,
|
||||||
std::string data, header_map h = header_map{}) const;
|
std::string data, header_map h = header_map{},
|
||||||
|
priority_spec prio = priority_spec()) const;
|
||||||
|
|
||||||
// Submits request to server using |method| (e.g., "GET"), |uri|
|
// Submits request to server using |method| (e.g., "GET"), |uri|
|
||||||
// (e.g., "http://localhost/") and optionally additional header
|
// (e.g., "http://localhost/") and optionally additional header
|
||||||
@@ -195,7 +219,8 @@ public:
|
|||||||
// nullptr and |ec| contains error message.
|
// nullptr and |ec| contains error message.
|
||||||
const request *submit(boost::system::error_code &ec,
|
const request *submit(boost::system::error_code &ec,
|
||||||
const std::string &method, const std::string &uri,
|
const std::string &method, const std::string &uri,
|
||||||
generator_cb cb, header_map h = header_map{}) const;
|
generator_cb cb, header_map h = header_map{},
|
||||||
|
priority_spec prio = priority_spec()) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<session_impl> impl_;
|
std::shared_ptr<session_impl> impl_;
|
||||||
|
|||||||
@@ -48,7 +48,9 @@
|
|||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|
||||||
typedef struct { int dump_header_table; } inflate_config;
|
typedef struct {
|
||||||
|
int dump_header_table;
|
||||||
|
} inflate_config;
|
||||||
|
|
||||||
static inflate_config config;
|
static inflate_config config;
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,15 @@
|
|||||||
#include "nghttp2_config.h"
|
#include "nghttp2_config.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* Structure for scatter/gather I/O. */
|
||||||
|
struct iovec {
|
||||||
|
void *iov_base; /* Pointer to data. */
|
||||||
|
size_t iov_len; /* Length of data. */
|
||||||
|
};
|
||||||
|
#else // !_WIN32
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
#endif // !_WIN32
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -50,23 +58,21 @@ namespace nghttp2 {
|
|||||||
#endif // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
|
#endif // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
|
||||||
|
|
||||||
template <size_t N> struct Memchunk {
|
template <size_t N> struct Memchunk {
|
||||||
Memchunk(std::unique_ptr<Memchunk> next_chunk)
|
Memchunk(Memchunk *next_chunk)
|
||||||
: pos(std::begin(buf)),
|
: pos(std::begin(buf)), last(pos), knext(next_chunk), next(nullptr) {}
|
||||||
last(pos),
|
|
||||||
knext(std::move(next_chunk)),
|
|
||||||
next(nullptr) {}
|
|
||||||
size_t len() const { return last - pos; }
|
size_t len() const { return last - pos; }
|
||||||
size_t left() const { return std::end(buf) - last; }
|
size_t left() const { return std::end(buf) - last; }
|
||||||
void reset() { pos = last = std::begin(buf); }
|
void reset() { pos = last = std::begin(buf); }
|
||||||
std::array<uint8_t, N> buf;
|
std::array<uint8_t, N> buf;
|
||||||
uint8_t *pos, *last;
|
uint8_t *pos, *last;
|
||||||
std::unique_ptr<Memchunk> knext;
|
Memchunk *knext;
|
||||||
Memchunk *next;
|
Memchunk *next;
|
||||||
static const size_t size = N;
|
static const size_t size = N;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct Pool {
|
template <typename T> struct Pool {
|
||||||
Pool() : pool(nullptr), freelist(nullptr), poolsize(0) {}
|
Pool() : pool(nullptr), freelist(nullptr), poolsize(0) {}
|
||||||
|
~Pool() { clear(); }
|
||||||
T *get() {
|
T *get() {
|
||||||
if (freelist) {
|
if (freelist) {
|
||||||
auto m = freelist;
|
auto m = freelist;
|
||||||
@@ -76,9 +82,9 @@ template <typename T> struct Pool {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool = make_unique<T>(std::move(pool));
|
pool = new T{pool};
|
||||||
poolsize += T::size;
|
poolsize += T::size;
|
||||||
return pool.get();
|
return pool;
|
||||||
}
|
}
|
||||||
void recycle(T *m) {
|
void recycle(T *m) {
|
||||||
m->next = freelist;
|
m->next = freelist;
|
||||||
@@ -86,11 +92,16 @@ template <typename T> struct Pool {
|
|||||||
}
|
}
|
||||||
void clear() {
|
void clear() {
|
||||||
freelist = nullptr;
|
freelist = nullptr;
|
||||||
|
for (auto p = pool; p;) {
|
||||||
|
auto knext = p->knext;
|
||||||
|
delete p;
|
||||||
|
p = knext;
|
||||||
|
}
|
||||||
pool = nullptr;
|
pool = nullptr;
|
||||||
poolsize = 0;
|
poolsize = 0;
|
||||||
}
|
}
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
std::unique_ptr<T> pool;
|
T *pool;
|
||||||
T *freelist;
|
T *freelist;
|
||||||
size_t poolsize;
|
size_t poolsize;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,34 +42,34 @@ void test_pool_recycle(void) {
|
|||||||
|
|
||||||
auto m1 = pool.get();
|
auto m1 = pool.get();
|
||||||
|
|
||||||
CU_ASSERT(m1 == pool.pool.get());
|
CU_ASSERT(m1 == pool.pool);
|
||||||
CU_ASSERT(MemchunkPool::value_type::size == pool.poolsize);
|
CU_ASSERT(MemchunkPool::value_type::size == pool.poolsize);
|
||||||
CU_ASSERT(nullptr == pool.freelist);
|
CU_ASSERT(nullptr == pool.freelist);
|
||||||
|
|
||||||
auto m2 = pool.get();
|
auto m2 = pool.get();
|
||||||
|
|
||||||
CU_ASSERT(m2 == pool.pool.get());
|
CU_ASSERT(m2 == pool.pool);
|
||||||
CU_ASSERT(2 * MemchunkPool::value_type::size == pool.poolsize);
|
CU_ASSERT(2 * MemchunkPool::value_type::size == pool.poolsize);
|
||||||
CU_ASSERT(nullptr == pool.freelist);
|
CU_ASSERT(nullptr == pool.freelist);
|
||||||
CU_ASSERT(m1 == m2->knext.get());
|
CU_ASSERT(m1 == m2->knext);
|
||||||
CU_ASSERT(nullptr == m1->knext.get());
|
CU_ASSERT(nullptr == m1->knext);
|
||||||
|
|
||||||
auto m3 = pool.get();
|
auto m3 = pool.get();
|
||||||
|
|
||||||
CU_ASSERT(m3 == pool.pool.get());
|
CU_ASSERT(m3 == pool.pool);
|
||||||
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
|
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
|
||||||
CU_ASSERT(nullptr == pool.freelist);
|
CU_ASSERT(nullptr == pool.freelist);
|
||||||
|
|
||||||
pool.recycle(m3);
|
pool.recycle(m3);
|
||||||
|
|
||||||
CU_ASSERT(m3 == pool.pool.get());
|
CU_ASSERT(m3 == pool.pool);
|
||||||
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
|
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
|
||||||
CU_ASSERT(m3 == pool.freelist);
|
CU_ASSERT(m3 == pool.freelist);
|
||||||
|
|
||||||
auto m4 = pool.get();
|
auto m4 = pool.get();
|
||||||
|
|
||||||
CU_ASSERT(m3 == m4);
|
CU_ASSERT(m3 == m4);
|
||||||
CU_ASSERT(m4 == pool.pool.get());
|
CU_ASSERT(m4 == pool.pool);
|
||||||
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
|
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
|
||||||
CU_ASSERT(nullptr == pool.freelist);
|
CU_ASSERT(nullptr == pool.freelist);
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,11 @@
|
|||||||
#ifdef HAVE_SYS_SOCKET_H
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#endif // HAVE_SYS_SOCKET_H
|
#endif // HAVE_SYS_SOCKET_H
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#else // !_WIN32
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#endif // !_WIN32
|
||||||
#ifdef HAVE_NETINET_IN_H
|
#ifdef HAVE_NETINET_IN_H
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif // HAVE_NETINET_IN_H
|
#endif // HAVE_NETINET_IN_H
|
||||||
@@ -48,7 +52,9 @@ union sockaddr_union {
|
|||||||
sockaddr sa;
|
sockaddr sa;
|
||||||
sockaddr_in6 in6;
|
sockaddr_in6 in6;
|
||||||
sockaddr_in in;
|
sockaddr_in in;
|
||||||
|
#ifndef _WIN32
|
||||||
sockaddr_un un;
|
sockaddr_un un;
|
||||||
|
#endif // !_WIN32
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Address {
|
struct Address {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
#include "HtmlParser.h"
|
#include "HtmlParser.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
#include "ssl.h"
|
#include "tls.h"
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
|
|
||||||
#ifndef O_BINARY
|
#ifndef O_BINARY
|
||||||
@@ -89,7 +89,11 @@ enum {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr auto anchors = std::array<Anchor, 5>{{
|
constexpr auto anchors = std::array<Anchor, 5>{{
|
||||||
{3, 0, 201}, {5, 0, 101}, {7, 0, 1}, {9, 7, 1}, {11, 3, 1},
|
{3, 0, 201},
|
||||||
|
{5, 0, 101},
|
||||||
|
{7, 0, 1},
|
||||||
|
{9, 7, 1},
|
||||||
|
{11, 3, 1},
|
||||||
}};
|
}};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -116,7 +120,8 @@ Config::Config()
|
|||||||
no_dep(false),
|
no_dep(false),
|
||||||
hexdump(false),
|
hexdump(false),
|
||||||
no_push(false),
|
no_push(false),
|
||||||
expect_continue(false) {
|
expect_continue(false),
|
||||||
|
verify_peer(true) {
|
||||||
nghttp2_option_new(&http2_option);
|
nghttp2_option_new(&http2_option);
|
||||||
nghttp2_option_set_peer_max_concurrent_streams(http2_option,
|
nghttp2_option_set_peer_max_concurrent_streams(http2_option,
|
||||||
peer_max_concurrent_streams);
|
peer_max_concurrent_streams);
|
||||||
@@ -171,6 +176,8 @@ Request::~Request() { nghttp2_gzip_inflate_del(inflater); }
|
|||||||
|
|
||||||
void Request::init_inflater() {
|
void Request::init_inflater() {
|
||||||
int rv;
|
int rv;
|
||||||
|
// This is required with --disable-assert.
|
||||||
|
(void)rv;
|
||||||
rv = nghttp2_gzip_inflate_new(&inflater);
|
rv = nghttp2_gzip_inflate_new(&inflater);
|
||||||
assert(rv == 0);
|
assert(rv == 0);
|
||||||
}
|
}
|
||||||
@@ -401,17 +408,10 @@ int htp_msg_begincb(http_parser *htp) {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
|
||||||
int htp_statuscb(http_parser *htp, const char *at, size_t length) {
|
|
||||||
auto client = static_cast<HttpClient *>(htp->data);
|
|
||||||
client->upgrade_response_status_code = htp->status_code;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int htp_msg_completecb(http_parser *htp) {
|
int htp_msg_completecb(http_parser *htp) {
|
||||||
auto client = static_cast<HttpClient *>(htp->data);
|
auto client = static_cast<HttpClient *>(htp->data);
|
||||||
|
client->upgrade_response_status_code = htp->status_code;
|
||||||
client->upgrade_response_complete = true;
|
client->upgrade_response_complete = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -421,7 +421,7 @@ namespace {
|
|||||||
constexpr http_parser_settings htp_hooks = {
|
constexpr http_parser_settings htp_hooks = {
|
||||||
htp_msg_begincb, // http_cb on_message_begin;
|
htp_msg_begincb, // http_cb on_message_begin;
|
||||||
nullptr, // http_data_cb on_url;
|
nullptr, // http_data_cb on_url;
|
||||||
htp_statuscb, // http_data_cb on_status;
|
nullptr, // http_data_cb on_status;
|
||||||
nullptr, // http_data_cb on_header_field;
|
nullptr, // http_data_cb on_header_field;
|
||||||
nullptr, // http_data_cb on_header_value;
|
nullptr, // http_data_cb on_header_value;
|
||||||
nullptr, // http_cb on_headers_complete;
|
nullptr, // http_cb on_headers_complete;
|
||||||
@@ -646,6 +646,11 @@ int HttpClient::resolve_host(const std::string &host, uint16_t port) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Just returns 1 to continue handshake.
|
||||||
|
int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int HttpClient::initiate_connection() {
|
int HttpClient::initiate_connection() {
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
@@ -675,6 +680,17 @@ int HttpClient::initiate_connection() {
|
|||||||
const auto &host_string =
|
const auto &host_string =
|
||||||
config.host_override.empty() ? host : config.host_override;
|
config.host_override.empty() ? host : config.host_override;
|
||||||
|
|
||||||
|
#if (!defined(LIBRESSL_VERSION_NUMBER) && \
|
||||||
|
OPENSSL_VERSION_NUMBER >= 0x10002000L) || \
|
||||||
|
defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
auto param = SSL_get0_param(ssl);
|
||||||
|
X509_VERIFY_PARAM_set_hostflags(param, 0);
|
||||||
|
X509_VERIFY_PARAM_set1_host(param, host_string.c_str(),
|
||||||
|
host_string.size());
|
||||||
|
#endif // (!defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >=
|
||||||
|
// 0x10002000L) || defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
SSL_set_verify(ssl, SSL_VERIFY_PEER, verify_cb);
|
||||||
|
|
||||||
if (!util::numeric_host(host_string.c_str())) {
|
if (!util::numeric_host(host_string.c_str())) {
|
||||||
SSL_set_tlsext_host_name(ssl, host_string.c_str());
|
SSL_set_tlsext_host_name(ssl, host_string.c_str());
|
||||||
}
|
}
|
||||||
@@ -1295,6 +1311,14 @@ int HttpClient::tls_handshake() {
|
|||||||
readfn = &HttpClient::read_tls;
|
readfn = &HttpClient::read_tls;
|
||||||
writefn = &HttpClient::write_tls;
|
writefn = &HttpClient::write_tls;
|
||||||
|
|
||||||
|
if (config.verify_peer) {
|
||||||
|
auto verify_res = SSL_get_verify_result(ssl);
|
||||||
|
if (verify_res != X509_V_OK) {
|
||||||
|
std::cerr << "[WARNING] Certificate verification failed: "
|
||||||
|
<< X509_verify_cert_error_string(verify_res) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (connection_made() != 0) {
|
if (connection_made() != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -2247,15 +2271,20 @@ int communicate(
|
|||||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||||
|
|
||||||
if (nghttp2::ssl::ssl_ctx_set_proto_versions(
|
if (SSL_CTX_set_default_verify_paths(ssl_ctx) != 1) {
|
||||||
ssl_ctx, nghttp2::ssl::NGHTTP2_TLS_MIN_VERSION,
|
std::cerr << "[WARNING] Could not load system trusted CA certificates: "
|
||||||
nghttp2::ssl::NGHTTP2_TLS_MAX_VERSION) != 0) {
|
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nghttp2::tls::ssl_ctx_set_proto_versions(
|
||||||
|
ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
|
||||||
|
nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
|
||||||
std::cerr << "[ERROR] Could not set TLS versions" << std::endl;
|
std::cerr << "[ERROR] Could not set TLS versions" << std::endl;
|
||||||
result = -1;
|
result = -1;
|
||||||
goto fin;
|
goto fin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST) == 0) {
|
if (SSL_CTX_set_cipher_list(ssl_ctx, tls::DEFAULT_CIPHER_LIST) == 0) {
|
||||||
std::cerr << "[ERROR] " << ERR_error_string(ERR_get_error(), nullptr)
|
std::cerr << "[ERROR] " << ERR_error_string(ERR_get_error(), nullptr)
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
result = -1;
|
result = -1;
|
||||||
@@ -2433,8 +2462,8 @@ int run(char **uris, int n) {
|
|||||||
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
|
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
|
||||||
callbacks, verbose_on_invalid_frame_recv_callback);
|
callbacks, verbose_on_invalid_frame_recv_callback);
|
||||||
|
|
||||||
nghttp2_session_callbacks_set_error_callback(callbacks,
|
nghttp2_session_callbacks_set_error_callback2(callbacks,
|
||||||
verbose_error_callback);
|
verbose_error_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||||
@@ -2701,6 +2730,9 @@ Options:
|
|||||||
(up to a short timeout) until the server sends a 100
|
(up to a short timeout) until the server sends a 100
|
||||||
Continue interim response. This option is ignored unless
|
Continue interim response. This option is ignored unless
|
||||||
combined with the -d option.
|
combined with the -d option.
|
||||||
|
-y, --no-verify-peer
|
||||||
|
Suppress warning on server certificate verification
|
||||||
|
failure.
|
||||||
--version Display version information and exit.
|
--version Display version information and exit.
|
||||||
-h, --help Display this help and exit.
|
-h, --help Display this help and exit.
|
||||||
|
|
||||||
@@ -2718,7 +2750,7 @@ Options:
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
ssl::libssl_init();
|
tls::libssl_init();
|
||||||
|
|
||||||
bool color = false;
|
bool color = false;
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -2742,6 +2774,7 @@ int main(int argc, char **argv) {
|
|||||||
{"header-table-size", required_argument, nullptr, 'c'},
|
{"header-table-size", required_argument, nullptr, 'c'},
|
||||||
{"padding", required_argument, nullptr, 'b'},
|
{"padding", required_argument, nullptr, 'b'},
|
||||||
{"har", required_argument, nullptr, 'r'},
|
{"har", required_argument, nullptr, 'r'},
|
||||||
|
{"no-verify-peer", no_argument, nullptr, 'y'},
|
||||||
{"cert", required_argument, &flag, 1},
|
{"cert", required_argument, &flag, 1},
|
||||||
{"key", required_argument, &flag, 2},
|
{"key", required_argument, &flag, 2},
|
||||||
{"color", no_argument, &flag, 3},
|
{"color", no_argument, &flag, 3},
|
||||||
@@ -2757,8 +2790,9 @@ int main(int argc, char **argv) {
|
|||||||
{"encoder-header-table-size", required_argument, &flag, 14},
|
{"encoder-header-table-size", required_argument, &flag, 14},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int c = getopt_long(argc, argv, "M:Oab:c:d:gm:np:r:hH:vst:uw:W:",
|
int c =
|
||||||
long_options, &option_index);
|
getopt_long(argc, argv, "M:Oab:c:d:m:np:r:hH:vst:uw:yW:", long_options,
|
||||||
|
&option_index);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2888,6 +2922,9 @@ int main(int argc, char **argv) {
|
|||||||
config.min_header_table_size = std::min(config.min_header_table_size, n);
|
config.min_header_table_size = std::min(config.min_header_table_size, n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'y':
|
||||||
|
config.verify_peer = false;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
util::show_candidates(argv[optind - 1], long_options);
|
util::show_candidates(argv[optind - 1], long_options);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ struct Config {
|
|||||||
bool hexdump;
|
bool hexdump;
|
||||||
bool no_push;
|
bool no_push;
|
||||||
bool expect_continue;
|
bool expect_continue;
|
||||||
|
bool verify_peer;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class RequestState { INITIAL, ON_REQUEST, ON_RESPONSE, ON_COMPLETE };
|
enum class RequestState { INITIAL, ON_REQUEST, ON_RESPONSE, ON_COMPLETE };
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ int nghttp2_gzip_inflate(nghttp2_gzip *inflater, uint8_t *out,
|
|||||||
switch (rv) {
|
switch (rv) {
|
||||||
case Z_STREAM_END:
|
case Z_STREAM_END:
|
||||||
inflater->finished = 1;
|
inflater->finished = 1;
|
||||||
|
/* FALL THROUGH */
|
||||||
case Z_OK:
|
case Z_OK:
|
||||||
case Z_BUF_ERROR:
|
case Z_BUF_ERROR:
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -43,14 +43,14 @@ static size_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in,
|
|||||||
zst.opaque = Z_NULL;
|
zst.opaque = Z_NULL;
|
||||||
|
|
||||||
rv = deflateInit(&zst, Z_DEFAULT_COMPRESSION);
|
rv = deflateInit(&zst, Z_DEFAULT_COMPRESSION);
|
||||||
assert(rv == Z_OK);
|
CU_ASSERT(rv == Z_OK);
|
||||||
|
|
||||||
zst.avail_in = (unsigned int)inlen;
|
zst.avail_in = (unsigned int)inlen;
|
||||||
zst.next_in = (uint8_t *)in;
|
zst.next_in = (uint8_t *)in;
|
||||||
zst.avail_out = (unsigned int)outlen;
|
zst.avail_out = (unsigned int)outlen;
|
||||||
zst.next_out = out;
|
zst.next_out = out;
|
||||||
rv = deflate(&zst, Z_SYNC_FLUSH);
|
rv = deflate(&zst, Z_SYNC_FLUSH);
|
||||||
assert(rv == Z_OK);
|
CU_ASSERT(rv == Z_OK);
|
||||||
|
|
||||||
deflateEnd(&zst);
|
deflateEnd(&zst);
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
#include "app_helper.h"
|
#include "app_helper.h"
|
||||||
#include "HttpServer.h"
|
#include "HttpServer.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ssl.h"
|
#include "tls.h"
|
||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|
||||||
@@ -174,8 +174,7 @@ Options:
|
|||||||
--mime-types-file=<PATH>
|
--mime-types-file=<PATH>
|
||||||
Path to file that contains MIME media types and the
|
Path to file that contains MIME media types and the
|
||||||
extensions that represent them.
|
extensions that represent them.
|
||||||
Default: )"
|
Default: )" << config.mime_types_file << R"(
|
||||||
<< config.mime_types_file << R"(
|
|
||||||
--no-content-length
|
--no-content-length
|
||||||
Don't send content-length header field.
|
Don't send content-length header field.
|
||||||
--version Display version information and exit.
|
--version Display version information and exit.
|
||||||
@@ -190,10 +189,10 @@ Options:
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
ssl::libssl_init();
|
tls::libssl_init();
|
||||||
|
|
||||||
#ifndef NOTHREADS
|
#ifndef NOTHREADS
|
||||||
ssl::LibsslGlobalLock lock;
|
tls::LibsslGlobalLock lock;
|
||||||
#endif // NOTHREADS
|
#endif // NOTHREADS
|
||||||
|
|
||||||
Config config;
|
Config config;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user