Compare commits

..

3 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
d13a575837 Update manual pages 2024-05-19 12:16:46 +09:00
Tatsuhiro Tsujikawa
001833c5a4 Bump package version 2024-05-19 12:14:09 +09:00
Tatsuhiro Tsujikawa
38fb5c2b3f nghttpx: Fix batch UDP QUIC packet dropped on GRO read 2024-05-19 11:37:27 +09:00
285 changed files with 29371 additions and 24982 deletions

View File

@@ -8,91 +8,56 @@ AlignConsecutiveAssignments:
AcrossEmptyLines: false AcrossEmptyLines: false
AcrossComments: false AcrossComments: false
AlignCompound: false AlignCompound: false
AlignFunctionPointers: false
PadOperators: true PadOperators: true
AlignConsecutiveBitFields: AlignConsecutiveBitFields:
Enabled: false Enabled: false
AcrossEmptyLines: false AcrossEmptyLines: false
AcrossComments: false AcrossComments: false
AlignCompound: false AlignCompound: false
AlignFunctionPointers: false
PadOperators: true PadOperators: true
AlignConsecutiveDeclarations: AlignConsecutiveDeclarations:
Enabled: false Enabled: false
AcrossEmptyLines: false AcrossEmptyLines: false
AcrossComments: false AcrossComments: false
AlignCompound: false AlignCompound: false
AlignFunctionPointers: false
PadOperators: true PadOperators: true
AlignConsecutiveMacros: AlignConsecutiveMacros:
Enabled: false Enabled: false
AcrossEmptyLines: false AcrossEmptyLines: false
AcrossComments: false AcrossComments: false
AlignCompound: false AlignCompound: false
AlignFunctionPointers: false
PadOperators: true PadOperators: true
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Right AlignEscapedNewlines: Right
AlignOperands: Align AlignOperands: Align
AlignTrailingComments: AlignTrailingComments: true
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros: AttributeMacros:
- __capability - __capability
BinPackArguments: true BinPackArguments: true
BinPackParameters: true BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping: BraceWrapping:
AfterCaseLabel: false AfterCaseLabel: false
AfterClass: false AfterClass: false
AfterControlStatement: Never AfterControlStatement: Never
AfterEnum: false AfterEnum: false
AfterExternBlock: false
AfterFunction: false AfterFunction: false
AfterNamespace: false AfterNamespace: false
AfterObjCDeclaration: false AfterObjCDeclaration: false
AfterStruct: false AfterStruct: false
AfterUnion: false AfterUnion: false
AfterExternBlock: false
BeforeCatch: false BeforeCatch: false
BeforeElse: false BeforeElse: false
BeforeLambdaBody: false BeforeLambdaBody: false
@@ -101,32 +66,33 @@ BraceWrapping:
SplitEmptyFunction: true SplitEmptyFunction: true
SplitEmptyRecord: true SplitEmptyRecord: true
SplitEmptyNamespace: true SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true BreakStringLiterals: true
BreakTemplateDeclarations: MultiLine
ColumnLimit: 80 ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:' CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false CompactNamespaces: false
ConstructorInitializerIndentWidth: 2 ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 2 ContinuationIndentWidth: 4
Cpp11BracedListStyle: true Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false DerivePointerAlignment: false
DisableFormat: false DisableFormat: false
EmptyLineAfterAccessModifier: Never EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: NextLine
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true FixNamespaceComments: true
ForEachMacros: ForEachMacros:
- foreach - foreach
@@ -151,35 +117,22 @@ IncludeCategories:
IncludeIsMainRegex: '$' IncludeIsMainRegex: '$'
IncludeIsMainSourceRegex: '' IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false IndentCaseLabels: false
IndentExternBlock: AfterExternBlock IndentCaseBlocks: false
IndentGotoLabels: true IndentGotoLabels: true
IndentPPDirectives: AfterHash IndentPPDirectives: AfterHash
IndentExternBlock: AfterExternBlock
IndentRequiresClause: false IndentRequiresClause: false
IndentWidth: 2 IndentWidth: 2
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
InsertBraces: false InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave JavaScriptQuotes: Leave
JavaScriptWrapImports: true JavaScriptWrapImports: true
KeepEmptyLines: KeepEmptyLinesAtTheStartOfBlocks: true
AtEndOfFile: false
AtStartOfBlock: false
AtStartOfFile: true
LambdaBodyIndentation: Signature LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: '' MacroBlockBegin: ''
MacroBlockEnd: '' MacroBlockEnd: ''
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
ObjCBinPackProtocolList: Auto ObjCBinPackProtocolList: Auto
@@ -187,44 +140,35 @@ ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2 PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300 PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120 PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0 PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000 PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10 PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000 PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60 PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Right PointerAlignment: Right
PPIndentWidth: -1 PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer ReferenceAlignment: Pointer
ReflowComments: true ReflowComments: true
RemoveBracesLLVM: false RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1 ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: Never SortIncludes: Never
SortJavaStaticImport: Before SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric SortUsingDeclarations: true
SpaceAfterCStyleCast: false SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions: SpaceBeforeParensOptions:
AfterControlStatements: true AfterControlStatements: true
@@ -233,40 +177,34 @@ SpaceBeforeParensOptions:
AfterFunctionDeclarationName: false AfterFunctionDeclarationName: false
AfterIfMacros: true AfterIfMacros: true
AfterOverloadedOperator: false AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false AfterRequiresInClause: false
AfterRequiresInExpression: false AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1 SpacesBeforeTrailingComments: 1
SpacesInAngles: Never SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix: SpacesInLineCommentPrefix:
Minimum: 1 Minimum: 1
Maximum: -1 Maximum: -1
SpacesInParens: Never SpacesInParentheses: false
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest Standard: Latest
StatementAttributeLikeMacros: StatementAttributeLikeMacros:
- Q_EMIT - Q_EMIT
StatementMacros: StatementMacros:
- Q_UNUSED - Q_UNUSED
- QT_REQUIRE_VERSION - QT_REQUIRE_VERSION
- munit_void_test_decl
- nghttp2_max_def
- nghttp2_min_def
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 8 TabWidth: 8
UseCRLF: false
UseTab: Never UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros: WhitespaceSensitiveMacros:
- STRINGIZE - STRINGIZE
- PP_STRINGIZE - PP_STRINGIZE

View File

@@ -1,24 +0,0 @@
name: android
on:
push:
paths:
- Dockerfile.android
- .github/workflows/android.yml
branches:
- '**'
permissions: read-all
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build
uses: docker/build-push-action@v6
with:
file: Dockerfile.android

View File

@@ -5,26 +5,25 @@ on: [push, pull_request]
permissions: read-all permissions: read-all
env: env:
LIBBPF_VERSION: v1.6.2 LIBBPF_VERSION: v1.3.0
OPENSSL1_VERSION: 1_1_1w+quic OPENSSL1_VERSION: 1_1_1w+quic
OPENSSL3_VERSION: 3.5.2 OPENSSL3_VERSION: 3.1.5+quic
BORINGSSL_VERSION: 729648fb79df7bc46c145e49b0dfd8d2a24232f1 BORINGSSL_VERSION: 6ab7c1482bf4cdc91c87bc512aaf68ffb18975ec
AWSLC_VERSION: v1.58.1 AWSLC_VERSION: v1.26.0
NGHTTP3_VERSION: v1.11.0 NGHTTP3_VERSION: v1.3.0
NGTCP2_VERSION: v1.15.1 NGTCP2_VERSION: v1.5.0
WOLFSSL_VERSION: v5.8.2-stable
jobs: jobs:
build-cache: build-cache:
strategy: strategy:
matrix: matrix:
os: [ubuntu-24.04, macos-14, macos-15] os: [ubuntu-22.04, macos-13, macos-14]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
- name: Restore libbpf cache - name: Restore libbpf cache
id: cache-libbpf id: cache-libbpf
uses: actions/cache@v4 uses: actions/cache@v4
@@ -49,8 +48,8 @@ jobs:
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: | path: |
boringssl/build/libcrypto.a boringssl/build/crypto/libcrypto.a
boringssl/build/libssl.a boringssl/build/ssl/libssl.a
boringssl/include boringssl/include
key: ${{ matrix.os }}-boringssl-${{ env.BORINGSSL_VERSION }} key: ${{ matrix.os }}-boringssl-${{ env.BORINGSSL_VERSION }}
- name: Restore aws-lc cache - name: Restore aws-lc cache
@@ -62,12 +61,6 @@ jobs:
aws-lc/build/ssl/libssl.a aws-lc/build/ssl/libssl.a
aws-lc/include aws-lc/include
key: ${{ matrix.os }}-awslc-${{ env.AWSLC_VERSION }} key: ${{ matrix.os }}-awslc-${{ env.AWSLC_VERSION }}
- name: Restore wolfSSL cache
id: cache-wolfssl
uses: actions/cache@v4
with:
path: wolfssl/build
key: ${{ matrix.os }}-wolfssl-${{ env.WOLFSSL_VERSION }}
- name: Restore nghttp3 cache - name: Restore nghttp3 cache
id: cache-nghttp3 id: cache-nghttp3
uses: actions/cache@v4 uses: actions/cache@v4
@@ -93,7 +86,6 @@ jobs:
steps.cache-openssl3.outputs.cache-hit != 'true' || steps.cache-openssl3.outputs.cache-hit != 'true' ||
steps.cache-boringssl.outputs.cache-hit != 'true' || steps.cache-boringssl.outputs.cache-hit != 'true' ||
steps.cache-awslc.outputs.cache-hit != 'true' || steps.cache-awslc.outputs.cache-hit != 'true' ||
steps.cache-wolfssl.outputs.cache-hit != 'true' ||
steps.cache-nghttp3.outputs.cache-hit != 'true' || steps.cache-nghttp3.outputs.cache-hit != 'true' ||
steps.cache-ngtcp2-openssl1.outputs.cache-hit != 'true' || steps.cache-ngtcp2-openssl1.outputs.cache-hit != 'true' ||
steps.cache-ngtcp2-openssl3.outputs.cache-hit != 'true' steps.cache-ngtcp2-openssl3.outputs.cache-hit != 'true'
@@ -104,6 +96,8 @@ jobs:
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install \ sudo apt-get install \
g++-12 \
clang-15 \
autoconf \ autoconf \
automake \ automake \
autotools-dev \ autotools-dev \
@@ -118,27 +112,28 @@ jobs:
brew install \ brew install \
autoconf \ autoconf \
automake \ automake \
pkg-config \
libtool libtool
- name: Build libbpf - name: Build libbpf
if: steps.cache-libbpf.outputs.cache-hit != 'true' && runner.os == 'Linux' if: steps.cache-libbpf.outputs.cache-hit != 'true' && runner.os == 'Linux'
run: | run: |
git clone --recursive --shallow-submodules -b ${{ env.LIBBPF_VERSION }} https://github.com/libbpf/libbpf git clone --recursive -b ${{ env.LIBBPF_VERSION }} https://github.com/libbpf/libbpf
cd libbpf cd libbpf
make -C src install PREFIX=$PWD/build make -C src install PREFIX=$PWD/build
- name: Build quictls/openssl v1.1.1 - name: Build quictls/openssl v1.1.1
if: steps.cache-openssl1.outputs.cache-hit != 'true' if: steps.cache-openssl1.outputs.cache-hit != 'true'
run: | run: |
git clone --recursive --shallow-submodules --depth 1 -b OpenSSL_${{ env.OPENSSL1_VERSION }} https://github.com/quictls/openssl openssl1 git clone --recursive --depth 1 -b OpenSSL_${{ env.OPENSSL1_VERSION }} https://github.com/quictls/openssl openssl1
cd openssl1 cd openssl1
./config --prefix=$PWD/build ./config --prefix=$PWD/build
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
make install_sw make install_sw
- name: Build openssl/openssl v3.x - name: Build quictls/openssl v3.x
if: steps.cache-openssl3.outputs.cache-hit != 'true' if: steps.cache-openssl3.outputs.cache-hit != 'true'
run: | run: |
git clone --recursive --shallow-submodules --depth 1 -b openssl-${{ env.OPENSSL3_VERSION }} https://github.com/openssl/openssl openssl3 git clone --recursive --depth 1 -b openssl-${{ env.OPENSSL3_VERSION }} https://github.com/quictls/openssl openssl3
cd openssl3 cd openssl3
./config enable-ktls --prefix=$PWD/build ./config enable-ktls --prefix=$PWD/build --libdir=$PWD/build/lib
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
make install_sw make install_sw
- name: Build BoringSSL - name: Build BoringSSL
@@ -157,56 +152,42 @@ jobs:
- name: Build aws-lc - name: Build aws-lc
if: steps.cache-awslc.outputs.cache-hit != 'true' if: steps.cache-awslc.outputs.cache-hit != 'true'
run: | run: |
git clone --recursive --shallow-submodules --depth 1 -b "${AWSLC_VERSION}" https://github.com/aws/aws-lc git clone --recursive --depth 1 -b "${AWSLC_VERSION}" https://github.com/aws/aws-lc
cd aws-lc cd aws-lc
cmake -B build -DDISABLE_GO=ON cmake -B build -DDISABLE_GO=ON
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" -C build make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" -C build
- name: Build wolfSSL
if: steps.cache-wolfssl.outputs.cache-hit != 'true'
run: |
git clone --depth 1 -b ${{ env.WOLFSSL_VERSION }} https://github.com/wolfSSL/wolfssl
cd wolfssl
autoreconf -i
./configure --disable-dependency-tracking --prefix=$PWD/build \
--enable-all --enable-harden --disable-ech
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
make install
- name: Build nghttp3 - name: Build nghttp3
if: steps.cache-nghttp3.outputs.cache-hit != 'true' if: steps.cache-nghttp3.outputs.cache-hit != 'true'
run: | run: |
git clone --recursive --shallow-submodules --depth 1 -b ${{ env.NGHTTP3_VERSION}} https://github.com/ngtcp2/nghttp3 git clone --recursive --depth 1 -b ${{ env.NGHTTP3_VERSION}} https://github.com/ngtcp2/nghttp3
cd nghttp3 cd nghttp3
autoreconf -i autoreconf -i
./configure --disable-dependency-tracking --prefix=$PWD/build \ ./configure --prefix=$PWD/build --enable-lib-only
--enable-lib-only
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check
make install make install
- name: Build ngtcp2 + quictls/openssl v1.1.1 + BoringSSL - name: Build ngtcp2 + quictls/openssl v1.1.1 + BoringSSL
if: steps.cache-ngtcp2-openssl1.outputs.cache-hit != 'true' if: steps.cache-ngtcp2-openssl1.outputs.cache-hit != 'true'
run: | run: |
git clone --recursive --shallow-submodules --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl1 git clone --recursive --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl1
cd ngtcp2-openssl1 cd ngtcp2-openssl1
autoreconf -i autoreconf -i
./configure --prefix=$PWD/build --enable-lib-only \ ./configure --prefix=$PWD/build --enable-lib-only \
PKG_CONFIG_PATH="../openssl1/build/lib/pkgconfig:../wolfssl/build/lib/pkgconfig" \ PKG_CONFIG_PATH="../openssl1/build/lib/pkgconfig" \
BORINGSSL_CFLAGS="-I$PWD/../boringssl/include/" \ BORINGSSL_CFLAGS="-I$PWD/../boringssl/include/" \
BORINGSSL_LIBS="-L$PWD/../boringssl/build -lssl -lcrypto" \ BORINGSSL_LIBS="-L$PWD/../boringssl/build/ssl -lssl -L$PWD/../boringssl/build/crypto -lcrypto" \
--disable-dependency-tracking \ --with-boringssl
--with-boringssl \
--with-wolfssl
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check
make install make install
- name: Build ngtcp2 + quictls/openssl v3.x + aws-lc - name: Build ngtcp2 + quictls/openssl v3.x + aws-lc
if: steps.cache-ngtcp2-openssl3.outputs.cache-hit != 'true' if: steps.cache-ngtcp2-openssl3.outputs.cache-hit != 'true'
run: | run: |
git clone --recursive --shallow-submodules --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl3 git clone --recursive --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl3
cd ngtcp2-openssl3 cd ngtcp2-openssl3
autoreconf -i autoreconf -i
./configure --prefix=$PWD/build --enable-lib-only \ ./configure --prefix=$PWD/build --enable-lib-only \
PKG_CONFIG_PATH="../openssl3/build/lib64/pkgconfig:../openssl3/build/lib/pkgconfig" \ PKG_CONFIG_PATH="../openssl3/build/lib/pkgconfig" \
BORINGSSL_CFLAGS="-I$PWD/../aws-lc/include/" \ BORINGSSL_CFLAGS="-I$PWD/../aws-lc/include/" \
BORINGSSL_LIBS="-L$PWD/../aws-lc/build/ssl -lssl -L$PWD/../aws-lc/build/crypto -lcrypto" \ BORINGSSL_LIBS="-L$PWD/../aws-lc/build/ssl -lssl -L$PWD/../aws-lc/build/crypto -lcrypto" \
--disable-dependency-tracking \
--with-boringssl --with-boringssl
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check
make install make install
@@ -217,42 +198,46 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-24.04, macos-14, macos-15] os: [ubuntu-22.04, macos-13, macos-14]
compiler: [gcc, clang] compiler: [gcc, clang]
buildtool: [autotools, cmake] buildtool: [autotools, cmake]
http3: [http3, no-http3] http3: [http3, no-http3]
openssl: [openssl1, openssl3, boringssl, awslc, wolfssl] openssl: [openssl1, openssl3, boringssl, awslc]
exclude: exclude:
- http3: no-http3 - os: macos-13
openssl: openssl3 openssl: openssl3
- os: macos-14 - os: macos-14
openssl: openssl3
- http3: no-http3
openssl: openssl3
- os: macos-13
compiler: gcc compiler: gcc
- os: macos-15 - os: macos-14
compiler: gcc compiler: gcc
- # disable macos cmake because of include path issue
os: macos-13
buildtool: cmake
- # disable macos cmake because of include path issue - # disable macos cmake because of include path issue
os: macos-14 os: macos-14
buildtool: cmake buildtool: cmake
- # disable macos cmake because of include path issue - os: macos-13
os: macos-15
buildtool: cmake
- os: macos-14
openssl: boringssl openssl: boringssl
- os: macos-15 - os: macos-14
openssl: boringssl openssl: boringssl
- openssl: boringssl - openssl: boringssl
buildtool: cmake buildtool: cmake
- openssl: boringssl - openssl: boringssl
compiler: gcc compiler: gcc
- os: macos-14 - os: macos-13
openssl: awslc openssl: awslc
- os: macos-15 - os: macos-14
openssl: awslc openssl: awslc
- openssl: awslc - openssl: awslc
buildtool: cmake buildtool: cmake
- openssl: awslc - openssl: awslc
compiler: gcc compiler: gcc
include: include:
- os: ubuntu-24.04 - os: ubuntu-22.04
compiler: clang compiler: clang
buildtool: distcheck buildtool: distcheck
http3: http3 http3: http3
@@ -262,7 +247,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- name: Linux setup - name: Linux setup
@@ -270,8 +255,8 @@ jobs:
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install \ sudo apt-get install \
g++-14 \ g++-12 \
clang-19 \ clang-15 \
autoconf \ autoconf \
automake \ automake \
autotools-dev \ autotools-dev \
@@ -302,16 +287,20 @@ jobs:
run: | run: |
brew install \ brew install \
libev \ libev \
libevent \
c-ares \
libressl \ libressl \
brotli \
autoconf \ autoconf \
automake \ automake \
pkg-config \
libtool libtool
echo 'PKG_CONFIG_PATH=/usr/local/opt/libressl/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig' >> $GITHUB_ENV echo 'PKG_CONFIG_PATH=/usr/local/opt/libressl/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig' >> $GITHUB_ENV
- name: Setup clang (Linux) - name: Setup clang (Linux)
if: runner.os == 'Linux' && matrix.compiler == 'clang' if: runner.os == 'Linux' && matrix.compiler == 'clang'
run: | run: |
echo 'CC=clang-19' >> $GITHUB_ENV echo 'CC=clang-15' >> $GITHUB_ENV
echo 'CXX=clang++-19' >> $GITHUB_ENV echo 'CXX=clang++-15' >> $GITHUB_ENV
- name: Setup clang (MacOS) - name: Setup clang (MacOS)
if: runner.os == 'macOS' && matrix.compiler == 'clang' if: runner.os == 'macOS' && matrix.compiler == 'clang'
run: | run: |
@@ -320,8 +309,8 @@ jobs:
- name: Setup gcc (Linux) - name: Setup gcc (Linux)
if: runner.os == 'Linux' && matrix.compiler == 'gcc' if: runner.os == 'Linux' && matrix.compiler == 'gcc'
run: | run: |
echo 'CC=gcc-14' >> $GITHUB_ENV echo 'CC=gcc-12' >> $GITHUB_ENV
echo 'CXX=g++-14' >> $GITHUB_ENV echo 'CXX=g++-12' >> $GITHUB_ENV
# g++-12 is known to produce false positive warnings. # g++-12 is known to produce false positive warnings.
echo 'CXXFLAGS=-Wno-restrict' >> $GITHUB_ENV echo 'CXXFLAGS=-Wno-restrict' >> $GITHUB_ENV
- name: Setup gcc (MacOS) - name: Setup gcc (MacOS)
@@ -341,13 +330,13 @@ jobs:
run: | run: |
cd libbpf cd libbpf
EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --with-libbpf" EXTRA_AUTOTOOLS_OPTS="--with-libbpf"
EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DWITH_LIBBPF=1" EXTRA_CMAKE_OPTS="-DWITH_LIBBPF=1"
echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV
- name: Setup libev variables - name: Setup libev variables
if: runner.os == 'macOS' if: matrix.os == 'macos-14'
run: | run: |
LIBEV_CFLAGS="-I/opt/homebrew/Cellar/libev/4.33/include" LIBEV_CFLAGS="-I/opt/homebrew/Cellar/libev/4.33/include"
LIBEV_LIBS="-L/opt/homebrew/Cellar/libev/4.33/lib -lev" LIBEV_LIBS="-L/opt/homebrew/Cellar/libev/4.33/lib -lev"
@@ -361,7 +350,7 @@ jobs:
path: openssl1/build path: openssl1/build
key: ${{ matrix.os }}-openssl-${{ env.OPENSSL1_VERSION }} key: ${{ matrix.os }}-openssl-${{ env.OPENSSL1_VERSION }}
fail-on-cache-miss: true fail-on-cache-miss: true
- name: Restore openssl/openssl v3.x cache - name: Restore quictls/openssl v3.x cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
if: matrix.openssl == 'openssl3' if: matrix.openssl == 'openssl3'
with: with:
@@ -373,8 +362,8 @@ jobs:
if: matrix.openssl == 'boringssl' if: matrix.openssl == 'boringssl'
with: with:
path: | path: |
boringssl/build/libcrypto.a boringssl/build/crypto/libcrypto.a
boringssl/build/libssl.a boringssl/build/ssl/libssl.a
boringssl/include boringssl/include
key: ${{ matrix.os }}-boringssl-${{ env.BORINGSSL_VERSION }} key: ${{ matrix.os }}-boringssl-${{ env.BORINGSSL_VERSION }}
fail-on-cache-miss: true fail-on-cache-miss: true
@@ -394,7 +383,7 @@ jobs:
cd boringssl cd boringssl
OPENSSL_CFLAGS="-I$PWD/include/" OPENSSL_CFLAGS="-I$PWD/include/"
OPENSSL_LIBS="-L$PWD/build -lssl -lcrypto -pthread" OPENSSL_LIBS="-L$PWD/build/ssl -lssl -L$PWD/build/crypto -lcrypto -pthread"
EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --without-neverbleed --without-jemalloc --disable-examples" EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --without-neverbleed --without-jemalloc --disable-examples"
echo 'OPENSSL_CFLAGS='"$OPENSSL_CFLAGS" >> $GITHUB_ENV echo 'OPENSSL_CFLAGS='"$OPENSSL_CFLAGS" >> $GITHUB_ENV
@@ -416,21 +405,6 @@ jobs:
echo 'BORINGSSL_CFLAGS='"$OPENSSL_CFLAGS" >> $GITHUB_ENV echo 'BORINGSSL_CFLAGS='"$OPENSSL_CFLAGS" >> $GITHUB_ENV
echo 'BORINGSSL_LIBS='"$OPENSSL_LIBS" >> $GITHUB_ENV echo 'BORINGSSL_LIBS='"$OPENSSL_LIBS" >> $GITHUB_ENV
echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
- name: Restore wolfSSL cache
uses: actions/cache/restore@v4
if: matrix.openssl == 'wolfssl'
with:
path: wolfssl/build
key: ${{ matrix.os }}-wolfssl-${{ env.WOLFSSL_VERSION }}
fail-on-cache-miss: true
- name: Set wolfSSL variables
if: matrix.openssl == 'wolfssl'
run: |
EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --with-wolfssl --without-neverbleed"
EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DWITH_WOLFSSL=1 -DWITH_NEVERBLEED=0 -DENABLE_EXAMPLES=0"
echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV
- name: Restore nghttp3 cache - name: Restore nghttp3 cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
if: matrix.http3 == 'http3' if: matrix.http3 == 'http3'
@@ -440,7 +414,7 @@ jobs:
fail-on-cache-miss: true fail-on-cache-miss: true
- name: Restore ngtcp2 + quictls/openssl v1.1.1 cache + BoringSSL - name: Restore ngtcp2 + quictls/openssl v1.1.1 cache + BoringSSL
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
if: matrix.http3 == 'http3' && (matrix.openssl == 'openssl1' || matrix.openssl == 'boringssl' || matrix.openssl == 'wolfssl') if: matrix.http3 == 'http3' && (matrix.openssl == 'openssl1' || matrix.openssl == 'boringssl')
with: with:
path: ngtcp2-openssl1/build path: ngtcp2-openssl1/build
key: ${{ matrix.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL1_VERSION }} key: ${{ matrix.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL1_VERSION }}
@@ -455,18 +429,18 @@ jobs:
- name: Setup extra environment variables - name: Setup extra environment variables
if: matrix.http3 == 'no-http3' if: matrix.http3 == 'no-http3'
run: | run: |
PKG_CONFIG_PATH="$PWD/openssl1/build/lib/pkgconfig:$PWD/openssl3/build/lib64/pkgconfig:$PWD/openssl3/build/lib/pkgconfig:$PWD/wolfssl/build/lib/pkgconfig:$PKG_CONFIG_PATH" PKG_CONFIG_PATH="$PWD/openssl1/build/lib/pkgconfig:$PWD/openssl3/build/lib/pkgconfig"
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/openssl1/build/lib -Wl,-rpath,$PWD/openssl3/build/lib64 -Wl,-rpath,$PWD/openssl3/build/lib" LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/openssl1/build/lib -Wl,-rpath,$PWD/openssl3/build/lib"
echo 'PKG_CONFIG_PATH='"$PKG_CONFIG_PATH" >> $GITHUB_ENV echo 'PKG_CONFIG_PATH='"$PKG_CONFIG_PATH" >> $GITHUB_ENV
echo 'LDFLAGS='"$LDFLAGS" >> $GITHUB_ENV echo 'LDFLAGS='"$LDFLAGS" >> $GITHUB_ENV
- name: Setup extra environment variables for HTTP/3 - name: Setup extra environment variables for HTTP/3
if: matrix.http3 == 'http3' if: matrix.http3 == 'http3'
run: | run: |
PKG_CONFIG_PATH="$PWD/openssl1/build/lib/pkgconfig:$PWD/openssl3/build/lib64/pkgconfig:$PWD/openssl3/build/lib/pkgconfig:$PWD/wolfssl/build/lib/pkgconfig:$PWD/nghttp3/build/lib/pkgconfig:$PWD/ngtcp2-openssl1/build/lib/pkgconfig:$PWD/ngtcp2-openssl3/build/lib/pkgconfig:$PWD/libbpf/build/lib64/pkgconfig:$PKG_CONFIG_PATH" PKG_CONFIG_PATH="$PWD/openssl1/build/lib/pkgconfig:$PWD/openssl3/build/lib/pkgconfig:$PWD/nghttp3/build/lib/pkgconfig:$PWD/ngtcp2-openssl1/build/lib/pkgconfig:$PWD/ngtcp2-openssl3/build/lib/pkgconfig:$PWD/libbpf/build/lib64/pkgconfig:$PKG_CONFIG_PATH"
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/openssl1/build/lib -Wl,-rpath,$PWD/openssl3/build/lib64 -Wl,-rpath,$PWD/openssl3/build/lib -Wl,-rpath,$PWD/libbpf/build/lib64" LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/openssl1/build/lib -Wl,-rpath,$PWD/openssl3/build/lib -Wl,-rpath,$PWD/libbpf/build/lib64"
EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --enable-http3" EXTRA_AUTOTOOLS_OPTS="--enable-http3 $EXTRA_AUTOTOOLS_OPTS"
EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DENABLE_HTTP3=1" EXTRA_CMAKE_OPTS="-DENABLE_HTTP3=1 $EXTRA_CMAKE_OPTS"
echo 'PKG_CONFIG_PATH='"$PKG_CONFIG_PATH" >> $GITHUB_ENV echo 'PKG_CONFIG_PATH='"$PKG_CONFIG_PATH" >> $GITHUB_ENV
echo 'LDFLAGS='"$LDFLAGS" >> $GITHUB_ENV echo 'LDFLAGS='"$LDFLAGS" >> $GITHUB_ENV
@@ -475,7 +449,7 @@ jobs:
- name: Configure autotools - name: Configure autotools
run: | run: |
autoreconf -i autoreconf -i
./configure --disable-dependency-tracking ./configure
- name: Make distribution and unpack - name: Make distribution and unpack
if: matrix.buildtool != 'distcheck' if: matrix.buildtool != 'distcheck'
run: | run: |
@@ -504,14 +478,14 @@ jobs:
run: | run: |
cd $NGHTTP2_BUILD_DIR cd $NGHTTP2_BUILD_DIR
./configure --disable-dependency-tracking --with-mruby --with-neverbleed --with-libev --with-libbrotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS ./configure --with-mruby --with-neverbleed --with-libev --with-libbrotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS
make -j"$(nproc)" check make -j"$(nproc)" check
- name: Build nghttp2 with autotools (MacOS) - name: Build nghttp2 with autotools (MacOS)
if: matrix.buildtool == 'autotools' && runner.os == 'macOS' if: matrix.buildtool == 'autotools' && runner.os == 'macOS'
run: | run: |
cd $NGHTTP2_BUILD_DIR cd $NGHTTP2_BUILD_DIR
./configure --disable-dependency-tracking --with-mruby --with-libev --with-libbrotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS ./configure --with-mruby --with-libev --with-libbrotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS
make -j"$(sysctl -n hw.ncpu)" check make -j"$(sysctl -n hw.ncpu)" check
- name: Build nghttp2 with autotools (distcheck) - name: Build nghttp2 with autotools (distcheck)
if: matrix.buildtool == 'distcheck' if: matrix.buildtool == 'distcheck'
@@ -527,13 +501,12 @@ jobs:
- uses: actions/setup-go@v5 - uses: actions/setup-go@v5
if: matrix.buildtool != 'distcheck' if: matrix.buildtool != 'distcheck'
with: with:
go-version: "1.24" go-version-file: go.mod
- name: Integration test - name: Integration test
# Integration tests for nghttpx; autotools erases build # Integration tests for nghttpx; autotools erases build
# artifacts. # artifacts.
if: matrix.buildtool != 'distcheck' if: matrix.buildtool != 'distcheck'
run: | run: |
sudo sh -c 'echo "127.0.0.1 127.0.0.1.nip.io" >> /etc/hosts'
cd $NGHTTP2_BUILD_DIR/integration-tests cd $NGHTTP2_BUILD_DIR/integration-tests
make it make it
@@ -542,22 +515,19 @@ jobs:
matrix: matrix:
host: [x86_64-w64-mingw32, i686-w64-mingw32] host: [x86_64-w64-mingw32, i686-w64-mingw32]
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
env: env:
HOST: ${{ matrix.host }} HOST: ${{ matrix.host }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- name: Prepare for i386
if: matrix.host == 'i686-w64-mingw32'
run: |
sudo dpkg --add-architecture i386
- name: Linux setup - name: Linux setup
run: | run: |
sudo dpkg --add-architecture i386
sudo apt-get update sudo apt-get update
sudo apt-get install \ sudo apt-get install \
gcc-mingw-w64 \ gcc-mingw-w64 \
@@ -570,16 +540,16 @@ jobs:
- name: Configure autotools - name: Configure autotools
run: | run: |
autoreconf -i && \ autoreconf -i && \
./configure --disable-dependency-tracking --enable-werror \ ./configure --enable-werror --enable-lib-only --host="$HOST" \
--enable-lib-only --host="$HOST" \
CFLAGS="-g -O2 -D_WIN32_WINNT=0x0600" LIBS="-pthread" CFLAGS="-g -O2 -D_WIN32_WINNT=0x0600" LIBS="-pthread"
- name: Build nghttp2 - name: Build nghttp2
run: | run: |
make -j$(nproc) make -j$(nproc)
make -j$(nproc) check TESTS="" make -j$(nproc) check TESTS=""
- name: Run tests - name: Run tests
if: matrix.host == 'x86_64-w64-mingw32'
run: | run: |
export WINEPATH="/usr/${{ matrix.host }}/lib;$(winepath -w /usr/lib/x86_64-linux-gnu/wine/x86_64-windows)" export WINEPATH=/usr/x86_64-w64-mingw32/lib
cd tests cd tests
wine main.exe wine main.exe
@@ -597,7 +567,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- uses: microsoft/setup-msbuild@v2 - uses: microsoft/setup-msbuild@v2
@@ -619,10 +589,10 @@ jobs:
permissions: permissions:
contents: write contents: write
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: recursive submodules: recursive

View File

@@ -11,14 +11,14 @@ permissions: read-all
jobs: jobs:
build: build:
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Build - name: Build
uses: docker/build-push-action@v6 uses: docker/build-push-action@v5
with: with:
context: docker context: docker
build-args: NGHTTP2_BRANCH=${{ github.ref_name }} build-args: NGHTTP2_BRANCH=${{ github.ref_name }}

View File

@@ -6,11 +6,10 @@ on:
permissions: permissions:
issues: write issues: write
actions: write
jobs: jobs:
stale: stale:
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v9
@@ -18,5 +17,4 @@ jobs:
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.' stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
days-before-stale: 30 days-before-stale: 30
days-before-close: 7 days-before-close: 7
days-before-pr-stale: -1
exempt-all-milestones: true exempt-all-milestones: true

3
.gitmodules vendored
View File

@@ -8,6 +8,3 @@
[submodule "tests/munit"] [submodule "tests/munit"]
path = tests/munit path = tests/munit
url = https://github.com/ngtcp2/munit url = https://github.com/ngtcp2/munit
[submodule "third-party/urlparse"]
path = third-party/urlparse
url = https://github.com/ngtcp2/urlparse

12
AUTHORS
View File

@@ -47,7 +47,6 @@ David Beitey
David Korczynski David Korczynski
David Weekly David Weekly
Deel Deel
Deep Chordia
Dimitris Apostolou Dimitris Apostolou
Dmitri Tikhonov Dmitri Tikhonov
Dmitriy Vetutnev Dmitriy Vetutnev
@@ -80,7 +79,6 @@ Jonas Kvinge
Josh Braegger Josh Braegger
José F. Calcerrada José F. Calcerrada
Kamil Dudka Kamil Dudka
Karthik Dasari
Kazuho Oku Kazuho Oku
Kenny (kang-yen) Peng Kenny (kang-yen) Peng
Kenny Peng Kenny Peng
@@ -90,11 +88,9 @@ LazyHamster
Leo Neat Leo Neat
Lorenz Nickel Lorenz Nickel
Lucas Pardue Lucas Pardue
Lukas Märdian
MATSUMOTO Ryosuke MATSUMOTO Ryosuke
Marc Bachmann Marc Bachmann
Marcelo Trylesinski Marcelo Trylesinski
Mark Boddington
Matt Rudary Matt Rudary
Matt Way Matt Way
Michael Kaufmann Michael Kaufmann
@@ -106,7 +102,6 @@ Nora Shoemaker
Paweł Wegner Paweł Wegner
Pedro Santos Pedro Santos
Peeyush Aggarwal Peeyush Aggarwal
Peng-Yu Chen
Peter Wu Peter Wu
Piotr Sikora Piotr Sikora
PufferOverflow PufferOverflow
@@ -118,11 +113,9 @@ Richard Wolfert
Rick Lei Rick Lei
Ross Smith II Ross Smith II
Rudi Heitbaum Rudi Heitbaum
Ryan Carsten Schmidt
Ryo Ota Ryo Ota
Scott Mitchell Scott Mitchell
Sebastiaan Deckers Sebastiaan Deckers
Sergei Trofimovich
Sergey Fedorov Sergey Fedorov
Shelley Vohr Shelley Vohr
Simon Frankenberger Simon Frankenberger
@@ -136,7 +129,6 @@ Syohei YOSHIDA
Tapanito Tapanito
Tatsuhiko Kubo Tatsuhiko Kubo
Tatsuhiro Tsujikawa Tatsuhiro Tsujikawa
Thomas Devoogdt
Tobias Geerinckx-Rice Tobias Geerinckx-Rice
Tom Harwood Tom Harwood
Tomas Krizek Tomas Krizek
@@ -146,22 +138,18 @@ Vernon Tang
Viacheslav Biriukov Viacheslav Biriukov
Viktor Szakats Viktor Szakats
Viktor Szépe Viktor Szépe
Ville Vesilehto
Wenfeng Liu Wenfeng Liu
William A Rowe Jr William A Rowe Jr
Xiaoguang Sun Xiaoguang Sun
Zachary Turner
Zhuoyun Wei Zhuoyun Wei
acesso acesso
ayanamist ayanamist
bmarques1995
bxshi bxshi
clemahieu clemahieu
dalf dalf
dawg dawg
es es
fangdingjun fangdingjun
feicong
hrxi hrxi
jwchoi jwchoi
kumagi kumagi

View File

@@ -24,13 +24,13 @@
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
# 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.67.0 LANGUAGES C) project(nghttp2 VERSION 1.62.1)
# See versioning rule: # See versioning rule:
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
set(LT_CURRENT 43) set(LT_CURRENT 42)
set(LT_REVISION 0) set(LT_REVISION 1)
set(LT_AGE 29) set(LT_AGE 28)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
include(Version) include(Version)
@@ -58,7 +58,6 @@ find_package(Python3 COMPONENTS Interpreter)
# Auto-detection of features that can be toggled # Auto-detection of features that can be toggled
if(NOT ENABLE_LIB_ONLY) if(NOT ENABLE_LIB_ONLY)
enable_language(CXX)
find_package(Libev 4.11) find_package(Libev 4.11)
find_package(Libcares 1.7.5) find_package(Libcares 1.7.5)
find_package(ZLIB 1.2.3) find_package(ZLIB 1.2.3)
@@ -66,20 +65,20 @@ if(NOT ENABLE_LIB_ONLY)
find_package(Libbrotlidec 1.0.9) find_package(Libbrotlidec 1.0.9)
endif() endif()
if(WITH_WOLFSSL) find_package(OpenSSL 1.1.1)
find_package(WolfSSL 5.7.0) find_package(Libngtcp2 1.0.0)
else() find_package(Libngtcp2_crypto_quictls 1.0.0)
find_package(OpenSSL 1.1.1) if(LIBNGTCP2_CRYPTO_QUICTLS_FOUND)
set(HAVE_LIBNGTCP2_CRYPTO_QUICTLS 1)
endif() endif()
find_package(Libngtcp2 1.15.0) find_package(Libnghttp3 1.1.0)
find_package(Libnghttp3 1.11.0)
if(WITH_LIBBPF) if(WITH_LIBBPF)
find_package(Libbpf 0.7.0) find_package(Libbpf 0.7.0)
if(NOT LIBBPF_FOUND) if(NOT LIBBPF_FOUND)
message(FATAL_ERROR "libbpf was requested (WITH_LIBBPF=1) but not found.") message(FATAL_ERROR "libbpf was requested (WITH_LIBBPF=1) but not found.")
endif() endif()
endif() endif()
if((OPENSSL_FOUND OR WOLFSSL_FOUND) AND LIBEV_FOUND AND ZLIB_FOUND) if(OPENSSL_FOUND AND LIBEV_FOUND AND ZLIB_FOUND)
set(ENABLE_APP_DEFAULT ON) set(ENABLE_APP_DEFAULT ON)
else() else()
set(ENABLE_APP_DEFAULT OFF) set(ENABLE_APP_DEFAULT OFF)
@@ -124,31 +123,30 @@ else()
set(HINT_NORETURN) set(HINT_NORETURN)
endif() endif()
if(NOT ENABLE_LIB_ONLY) include(ExtractValidFlags)
include(ExtractValidFlags) foreach(_cxx1x_flag -std=c++20)
foreach(_cxx1x_flag -std=c++20) extract_valid_cxx_flags(_cxx1x_flag_supported ${_cxx1x_flag})
extract_valid_cxx_flags(_cxx1x_flag_supported ${_cxx1x_flag}) if(_cxx1x_flag_supported)
if(_cxx1x_flag_supported) set(CXX1XCXXFLAGS ${_cxx1x_flag})
set(CXX1XCXXFLAGS ${_cxx1x_flag}) break()
break() endif()
endif() endforeach()
endforeach()
include(CMakePushCheckState)
include(CheckCXXSourceCompiles)
cmake_push_check_state()
set(CMAKE_REQUIRED_DEFINITIONS "${CXX1XCXXFLAGS}")
# Check that std::future is available.
check_cxx_source_compiles("
#include <vector>
#include <future>
int main() { std::vector<std::future<int>> v; }" HAVE_STD_FUTURE)
# Check that std::map::emplace is available for g++-4.7.
check_cxx_source_compiles("
#include <map>
int main() { std::map<int, int>().emplace(1, 2); }" HAVE_STD_MAP_EMPLACE)
cmake_pop_check_state()
include(CMakePushCheckState)
include(CheckCXXSourceCompiles)
cmake_push_check_state()
set(CMAKE_REQUIRED_DEFINITIONS "${CXX1XCXXFLAGS}")
# Check that std::future is available.
check_cxx_source_compiles("
#include <vector>
#include <future>
int main() { std::vector<std::future<int>> v; }" HAVE_STD_FUTURE)
# Check that std::chrono::time_zone is available.
check_cxx_source_compiles("
#include <chrono>
int main() { auto tz = std::chrono::current_zone(); (void)tz; }" HAVE_STD_CHRONO_TIME_ZONE)
cmake_pop_check_state()
endif()
# Checks for libraries. # Checks for libraries.
# Additional libraries required for programs under src directory. # Additional libraries required for programs under src directory.
@@ -176,7 +174,7 @@ add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
# openssl (for src) # openssl (for src)
include(CheckSymbolExists) include(CheckSymbolExists)
set(HAVE_OPENSSL ${OPENSSL_FOUND}) set(HAVE_OPENSSL ${OPENSSL_FOUND})
if(NOT ENABLE_LIB_ONLY AND OPENSSL_FOUND) if(OPENSSL_FOUND)
set(OPENSSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR}) set(OPENSSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})
cmake_push_check_state() cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
@@ -184,14 +182,10 @@ if(NOT ENABLE_LIB_ONLY AND OPENSSL_FOUND)
if(WIN32) if(WIN32)
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}" "ws2_32" "bcrypt") set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}" "ws2_32" "bcrypt")
endif() endif()
check_symbol_exists("LIBRESSL_VERSION_NUMBER" "openssl/opensslv.h" LIBRESSL_FOUND)
if(ENABLE_HTTP3) if(ENABLE_HTTP3)
check_symbol_exists(SSL_provide_quic_data "openssl/ssl.h" HAVE_SSL_PROVIDE_QUIC_DATA) check_symbol_exists(SSL_provide_quic_data "openssl/ssl.h" HAVE_SSL_PROVIDE_QUIC_DATA)
if(NOT HAVE_SSL_PROVIDE_QUIC_DATA) if(NOT HAVE_SSL_PROVIDE_QUIC_DATA)
check_symbol_exists(SSL_set_quic_tls_cbs "openssl/ssl.h" HAVE_SSL_SET_QUIC_TLS_CBS) message(WARNING "OpenSSL in ${OPENSSL_LIBRARIES} does not have SSL_provide_quic_data. HTTP/3 support cannot be enabled")
if(NOT HAVE_SSL_SET_QUIC_TLS_CBS)
message(WARNING "OpenSSL in ${OPENSSL_LIBRARIES} has neither SSL_provide_quic_data nor SSL_set_quic_tls_cbs. HTTP/3 support cannot be enabled")
endif()
endif() endif()
endif() endif()
cmake_pop_check_state() cmake_pop_check_state()
@@ -199,22 +193,6 @@ else()
set(OPENSSL_INCLUDE_DIRS "") set(OPENSSL_INCLUDE_DIRS "")
set(OPENSSL_LIBRARIES "") set(OPENSSL_LIBRARIES "")
endif() endif()
# wolfSSL (for src)
set(HAVE_WOLFSSL ${WOLFSSL_FOUND})
if(WOLFSSL_FOUND)
set(WOLFSSL_INCLUDE_DIRS ${WOLFSSL_INCLUDE_DIR})
cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES "${WOLFSSL_INCLUDE_DIR}")
set(CMAKE_REQUIRED_LIBRARIES "${WOLFSSL_LIBRARIES}")
check_symbol_exists(SSL_provide_quic_data "wolfssl/options.h;wolfssl/ssl.h" HAVE_WOLFSSL_SSL_PROVIDE_QUIC_DATA)
if(NOT HAVE_WOLFSSL_SSL_PROVIDE_QUIC_DATA)
message(WARNING "wolfSSL in ${WOLFSSL_LIBRARIES} does not have SSL_provide_quic_data. HTTP/3 support cannot be enabled")
endif()
cmake_pop_check_state()
else()
set(WOLFSSL_INCLUDE_DIRS "")
set(WOLFSSL_LIBRARIES "")
endif()
# libev (for src) # libev (for src)
set(HAVE_LIBEV ${LIBEV_FOUND}) set(HAVE_LIBEV ${LIBEV_FOUND})
set(HAVE_ZLIB ${ZLIB_FOUND}) set(HAVE_ZLIB ${ZLIB_FOUND})
@@ -267,45 +245,13 @@ int main() { enum bpf_stats_type foo; (void)foo; }" HAVE_BPF_STATS_TYPE)
endif() endif()
# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL and libev # The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL and libev
if(ENABLE_APP AND NOT (ZLIB_FOUND AND (OPENSSL_FOUND OR WOLFSSL_FOUND) AND LIBEV_FOUND)) if(ENABLE_APP AND NOT (ZLIB_FOUND AND OPENSSL_FOUND AND LIBEV_FOUND))
message(FATAL_ERROR "Applications were requested (ENABLE_APP=1) but dependencies are not met.") message(FATAL_ERROR "Applications were requested (ENABLE_APP=1) but dependencies are not met.")
endif() endif()
if(ENABLE_HTTP3) # HTTP/3 requires quictls/openssl, libngtcp2, libngtcp2_crypto_quictls
if(HAVE_SSL_PROVIDE_QUIC_DATA AND NOT LIBRESSL_FOUND) # and libnghttp3.
find_package(Libngtcp2_crypto_quictls 1.15.0) if(ENABLE_HTTP3 AND NOT (HAVE_SSL_PROVIDE_QUIC_DATA AND LIBNGTCP2_FOUND AND LIBNGTCP2_CRYPTO_QUICTLS_FOUND AND LIBNGHTTP3_FOUND))
if(LIBNGTCP2_CRYPTO_QUICTLS_FOUND)
set(HAVE_LIBNGTCP2_CRYPTO_QUICTLS 1)
endif()
elseif(HAVE_SSL_PROVIDE_QUIC_DATA AND LIBRESSL_FOUND)
find_package(Libngtcp2_crypto_libressl 1.15.0)
if(LIBNGTCP2_CRYPTO_LIBRESSL_FOUND)
set(HAVE_LIBNGTCP2_CRYPTO_LIBRESSL 1)
endif()
elseif(HAVE_WOLFSSL_SSL_PROVIDE_QUIC_DATA)
find_package(Libngtcp2_crypto_wolfssl 1.15.0)
if(LIBNGTCP2_CRYPTO_WOLFSSL_FOUND)
set(HAVE_LIBNGTCP2_CRYPTO_WOLFSSL 1)
endif()
elseif(HAVE_SSL_SET_QUIC_TLS_CBS)
find_package(Libngtcp2_crypto_ossl 1.15.0)
if(LIBNGTCP2_CRYPTO_OSSL_FOUND)
set(HAVE_LIBNGTCP2_CRYPTO_OSSL 1)
endif()
endif()
endif()
# HTTP/3 requires libngtcp2 + nghttp3 + one of:
#
# - quictls/openssl + libngtcp2_crypto_quictls
# - libressl + libngtcp2_crypto_libressl
# - wolfSSL + libngtcp2_crypto_wolfssl
# - openssl/openssl + libngtcp2_crypto_ossl
if(ENABLE_HTTP3 AND NOT (LIBNGTCP2_FOUND AND LIBNGHTTP3_FOUND AND
((HAVE_SSL_PROVIDE_QUIC_DATA AND NOT LIBRESSL_FOUND AND LIBNGTCP2_CRYPTO_QUICTLS_FOUND) OR
(HAVE_SSL_PROVIDE_QUIC_DATA AND LIBRESSL_FOUND AND LIBNGTCP2_CRYPTO_LIBRESSL_FOUND) OR
(HAVE_WOLFSSL_SSL_PROVIDE_QUIC_DATA AND LIBNGTCP2_CRYPTO_WOLFSSL_FOUND) OR
(HAVE_SSL_SET_QUIC_TLS_CBS AND LIBNGTCP2_CRYPTO_OSSL_FOUND))))
message(FATAL_ERROR "HTTP/3 was requested (ENABLE_HTTP3=1) but dependencies are not met.") message(FATAL_ERROR "HTTP/3 was requested (ENABLE_HTTP3=1) but dependencies are not met.")
endif() endif()
@@ -380,9 +326,8 @@ check_function_exists(_Exit HAVE__EXIT)
check_function_exists(accept4 HAVE_ACCEPT4) check_function_exists(accept4 HAVE_ACCEPT4)
check_function_exists(clock_gettime HAVE_CLOCK_GETTIME) check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
check_function_exists(mkostemp HAVE_MKOSTEMP) check_function_exists(mkostemp HAVE_MKOSTEMP)
check_function_exists(pipe2 HAVE_PIPE2)
check_symbol_exists(GetTickCount64 "windows.h;sysinfoapi.h" HAVE_GETTICKCOUNT64) check_symbol_exists(GetTickCount64 sysinfoapi.h HAVE_GETTICKCOUNT64)
include(CheckSymbolExists) include(CheckSymbolExists)
# XXX does this correctly detect initgroups (un)availability on cygwin? # XXX does this correctly detect initgroups (un)availability on cygwin?
@@ -499,6 +444,7 @@ if(ENABLE_DOC)
add_subdirectory(doc) add_subdirectory(doc)
endif() endif()
add_subdirectory(contrib) add_subdirectory(contrib)
add_subdirectory(script)
add_subdirectory(bpf) add_subdirectory(bpf)
@@ -526,14 +472,11 @@ message(STATUS "summary of build options:
Build Test: ${BUILD_TESTING} Build Test: ${BUILD_TESTING}
Libs: Libs:
OpenSSL: ${HAVE_OPENSSL} (LIBS='${OPENSSL_LIBRARIES}') OpenSSL: ${HAVE_OPENSSL} (LIBS='${OPENSSL_LIBRARIES}')
wolfSSL: ${HAVE_WOLFSSL} (LIBS='${WOLFSSL_LIBRARIES}')
Libxml2: ${HAVE_LIBXML2} (LIBS='${LIBXML2_LIBRARIES}') Libxml2: ${HAVE_LIBXML2} (LIBS='${LIBXML2_LIBRARIES}')
Libev: ${HAVE_LIBEV} (LIBS='${LIBEV_LIBRARIES}') Libev: ${HAVE_LIBEV} (LIBS='${LIBEV_LIBRARIES}')
Libc-ares: ${HAVE_LIBCARES} (LIBS='${LIBCARES_LIBRARIES}') Libc-ares: ${HAVE_LIBCARES} (LIBS='${LIBCARES_LIBRARIES}')
Libngtcp2: ${HAVE_LIBNGTCP2} (LIBS='${LIBNGTCP2_LIBRARIES}') Libngtcp2: ${HAVE_LIBNGTCP2} (LIBS='${LIBNGTCP2_LIBRARIES}')
Libngtcp2_crypto_quictls: ${HAVE_LIBNGTCP2_CRYPTO_QUICTLS} (LIBS='${LIBNGTCP2_CRYPTO_QUICTLS_LIBRARIES}') Libngtcp2_crypto_quictls: ${HAVE_LIBNGTCP2_CRYPTO_QUICTLS} (LIBS='${LIBNGTCP2_CRYPTO_QUICTLS_LIBRARIES}')
Libngtcp2_crypto_libressl: ${HAVE_LIBNGTCP2_CRYPTO_LIBRESSL} (LIBS='${LIBNGTCP2_CRYPTO_LIBRESSL_LIBRARIES}')
Libngtcp2_crypto_wolfssl: ${HAVE_LIBNGTCP2_CRYPTO_WOLFSSL} (LIBS='${LIBNGTCP2_CRYPTO_WOLFSSL_LIBRARIES}')
Libnghttp3: ${HAVE_LIBNGHTTP3} (LIBS='${LIBNGHTTP3_LIBRARIES}') Libnghttp3: ${HAVE_LIBNGHTTP3} (LIBS='${LIBNGHTTP3_LIBRARIES}')
Libbpf: ${HAVE_LIBBPF} (LIBS='${LIBBPF_LIBRARIES}') Libbpf: ${HAVE_LIBBPF} (LIBS='${LIBBPF_LIBRARIES}')
Libevent(SSL): ${HAVE_LIBEVENT_OPENSSL} (LIBS='${LIBEVENT_OPENSSL_LIBRARIES}') Libevent(SSL): ${HAVE_LIBEVENT_OPENSSL} (LIBS='${LIBEVENT_OPENSSL_LIBRARIES}')

View File

@@ -25,6 +25,5 @@ option(WITH_JEMALLOC "Use jemalloc"
option(WITH_MRUBY "Use mruby") option(WITH_MRUBY "Use mruby")
option(WITH_NEVERBLEED "Use neverbleed") option(WITH_NEVERBLEED "Use neverbleed")
option(WITH_LIBBPF "Use libbpf") option(WITH_LIBBPF "Use libbpf")
option(WITH_WOLFSSL "Use wolfSSL")
# vim: ft=cmake: # vim: ft=cmake:

View File

@@ -12,21 +12,21 @@
# Only use standalone-toolchain for reduce size # Only use standalone-toolchain for reduce size
FROM ubuntu:24.04 FROM ubuntu:22.04
LABEL org.opencontainers.image.authors="Tatsuhiro Tsujikawa" MAINTAINER Tatsuhiro Tsujikawa
ARG NDK_VERSION=r27c ENV NDK_VERSION r25b
ARG NDK=/root/android-ndk-$NDK_VERSION ENV NDK /root/android-ndk-$NDK_VERSION
ARG TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64 ENV TOOLCHAIN $NDK/toolchains/llvm/prebuilt/linux-x86_64
ARG TARGET=aarch64-linux-android ENV TARGET aarch64-linux-android
ARG API=33 ENV API 33
ARG AR=$TOOLCHAIN/bin/llvm-ar ENV AR $TOOLCHAIN/bin/llvm-ar
ARG CC=$TOOLCHAIN/bin/$TARGET$API-clang ENV CC $TOOLCHAIN/bin/$TARGET$API-clang
ARG CXX=$TOOLCHAIN/bin/$TARGET$API-clang++ ENV CXX $TOOLCHAIN/bin/$TARGET$API-clang++
ARG LD=$TOOLCHAIN/bin/ld ENV LD $TOOLCHAIN/bin/ld
ARG RANDLIB=$TOOLCHAIN/bin/llvm-ranlib ENV RANDLIB $TOOLCHAIN/bin/llvm-ranlib
ARG STRIP=$TOOLCHAIN/bin/llvm-strip ENV STRIP $TOOLCHAIN/bin/llvm-strip
ARG PREFIX=/root/usr/local ENV PREFIX /root/usr/local
WORKDIR /root WORKDIR /root
RUN apt-get update && \ RUN apt-get update && \
@@ -42,11 +42,11 @@ RUN curl -L -O https://dl.google.com/android/repository/android-ndk-$NDK_VERSION
rm android-ndk-$NDK_VERSION-linux.zip rm android-ndk-$NDK_VERSION-linux.zip
# Setup version of libraries # Setup version of libraries
ARG OPENSSL_VERSION=1.1.1w ENV OPENSSL_VERSION 1.1.1q
ARG LIBEV_VERSION=4.33 ENV LIBEV_VERSION 4.33
ARG ZLIB_VERSION=1.3.1 ENV ZLIB_VERSION 1.2.13
ARG CARES_VERSION=1.18.1 ENV CARES_VERSION 1.18.1
ARG NGHTTP2_VERSION=master ENV NGHTTP2_VERSION master
WORKDIR /root/build WORKDIR /root/build
RUN curl -L -O https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz && \ RUN curl -L -O https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz && \
@@ -65,7 +65,6 @@ RUN curl -L -O http://dist.schmorp.de/libev/Attic/libev-$LIBEV_VERSION.tar.gz &&
WORKDIR /root/build/libev-$LIBEV_VERSION WORKDIR /root/build/libev-$LIBEV_VERSION
RUN ./configure \ RUN ./configure \
--disable-dependency-tracking \
--host=$TARGET \ --host=$TARGET \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \ --build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--prefix=$PREFIX \ --prefix=$PREFIX \
@@ -76,7 +75,7 @@ RUN ./configure \
make install make install
WORKDIR /root/build WORKDIR /root/build
RUN curl -L -O https://github.com/madler/zlib/releases/download/v$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz && \ RUN curl -L -O https://zlib.net/zlib-$ZLIB_VERSION.tar.gz && \
tar xf zlib-$ZLIB_VERSION.tar.gz && \ tar xf zlib-$ZLIB_VERSION.tar.gz && \
rm zlib-$ZLIB_VERSION.tar.gz rm zlib-$ZLIB_VERSION.tar.gz
@@ -91,13 +90,12 @@ RUN HOST=$TARGET \
WORKDIR /root/build WORKDIR /root/build
RUN curl -L -O https://github.com/c-ares/c-ares/releases/download/cares-1_18_1/c-ares-$CARES_VERSION.tar.gz && \ RUN curl -L -O https://c-ares.haxx.se/download/c-ares-$CARES_VERSION.tar.gz && \
tar xf c-ares-$CARES_VERSION.tar.gz && \ tar xf c-ares-$CARES_VERSION.tar.gz && \
rm c-ares-$CARES_VERSION.tar.gz rm c-ares-$CARES_VERSION.tar.gz
WORKDIR /root/build/c-ares-$CARES_VERSION WORKDIR /root/build/c-ares-$CARES_VERSION
RUN ./configure \ RUN ./configure \
--disable-dependency-tracking \
--host=$TARGET \ --host=$TARGET \
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \ --build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
--prefix=$PREFIX \ --prefix=$PREFIX \
@@ -105,11 +103,10 @@ RUN ./configure \
make install make install
WORKDIR /root/build WORKDIR /root/build
RUN git clone --recursive --shallow-submodules https://github.com/nghttp2/nghttp2 -b $NGHTTP2_VERSION --depth 1 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 \
--disable-dependency-tracking \
--enable-app \ --enable-app \
--disable-shared \ --disable-shared \
--host=$TARGET \ --host=$TARGET \
@@ -119,6 +116,6 @@ RUN autoreconf -i && \
--disable-threads \ --disable-threads \
CPPFLAGS="-fPIE -I$PREFIX/include" \ CPPFLAGS="-fPIE -I$PREFIX/include" \
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \ PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
LDFLAGS="-static-libstdc++ -static-libgcc -fPIE -pie -L$PREFIX/lib" && \ LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
make && \ make && \
$STRIP src/nghttpx src/nghttpd src/nghttp $STRIP src/nghttpx src/nghttpd src/nghttp

View File

@@ -20,8 +20,8 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = lib tests third-party src bpf examples integration-tests \ SUBDIRS = lib third-party src bpf examples tests integration-tests \
doc contrib doc contrib script
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
@@ -46,9 +46,6 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-env \
cmake/FindLibngtcp2_crypto_quictls.cmake \ cmake/FindLibngtcp2_crypto_quictls.cmake \
cmake/FindLibbrotlienc.cmake \ cmake/FindLibbrotlienc.cmake \
cmake/FindLibbrotlidec.cmake \ cmake/FindLibbrotlidec.cmake \
cmake/FindLibngtcp2_crypto_wolfssl.cmake \
cmake/FindLibngtcp2_crypto_ossl.cmake \
cmake/FindWolfSSL.cmake \
cmake/PickyWarningsC.cmake \ cmake/PickyWarningsC.cmake \
cmake/PickyWarningsCXX.cmake cmake/PickyWarningsCXX.cmake

View File

@@ -31,8 +31,9 @@ implementation.
* https://nghttp2.org/ (TLS + ALPN and HTTP/3) * https://nghttp2.org/ (TLS + ALPN and HTTP/3)
This endpoint supports ``h2`` and ``http/1.1`` via ALPN and requires This endpoint supports ``h2``, ``h2-16``, ``h2-14``, and
TLSv1.2 for HTTP/2 connection. ``http/1.1`` via ALPN and requires TLSv1.2 for HTTP/2
connection.
It also supports HTTP/3. It also supports HTTP/3.
@@ -60,8 +61,8 @@ To build and run the application programs (``nghttp``, ``nghttpd``,
``nghttpx`` and ``h2load``) in the ``src`` directory, the following packages ``nghttpx`` and ``h2load``) in the ``src`` directory, the following packages
are required: are required:
* OpenSSL >= 1.1.1; or wolfSSL >= 5.7.0; or LibreSSL >= 3.8.1; or * OpenSSL >= 1.1.1; or LibreSSL >= 3.8.1; or aws-lc >= 1.19.0; or
aws-lc >= 1.19.0; or BoringSSL BoringSSL
* libev >= 4.11 * libev >= 4.11
* zlib >= 1.2.3 * zlib >= 1.2.3
* libc-ares >= 1.7.5 * libc-ares >= 1.7.5
@@ -122,13 +123,13 @@ exploited. The neverbleed is disabled by default. To enable it, use
To enable the experimental HTTP/3 support for h2load and nghttpx, the To enable the experimental HTTP/3 support for h2load and nghttpx, the
following libraries are required: following libraries are required:
* `quictls * `OpenSSL with QUIC support
<https://github.com/quictls/openssl/tree/OpenSSL_1_1_1w+quic>`_; or <https://github.com/quictls/openssl/tree/OpenSSL_1_1_1w+quic>`_; or
wolfSSL; or LibreSSL (does not support 0RTT); or aws-lc; or LibreSSL (does not support 0RTT); or aws-lc; or
`BoringSSL <https://boringssl.googlesource.com/boringssl/>`_ (commit `BoringSSL <https://boringssl.googlesource.com/boringssl/>`_ (commit
729648fb79df7bc46c145e49b0dfd8d2a24232f1); or OpenSSL >= 3.5.0 6ab7c1482bf4cdc91c87bc512aaf68ffb18975ec)
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 1.15.0 * `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 1.4.0
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 1.11.0 * `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 1.1.0
Use ``--enable-http3`` configure option to enable HTTP/3 feature for Use ``--enable-http3`` configure option to enable HTTP/3 feature for
h2load and nghttpx. h2load and nghttpx.
@@ -143,14 +144,14 @@ Use ``--with-libbpf`` configure option to build eBPF program.
libelf-dev is needed to build libbpf. libelf-dev is needed to build libbpf.
For Ubuntu 20.04, you can build libbpf from `the source code For Ubuntu 20.04, you can build libbpf from `the source code
<https://github.com/libbpf/libbpf/releases>`_. nghttpx requires eBPF <https://github.com/libbpf/libbpf/releases/tag/v1.3.0>`_. nghttpx
program for reloading its configuration and hot swapping its requires eBPF program for reloading its configuration and hot swapping
executable. its executable.
Compiling libnghttp2 C source code requires a C99 compiler. gcc 4.8 Compiling libnghttp2 C source code requires a C99 compiler. gcc 4.8
is known to be adequate. In order to compile the C++ source code, is known to be adequate. In order to compile the C++ source code,
C++20 compliant compiler is required. At least g++ >= 12 and C++20 compliant compiler is required. At least g++ >= 1.12 and
clang++ >= 18 are known to work. clang++ >= 1.15 are known to work.
.. note:: .. note::
@@ -340,7 +341,7 @@ Build aws-lc:
.. code-block:: text .. code-block:: text
$ git clone --depth 1 -b v1.58.1 https://github.com/aws/aws-lc $ git clone --depth 1 -b v1.26.0 https://github.com/aws/aws-lc
$ cd aws-lc $ cd aws-lc
$ cmake -B build -DDISABLE_GO=ON --install-prefix=$PWD/opt $ cmake -B build -DDISABLE_GO=ON --install-prefix=$PWD/opt
$ make -j$(nproc) -C build $ make -j$(nproc) -C build
@@ -351,7 +352,7 @@ Build nghttp3:
.. code-block:: text .. code-block:: text
$ git clone --depth 1 -b v1.11.0 https://github.com/ngtcp2/nghttp3 $ git clone --depth 1 -b v1.3.0 https://github.com/ngtcp2/nghttp3
$ cd nghttp3 $ cd nghttp3
$ git submodule update --init --depth 1 $ git submodule update --init --depth 1
$ autoreconf -i $ autoreconf -i
@@ -364,7 +365,7 @@ Build ngtcp2:
.. code-block:: text .. code-block:: text
$ git clone --depth 1 -b v1.15.1 https://github.com/ngtcp2/ngtcp2 $ git clone --depth 1 -b v1.5.0 https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2 $ cd ngtcp2
$ git submodule update --init --depth 1 $ git submodule update --init --depth 1
$ autoreconf -i $ autoreconf -i
@@ -380,7 +381,7 @@ from source:
.. code-block:: text .. code-block:: text
$ git clone --depth 1 -b v1.6.2 https://github.com/libbpf/libbpf $ git clone --depth 1 -b v1.3.0 https://github.com/libbpf/libbpf
$ cd libbpf $ cd libbpf
$ PREFIX=$PWD/build make -C src install $ PREFIX=$PWD/build make -C src install
$ cd .. $ cd ..
@@ -394,7 +395,7 @@ Build nghttp2:
$ git submodule update --init $ git submodule update --init
$ autoreconf -i $ autoreconf -i
$ ./configure --with-mruby --enable-http3 --with-libbpf \ $ ./configure --with-mruby --enable-http3 --with-libbpf \
CC=clang-19 CXX=clang++-19 \ CC=clang-15 CXX=clang++-15 \
PKG_CONFIG_PATH="$PWD/../aws-lc/opt/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig:$PWD/../ngtcp2/build/lib/pkgconfig:$PWD/../libbpf/build/lib64/pkgconfig" \ PKG_CONFIG_PATH="$PWD/../aws-lc/opt/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig:$PWD/../ngtcp2/build/lib/pkgconfig:$PWD/../libbpf/build/lib64/pkgconfig" \
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../aws-lc/opt/lib -Wl,-rpath,$PWD/../libbpf/build/lib64" LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../aws-lc/opt/lib -Wl,-rpath,$PWD/../libbpf/build/lib64"
$ make -j$(nproc) $ make -j$(nproc)
@@ -846,10 +847,10 @@ 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), dynamic session IDs, session tickets (with automatic key rotation), OCSP
record sizing, ALPN, forward secrecy and HTTP/2. ``nghttpx`` also stapling, dynamic record sizing, ALPN, forward secrecy and HTTP/2.
offers the functionality to share ticket keys among multiple ``nghttpx`` also offers the functionality to share session cache and
``nghttpx`` instances via memcached. ticket keys among multiple ``nghttpx`` instances via memcached.
``nghttpx`` has 2 operation modes: ``nghttpx`` has 2 operation modes:

View File

@@ -63,26 +63,28 @@ typedef __u8 state_t[4][4];
dynamically trading ROM for RAM - This can be useful in (embedded) dynamically trading ROM for RAM - This can be useful in (embedded)
bootloader applications, where ROM is often limited. */ bootloader applications, where ROM is often limited. */
static const __u8 rsbox[256] = { static const __u8 rsbox[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}; 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
0x55, 0x21, 0x0c, 0x7d};
/* This function adds the round key to state. The round key is added /* This function adds the round key to state. The round key is added
to the state by an XOR function. */ to the state by an XOR function. */

View File

@@ -17,18 +17,12 @@ find_library(LIBCARES_LIBRARY
) )
if(LIBCARES_INCLUDE_DIR) if(LIBCARES_INCLUDE_DIR)
file(READ "${LIBCARES_INCLUDE_DIR}/ares_version.h" _ares_version_h) set(_version_regex "^#define[ \t]+ARES_VERSION_STR[ \t]+\"([^\"]+)\".*")
string(REGEX REPLACE ".*#define[ \t]+ARES_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" file(STRINGS "${LIBCARES_INCLUDE_DIR}/ares_version.h"
_ares_version_major ${_ares_version_h}) LIBCARES_VERSION REGEX "${_version_regex}")
string(REGEX REPLACE ".*#define[ \t]+ARES_VERSION_MINOR[ \t]+([0-9]+).*" "\\1" string(REGEX REPLACE "${_version_regex}" "\\1"
_ares_version_minor ${_ares_version_h}) LIBCARES_VERSION "${LIBCARES_VERSION}")
string(REGEX REPLACE ".*#define[ \t]+ARES_VERSION_PATCH[ \t]+([0-9]+).*" "\\1" unset(_version_regex)
_ares_version_patch ${_ares_version_h})
set(LIBCARES_VERSION "${_ares_version_major}.${_ares_version_minor}.${_ares_version_patch}")
unset(_ares_version_patch)
unset(_ares_version_minor)
unset(_ares_version_major)
unset(_ares_version_h)
endif() endif()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)

View File

@@ -1,43 +0,0 @@
# - Try to find libngtcp2_crypto_libressl
# Once done this will define
# LIBNGTCP2_CRYPTO_LIBRESSL_FOUND - System has libngtcp2_crypto_libressl
# LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIRS - The libngtcp2_crypto_libressl include directories
# LIBNGTCP2_CRYPTO_LIBRESSL_LIBRARIES - The libraries needed to use libngtcp2_crypto_libressl
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBNGTCP2_CRYPTO_LIBRESSL QUIET libngtcp2_crypto_libressl)
find_path(LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIR
NAMES ngtcp2/ngtcp2_crypto_quictls.h
HINTS ${PC_LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIRS}
)
find_library(LIBNGTCP2_CRYPTO_LIBRESSL_LIBRARY
NAMES ngtcp2_crypto_libressl
HINTS ${PC_LIBNGTCP2_CRYPTO_LIBRESSL_LIBRARY_DIRS}
)
if(LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIR)
set(_version_regex "^#define[ \t]+NGTCP2_VERSION[ \t]+\"([^\"]+)\".*")
file(STRINGS "${LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIR}/ngtcp2/version.h"
LIBNGTCP2_CRYPTO_LIBRESSL_VERSION REGEX "${_version_regex}")
string(REGEX REPLACE "${_version_regex}" "\\1"
LIBNGTCP2_CRYPTO_LIBRESSL_VERSION "${LIBNGTCP2_CRYPTO_LIBRESSL_VERSION}")
unset(_version_regex)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set
# LIBNGTCP2_CRYPTO_LIBRESSL_FOUND to TRUE if all listed variables are
# TRUE and the requested version matches.
find_package_handle_standard_args(Libngtcp2_crypto_libressl REQUIRED_VARS
LIBNGTCP2_CRYPTO_LIBRESSL_LIBRARY
LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIR
VERSION_VAR LIBNGTCP2_CRYPTO_LIBRESSL_VERSION)
if(LIBNGTCP2_CRYPTO_LIBRESSL_FOUND)
set(LIBNGTCP2_CRYPTO_LIBRESSL_LIBRARIES ${LIBNGTCP2_CRYPTO_LIBRESSL_LIBRARY})
set(LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIRS ${LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIR})
endif()
mark_as_advanced(LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIR
LIBNGTCP2_CRYPTO_LIBRESSL_LIBRARY)

View File

@@ -1,43 +0,0 @@
# - Try to find libngtcp2_crypto_ossl
# Once done this will define
# LIBNGTCP2_CRYPTO_OSSL_FOUND - System has libngtcp2_crypto_ossl
# LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIRS - The libngtcp2_crypto_ossl include directories
# LIBNGTCP2_CRYPTO_OSSL_LIBRARIES - The libraries needed to use libngtcp2_crypto_ossl
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBNGTCP2_CRYPTO_OSSL QUIET libngtcp2_crypto_ossl)
find_path(LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIR
NAMES ngtcp2/ngtcp2_crypto_ossl.h
HINTS ${PC_LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIRS}
)
find_library(LIBNGTCP2_CRYPTO_OSSL_LIBRARY
NAMES ngtcp2_crypto_ossl
HINTS ${PC_LIBNGTCP2_CRYPTO_OSSL_LIBRARY_DIRS}
)
if(LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIR)
set(_version_regex "^#define[ \t]+NGTCP2_VERSION[ \t]+\"([^\"]+)\".*")
file(STRINGS "${LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIR}/ngtcp2/version.h"
LIBNGTCP2_CRYPTO_OSSL_VERSION REGEX "${_version_regex}")
string(REGEX REPLACE "${_version_regex}" "\\1"
LIBNGTCP2_CRYPTO_OSSL_VERSION "${LIBNGTCP2_CRYPTO_OSSL_VERSION}")
unset(_version_regex)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set
# LIBNGTCP2_CRYPTO_OSSL_FOUND to TRUE if all listed variables are
# TRUE and the requested version matches.
find_package_handle_standard_args(Libngtcp2_crypto_ossl REQUIRED_VARS
LIBNGTCP2_CRYPTO_OSSL_LIBRARY
LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIR
VERSION_VAR LIBNGTCP2_CRYPTO_OSSL_VERSION)
if(LIBNGTCP2_CRYPTO_OSSL_FOUND)
set(LIBNGTCP2_CRYPTO_OSSL_LIBRARIES ${LIBNGTCP2_CRYPTO_OSSL_LIBRARY})
set(LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIRS ${LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIR})
endif()
mark_as_advanced(LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIR
LIBNGTCP2_CRYPTO_OSSL_LIBRARY)

View File

@@ -1,43 +0,0 @@
# - Try to find libngtcp2_crypto_wolfssl
# Once done this will define
# LIBNGTCP2_CRYPTO_WOLFSSL_FOUND - System has libngtcp2_crypto_wolfssl
# LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIRS - The libngtcp2_crypto_wolfssl include directories
# LIBNGTCP2_CRYPTO_WOLFSSL_LIBRARIES - The libraries needed to use libngtcp2_crypto_wolfssl
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBNGTCP2_CRYPTO_WOLFSSL QUIET libngtcp2_crypto_wolfssl)
find_path(LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIR
NAMES ngtcp2/ngtcp2_crypto_wolfssl.h
HINTS ${PC_LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIRS}
)
find_library(LIBNGTCP2_CRYPTO_WOLFSSL_LIBRARY
NAMES ngtcp2_crypto_wolfssl
HINTS ${PC_LIBNGTCP2_CRYPTO_WOLFSSL_LIBRARY_DIRS}
)
if(LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIR)
set(_version_regex "^#define[ \t]+NGTCP2_VERSION[ \t]+\"([^\"]+)\".*")
file(STRINGS "${LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIR}/ngtcp2/version.h"
LIBNGTCP2_CRYPTO_WOLFSSL_VERSION REGEX "${_version_regex}")
string(REGEX REPLACE "${_version_regex}" "\\1"
LIBNGTCP2_CRYPTO_WOLFSSL_VERSION "${LIBNGTCP2_CRYPTO_WOLFSSL_VERSION}")
unset(_version_regex)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set
# LIBNGTCP2_CRYPTO_WOLFSSL_FOUND to TRUE if all listed variables are
# TRUE and the requested version matches.
find_package_handle_standard_args(Libngtcp2_crypto_wolfssl REQUIRED_VARS
LIBNGTCP2_CRYPTO_WOLFSSL_LIBRARY
LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIR
VERSION_VAR LIBNGTCP2_CRYPTO_WOLFSSL_VERSION)
if(LIBNGTCP2_CRYPTO_WOLFSSL_FOUND)
set(LIBNGTCP2_CRYPTO_WOLFSSL_LIBRARIES ${LIBNGTCP2_CRYPTO_WOLFSSL_LIBRARY})
set(LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIRS ${LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIR})
endif()
mark_as_advanced(LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIR
LIBNGTCP2_CRYPTO_WOLFSSL_LIBRARY)

View File

@@ -1,41 +0,0 @@
# - Try to find wolfssl
# Once done this will define
# WOLFSSL_FOUND - System has wolfssl
# WOLFSSL_INCLUDE_DIRS - The wolfssl include directories
# WOLFSSL_LIBRARIES - The libraries needed to use wolfssl
find_package(PkgConfig QUIET)
pkg_check_modules(PC_WOLFSSL QUIET wolfssl)
find_path(WOLFSSL_INCLUDE_DIR
NAMES wolfssl/ssl.h
HINTS ${PC_WOLFSSL_INCLUDE_DIRS}
)
find_library(WOLFSSL_LIBRARY
NAMES wolfssl
HINTS ${PC_WOLFSSL_LIBRARY_DIRS}
)
if(WOLFSSL_INCLUDE_DIR)
set(_version_regex "^#define[ \t]+LIBWOLFSSL_VERSION_STRING[ \t]+\"([^\"]+)\".*")
file(STRINGS "${WOLFSSL_INCLUDE_DIR}/wolfssl/version.h"
WOLFSSL_VERSION REGEX "${_version_regex}")
string(REGEX REPLACE "${_version_regex}" "\\1"
WOLFSSL_VERSION "${WOLFSSL_VERSION}")
unset(_version_regex)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set WOLFSSL_FOUND
# to TRUE if all listed variables are TRUE and the requested version
# matches.
find_package_handle_standard_args(WolfSSL REQUIRED_VARS
WOLFSSL_LIBRARY WOLFSSL_INCLUDE_DIR
VERSION_VAR WOLFSSL_VERSION)
if(WOLFSSL_FOUND)
set(WOLFSSL_LIBRARIES ${WOLFSSL_LIBRARY})
set(WOLFSSL_INCLUDE_DIRS ${WOLFSSL_INCLUDE_DIR})
endif()
mark_as_advanced(WOLFSSL_INCLUDE_DIR WOLFSSL_LIBRARY)

View File

@@ -58,10 +58,6 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID
list(APPEND WPICKY_ENABLE list(APPEND WPICKY_ENABLE
${WPICKY_COMMON_OLD} ${WPICKY_COMMON_OLD}
) )
list(APPEND WPICKY_ENABLE
# clang++-18 warns this when building with wolfSSL >= v5.7.6-stable.
-Wno-extern-c-compat
)
# Enable based on compiler version # Enable based on compiler version
if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.6) OR if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.6) OR
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.3)) (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.3))

View File

@@ -4,8 +4,8 @@
/* Define to `int' if <sys/types.h> does not define. */ /* Define to `int' if <sys/types.h> does not define. */
#cmakedefine ssize_t @ssize_t@ #cmakedefine ssize_t @ssize_t@
/* Define to 1 if you have the `std::chrono::time_zone`. */ /* Define to 1 if you have the `std::map::emplace`. */
#cmakedefine HAVE_STD_CHRONO_TIME_ZONE 1 #cmakedefine HAVE_STD_MAP_EMPLACE 1
/* Define to 1 if you have `libjansson` library. */ /* Define to 1 if you have `libjansson` library. */
#cmakedefine HAVE_JANSSON 1 #cmakedefine HAVE_JANSSON 1
@@ -31,9 +31,6 @@
/* Define to 1 if you have the `mkostemp` function. */ /* Define to 1 if you have the `mkostemp` function. */
#cmakedefine HAVE_MKOSTEMP 1 #cmakedefine HAVE_MKOSTEMP 1
/* Define to 1 if you have the `pipe2` function. */
#cmakedefine HAVE_PIPE2 1
/* Define to 1 if you have the `GetTickCount64` function. */ /* Define to 1 if you have the `GetTickCount64` function. */
#cmakedefine HAVE_GETTICKCOUNT64 1 #cmakedefine HAVE_GETTICKCOUNT64 1
@@ -100,17 +97,8 @@
/* Define to 1 if you have `libngtcp2_crypto_quictls` library. */ /* Define to 1 if you have `libngtcp2_crypto_quictls` library. */
#cmakedefine HAVE_LIBNGTCP2_CRYPTO_QUICTLS #cmakedefine HAVE_LIBNGTCP2_CRYPTO_QUICTLS
/* Define to 1 if you have `libngtcp2_crypto_libressl` library. */
#cmakedefine HAVE_LIBNGTCP2_CRYPTO_LIBRESSL
/* Define to 1 if you have `libngtcp2_crypto_wolfssl` library. */
#cmakedefine HAVE_LIBNGTCP2_CRYPTO_WOLFSSL 1
/* Define to 1 if you have `libev` library. */ /* Define to 1 if you have `libev` library. */
#cmakedefine HAVE_LIBEV 1 #cmakedefine HAVE_LIBEV 1
/* Define to 1 if you have `libbrotlienc` and `libbrotlidec` libraries. */ /* Define to 1 if you have `libbrotlienc` and `libbrotlidec` libraries. */
#cmakedefine HAVE_LIBBROTLI 1 #cmakedefine HAVE_LIBBROTLI 1
/* Define to 1 if you have `wolfssl` library. */
#cmakedefine HAVE_WOLFSSL 1

View File

@@ -25,7 +25,7 @@ dnl Do not change user variables!
dnl https://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html dnl https://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
AC_PREREQ(2.61) AC_PREREQ(2.61)
AC_INIT([nghttp2], [1.67.0], [t-tujikawa@users.sourceforge.net]) AC_INIT([nghttp2], [1.62.1], [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 https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html dnl https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 43) AC_SUBST(LT_CURRENT, 42)
AC_SUBST(LT_REVISION, 0) AC_SUBST(LT_REVISION, 1)
AC_SUBST(LT_AGE, 29) AC_SUBST(LT_AGE, 28)
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"`
@@ -127,11 +127,6 @@ AC_ARG_WITH([libcares],
[Use libc-ares [default=check]])], [Use libc-ares [default=check]])],
[request_libcares=$withval], [request_libcares=check]) [request_libcares=$withval], [request_libcares=check])
AC_ARG_WITH([wolfssl],
[AS_HELP_STRING([--with-wolfssl],
[Use wolfSSL [default=check]])],
[request_wolfssl=$withval], [request_wolfssl=check])
AC_ARG_WITH([openssl], AC_ARG_WITH([openssl],
[AS_HELP_STRING([--with-openssl], [AS_HELP_STRING([--with-openssl],
[Use openssl [default=check]])], [Use openssl [default=check]])],
@@ -272,6 +267,22 @@ std::vector<std::future<int>> v;
[have_std_future=no [have_std_future=no
AC_MSG_RESULT([no])]) AC_MSG_RESULT([no])])
# Check that std::map::emplace is available for g++-4.7.
AC_MSG_CHECKING([whether std::map::emplace is available])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[
#include <map>
]],
[[
std::map<int, int>().emplace(1, 2);
]])],
[AC_DEFINE([HAVE_STD_MAP_EMPLACE], [1],
[Define to 1 if you have the `std::map::emplace`.])
have_std_map_emplace=yes
AC_MSG_RESULT([yes])],
[have_std_map_emplace=no
AC_MSG_RESULT([no])])
# Check that std::atomic<std::shared_ptr<T>> is supported. # Check that std::atomic<std::shared_ptr<T>> is supported.
AC_MSG_CHECKING([whether std::atomic<std::shared_ptr<T>> is supported]) AC_MSG_CHECKING([whether std::atomic<std::shared_ptr<T>> is supported])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM( AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
@@ -291,21 +302,19 @@ a.store(p);
[have_atomic_std_shared_ptr=no [have_atomic_std_shared_ptr=no
AC_MSG_RESULT([no])]) AC_MSG_RESULT([no])])
# Check that std::chrono::time_zone is available. # Check that thread_local storage specifier is available
AC_MSG_CHECKING([whether std::chrono::time_zone is available]) AC_MSG_CHECKING([whether thread_local storage class specifier is available.])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM( AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
,
[[ [[
#include <chrono> thread_local int a = 0;
]], (void)a;
[[
auto tz = std::chrono::current_zone();
(void)tz;
]])], ]])],
[AC_DEFINE([HAVE_STD_CHRONO_TIME_ZONE], [1], [AC_DEFINE([HAVE_THREAD_LOCAL], [1],
[Define to 1 if you have the `std::chrono::time_zone`.]) [Define to 1 if you have thread_local storage specifier.])
have_std_chrono_time_zone=yes have_thread_local=yes
AC_MSG_RESULT([yes])], AC_MSG_RESULT([yes])],
[have_std_chrono_time_zone=no [have_Thread_local=no
AC_MSG_RESULT([no])]) AC_MSG_RESULT([no])])
CXXFLAGS=$save_CXXFLAGS CXXFLAGS=$save_CXXFLAGS
@@ -324,7 +333,7 @@ case "$host_os" in
*android*) *android*)
android_build=yes android_build=yes
# android does not need -pthread, but needs following 2 libs for C++ # android does not need -pthread, but needs following 2 libs for C++
APPLDFLAGS="$APPLDFLAGS -latomic" APPLDFLAGS="$APPLDFLAGS -lstdc++ -latomic"
;; ;;
*) *)
PTHREAD_LDFLAGS="-pthread" PTHREAD_LDFLAGS="-pthread"
@@ -402,15 +411,9 @@ if test "x${request_libev}" = "xyes" &&
AC_MSG_ERROR([libev was requested (--with-libev) but not found]) AC_MSG_ERROR([libev was requested (--with-libev) but not found])
fi fi
if test "x${request_openssl}" = "xyes" &&
test "x${request_wolfssl}" = "xyes"; then
AC_MSG_ERROR([Requesting both OpenSSL and wolfSSL is not allowed])
fi
# openssl (for src) # openssl (for src)
have_openssl=no have_openssl=no
if test "x${request_openssl}" != "xno" && if test "x${request_openssl}" != "xno"; then
test "x${request_wolfssl}" != "xyes"; then
PKG_CHECK_MODULES([OPENSSL], [openssl >= 1.1.1], PKG_CHECK_MODULES([OPENSSL], [openssl >= 1.1.1],
[have_openssl=yes], [have_openssl=no]) [have_openssl=yes], [have_openssl=no])
if test "x${have_openssl}" = "xno"; then if test "x${have_openssl}" = "xno"; then
@@ -436,22 +439,6 @@ if test "x${request_openssl}" != "xno" &&
[AC_MSG_RESULT([yes]); have_ssl_provide_quic_data=yes], [AC_MSG_RESULT([yes]); have_ssl_provide_quic_data=yes],
[AC_MSG_RESULT([no]); have_ssl_provide_quic_data=no]) [AC_MSG_RESULT([no]); have_ssl_provide_quic_data=no])
# Check whether this is libressl or not
AC_CHECK_DECLS([LIBRESSL_VERSION_NUMBER],
[have_libressl=yes], [have_libressl=no],
[[
#include <openssl/opensslv.h>
]])
AC_MSG_CHECKING([for SSL_set_quic_tls_cbs])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <openssl/ssl.h>
]], [[
SSL_set_quic_tls_cbs(NULL, NULL, NULL);
]])],
[AC_MSG_RESULT([yes]); have_ossl_quic=yes],
[AC_MSG_RESULT([no]); have_ossl_quic=no])
# boringssl has SSL_set_quic_early_data_context. # boringssl has SSL_set_quic_early_data_context.
AC_MSG_CHECKING([for SSL_set_quic_early_data_context]) AC_MSG_CHECKING([for SSL_set_quic_early_data_context])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
@@ -475,45 +462,6 @@ if test "x${request_openssl}" = "xyes" &&
AC_MSG_ERROR([openssl was requested (--with-openssl) but not found]) AC_MSG_ERROR([openssl was requested (--with-openssl) but not found])
fi fi
# wolfSSL (for src)
have_wolfssl=no
if test "x${request_wolfssl}" != "xno" &&
test "x${request_openssl}" != "xyes" &&
test "x${have_openssl}" != "xyes"; then
PKG_CHECK_MODULES([WOLFSSL], [wolfssl >= 5.7.0],
[have_wolfssl=yes], [have_wolfssl=no])
if test "x${have_wolfssl}" = "xno"; then
AC_MSG_NOTICE($WOLFSSL_PKG_ERRORS)
else
AC_DEFINE([HAVE_WOLFSSL], [1],
[Define to 1 if you have 'wolfssl' library.])
save_CFLAGS="$CFLAGS"
save_LIBS="$LIBS"
CFLAGS="$WOLFSSL_CFLAGS $CFLAGS"
LIBS="$WOLFSSL_LIBS $LIBS"
have_wolfssl_quic=no
AC_MSG_CHECKING([for wolfSSL QUIC])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <wolfssl/options.h>
#include <wolfssl/openssl/ssl.h>
]], [[
SSL_provide_quic_data(NULL, 0, NULL, 0);
]])],
[AC_MSG_RESULT([yes]); have_wolfssl_quic=yes],
[AC_MSG_RESULT([no]); have_wolfssl_quic=no])
CFLAGS="$save_CFLAGS"
LIBS="$save_LIBS"
fi
fi
if test "x${request_wolfssl}" = "xyes" &&
test "x${have_wolfssl}" != "xyes"; then
AC_MSG_ERROR([wolfSSL was requested (--with-wolfssl) but not found])
fi
# c-ares (for src) # c-ares (for src)
have_libcares=no have_libcares=no
if test "x${request_libcares}" != "xno"; then if test "x${request_libcares}" != "xno"; then
@@ -532,7 +480,7 @@ fi
# ngtcp2 (for src) # ngtcp2 (for src)
have_libngtcp2=no have_libngtcp2=no
if test "x${request_libngtcp2}" != "xno"; then if test "x${request_libngtcp2}" != "xno"; then
PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 1.15.0], [have_libngtcp2=yes], PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 1.4.0], [have_libngtcp2=yes],
[have_libngtcp2=no]) [have_libngtcp2=no])
if test "x${have_libngtcp2}" = "xno"; then if test "x${have_libngtcp2}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS) AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS)
@@ -544,36 +492,13 @@ if test "x${request_libngtcp2}" = "xyes" &&
AC_MSG_ERROR([libngtcp2 was requested (--with-libngtcp2) but not found]) AC_MSG_ERROR([libngtcp2 was requested (--with-libngtcp2) but not found])
fi fi
# ngtcp2_crypto_wolfssl (for src)
have_libngtcp2_crypto_wolfssl=no
if test "x${have_wolfssl_quic}" = "xyes" &&
test "x${request_libngtcp2}" != "xno"; then
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_WOLFSSL],
[libngtcp2_crypto_wolfssl >= 1.15.0],
[have_libngtcp2_crypto_wolfssl=yes],
[have_libngtcp2_crypto_wolfssl=no])
if test "x${have_libngtcp2_crypto_wolfssl}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_WOLFSSL_PKG_ERRORS)
else
AC_DEFINE([HAVE_LIBNGTCP2_CRYPTO_WOLFSSL], [1],
[Define to 1 if you have `libngtcp2_crypto_wolfssl` library.])
fi
fi
if test "x${have_wolfssl_quic}" = "xyes" &&
test "x${request_libngtcp2}" = "xyes" &&
test "x${have_libngtcp2_crypto_wolfssl}" != "xyes"; then
AC_MSG_ERROR([libngtcp2_crypto_wolfssl was requested (--with-libngtcp2) but not found])
fi
# ngtcp2_crypto_quictls (for src) # ngtcp2_crypto_quictls (for src)
have_libngtcp2_crypto_quictls=no have_libngtcp2_crypto_quictls=no
if test "x${have_ssl_provide_quic_data}" = "xyes" && if test "x${have_ssl_provide_quic_data}" = "xyes" &&
test "x${have_libressl}" != "xyes" &&
test "x${have_boringssl_quic}" != "xyes" && test "x${have_boringssl_quic}" != "xyes" &&
test "x${request_libngtcp2}" != "xno"; then test "x${request_libngtcp2}" != "xno"; then
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_QUICTLS], PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_QUICTLS],
[libngtcp2_crypto_quictls >= 1.15.0], [libngtcp2_crypto_quictls >= 1.0.0],
[have_libngtcp2_crypto_quictls=yes], [have_libngtcp2_crypto_quictls=yes],
[have_libngtcp2_crypto_quictls=no]) [have_libngtcp2_crypto_quictls=no])
if test "x${have_libngtcp2_crypto_quictls}" = "xno"; then if test "x${have_libngtcp2_crypto_quictls}" = "xno"; then
@@ -585,37 +510,12 @@ if test "x${have_ssl_provide_quic_data}" = "xyes" &&
fi fi
if test "x${have_ssl_provide_quic_data}" = "xyes" && if test "x${have_ssl_provide_quic_data}" = "xyes" &&
test "x${have_libressl}" != "xyes" &&
test "x${have_boringssl_quic}" != "xyes" && test "x${have_boringssl_quic}" != "xyes" &&
test "x${request_libngtcp2}" = "xyes" && test "x${request_libngtcp2}" = "xyes" &&
test "x${have_libngtcp2_crypto_quictls}" != "xyes"; then test "x${have_libngtcp2_crypto_quictls}" != "xyes"; then
AC_MSG_ERROR([libngtcp2_crypto_quictls was requested (--with-libngtcp2) but not found]) AC_MSG_ERROR([libngtcp2_crypto_quictls was requested (--with-libngtcp2) but not found])
fi fi
# ngtcp2_crypto_libressl (for src)
have_libngtcp2_crypto_libressl=no
if test "x${have_ssl_provide_quic_data}" = "xyes" &&
test "x${have_libressl}" = "xyes" &&
test "x${request_libngtcp2}" != "xno"; then
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_LIBRESSL],
[libngtcp2_crypto_libressl >= 1.15.0],
[have_libngtcp2_crypto_libressl=yes],
[have_libngtcp2_crypto_libressl=no])
if test "x${have_libngtcp2_crypto_libressl}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_LIBRESSL_PKG_ERRORS)
else
AC_DEFINE([HAVE_LIBNGTCP2_CRYPTO_LIBRESSL], [1],
[Define to 1 if you have `libngtcp2_crypto_libressl` library.])
fi
fi
if test "x${have_ssl_provide_quic_data}" = "xyes" &&
test "x${have_libressl}" = "xyes" &&
test "x${request_libngtcp2}" = "xyes" &&
test "x${have_libngtcp2_crypto_libressl}" != "xyes"; then
AC_MSG_ERROR([libngtcp2_crypto_libressl was requested (--with-libngtcp2) but not found])
fi
# ngtcp2_crypto_boringssl (for src) # ngtcp2_crypto_boringssl (for src)
have_libngtcp2_crypto_boringssl=no have_libngtcp2_crypto_boringssl=no
if test "x${have_boringssl_quic}" = "xyes" && if test "x${have_boringssl_quic}" = "xyes" &&
@@ -638,32 +538,10 @@ if test "x${have_boringssl_quic}" = "xyes" &&
AC_MSG_ERROR([libngtcp2_crypto_boringssl was requested (--with-libngtcp2) but not found]) AC_MSG_ERROR([libngtcp2_crypto_boringssl was requested (--with-libngtcp2) but not found])
fi fi
# ngtcp2_crypto_ossl (for src)
have_libngtcp2_crypto_ossl=no
if test "x${have_ossl_quic}" = "xyes" &&
test "x${request_libngtcp2}" != "xno"; then
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OSSL],
[libngtcp2_crypto_ossl >= 1.15.0],
[have_libngtcp2_crypto_ossl=yes],
[have_libngtcp2_crypto_ossl=no])
if test "x${have_libngtcp2_crypto_ossl}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_OSSL_PKG_ERRORS)
else
AC_DEFINE([HAVE_LIBNGTCP2_CRYPTO_OSSL], [1],
[Define to 1 if you have `libngtcp2_crypto_ossl` library.])
fi
fi
if test "x${have_ossl_quic}" = "xyes" &&
test "x${request_libngtcp2}" = "xyes" &&
test "x${have_libngtcp2_crypto_ossl}" != "xyes"; then
AC_MSG_ERROR([libngtcp2_crypto_ossl was requested (--with-libngtcp2) but not found])
fi
# nghttp3 (for src) # nghttp3 (for src)
have_libnghttp3=no have_libnghttp3=no
if test "x${request_libnghttp3}" != "xno"; then if test "x${request_libnghttp3}" != "xno"; then
PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 1.11.0], [have_libnghttp3=yes], PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 1.1.0], [have_libnghttp3=yes],
[have_libnghttp3=no]) [have_libnghttp3=no])
if test "x${have_libnghttp3}" = "xno"; then if test "x${have_libnghttp3}" = "xno"; then
AC_MSG_NOTICE($LIBNGHTTP3_PKG_ERRORS) AC_MSG_NOTICE($LIBNGHTTP3_PKG_ERRORS)
@@ -873,7 +751,7 @@ fi
enable_app=no enable_app=no
if test "x${request_app}" != "xno" && if test "x${request_app}" != "xno" &&
test "x${have_zlib}" = "xyes" && test "x${have_zlib}" = "xyes" &&
(test "x${have_openssl}" = "xyes" || test "x${have_wolfssl}" = "xyes") && test "x${have_openssl}" = "xyes" &&
test "x${have_libev}" = "xyes" && test "x${have_libev}" = "xyes" &&
test "x${have_libcares}" = "xyes"; then test "x${have_libcares}" = "xyes"; then
enable_app=yes enable_app=yes
@@ -890,11 +768,8 @@ AM_CONDITIONAL([ENABLE_APP], [ test "x${enable_app}" = "xyes" ])
enable_http3=no enable_http3=no
if test "x${request_http3}" != "xno" && if test "x${request_http3}" != "xno" &&
test "x${have_libngtcp2}" = "xyes" && test "x${have_libngtcp2}" = "xyes" &&
(test "x${have_libngtcp2_crypto_wolfssl}" = "xyes" || (test "x${have_libngtcp2_crypto_quictls}" = "xyes" ||
test "x${have_libngtcp2_crypto_quictls}" = "xyes" || test "x${have_libngtcp2_crypto_boringssl}" = "xyes") &&
test "x${have_libngtcp2_crypto_libressl}" = "xyes" ||
test "x${have_libngtcp2_crypto_boringssl}" = "xyes" ||
test "x${have_libngtcp2_crypto_ossl}" = "xyes") &&
test "x${have_libnghttp3}" = "xyes"; then test "x${have_libnghttp3}" = "xyes"; then
enable_http3=yes enable_http3=yes
AC_DEFINE([ENABLE_HTTP3], [1], [Define to 1 if HTTP/3 is enabled.]) AC_DEFINE([ENABLE_HTTP3], [1], [Define to 1 if HTTP/3 is enabled.])
@@ -1070,7 +945,6 @@ AC_CHECK_FUNCS([ \
memmove \ memmove \
memset \ memset \
mkostemp \ mkostemp \
pipe2 \
socket \ socket \
sqrt \ sqrt \
strchr \ strchr \
@@ -1175,7 +1049,6 @@ if test "x$werror" != "xno"; then
# Only work with Clang for the moment # Only work with Clang for the moment
AX_CHECK_COMPILE_FLAG([-Wheader-guard], [CFLAGS="$CFLAGS -Wheader-guard"]) AX_CHECK_COMPILE_FLAG([-Wheader-guard], [CFLAGS="$CFLAGS -Wheader-guard"])
AX_CHECK_COMPILE_FLAG([-Wsometimes-uninitialized], [CFLAGS="$CFLAGS -Wsometimes-uninitialized"]) AX_CHECK_COMPILE_FLAG([-Wsometimes-uninitialized], [CFLAGS="$CFLAGS -Wsometimes-uninitialized"])
AX_CHECK_COMPILE_FLAG([-Wextra-semi], [CFLAGS="$CFLAGS -Wextra-semi"])
# This is required because we pass format string as "const char*. # This is required because we pass format string as "const char*.
AX_CHECK_COMPILE_FLAG([-Wno-format-nonliteral], [CFLAGS="$CFLAGS -Wno-format-nonliteral"]) AX_CHECK_COMPILE_FLAG([-Wno-format-nonliteral], [CFLAGS="$CFLAGS -Wno-format-nonliteral"])
@@ -1186,13 +1059,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"])
AX_CHECK_COMPILE_FLAG([-Wextra-semi], [CXXFLAGS="$CXXFLAGS -Wextra-semi"])
AX_CHECK_COMPILE_FLAG([-Wconversion], [CXXFLAGS="$CXXFLAGS -Wconversion"])
# Disable noexcept-type warning of g++-7. This is not harmful as # Disable noexcept-type warning of g++-7. This is not harmful as
# long as all source files are compiled with the same compiler. # long as all source files are compiled with the same compiler.
AX_CHECK_COMPILE_FLAG([-Wno-noexcept-type], [CXXFLAGS="$CXXFLAGS -Wno-noexcept-type"]) AX_CHECK_COMPILE_FLAG([-Wno-noexcept-type], [CXXFLAGS="$CXXFLAGS -Wno-noexcept-type"])
# clang++-18 warns this when building with wolfSSL >= v5.7.6-stable.
AX_CHECK_COMPILE_FLAG([-Wno-extern-c-compat], [CXXFLAGS="$CXXFLAGS -Wno-extern-c-compat"])
AC_LANG_POP() AC_LANG_POP()
fi fi
@@ -1259,6 +1128,7 @@ AC_CONFIG_FILES([
doc/nghttp2ver.h.rst doc/nghttp2ver.h.rst
doc/contribute.rst doc/contribute.rst
contrib/Makefile contrib/Makefile
script/Makefile
]) ])
AC_OUTPUT AC_OUTPUT
@@ -1300,16 +1170,13 @@ AC_MSG_NOTICE([summary of build options:
Test: Test:
Failmalloc: ${enable_failmalloc} Failmalloc: ${enable_failmalloc}
Libs: Libs:
wolfSSL: ${have_wolfssl} (CFLAGS='${WOLFSSL_CFLAGS}' LIBS='${WOLFSSL_LIBS}')
OpenSSL: ${have_openssl} (CFLAGS='${OPENSSL_CFLAGS}' LIBS='${OPENSSL_LIBS}') OpenSSL: ${have_openssl} (CFLAGS='${OPENSSL_CFLAGS}' LIBS='${OPENSSL_LIBS}')
Libxml2: ${have_libxml2} (CFLAGS='${LIBXML2_CFLAGS}' LIBS='${LIBXML2_LIBS}') Libxml2: ${have_libxml2} (CFLAGS='${LIBXML2_CFLAGS}' LIBS='${LIBXML2_LIBS}')
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}')
libngtcp2: ${have_libngtcp2} (CFLAGS='${LIBNGTCP2_CFLAGS}' LIBS='${LIBNGTCP2_LIBS}') libngtcp2: ${have_libngtcp2} (CFLAGS='${LIBNGTCP2_CFLAGS}' LIBS='${LIBNGTCP2_LIBS}')
libngtcp2_crypto_quictls: ${have_libngtcp2_crypto_quictls} (CFLAGS='${LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_QUICTLS_LIBS}') libngtcp2_crypto_quictls: ${have_libngtcp2_crypto_quictls} (CFLAGS='${LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_QUICTLS_LIBS}')
libngtcp2_crypto_libressl: ${have_libngtcp2_crypto_libressl} (CFLAGS='${LIBNGTCP2_CRYPTO_LIBRESSL_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_LIBRESSL_LIBS}')
libngtcp2_crypto_boringssl: ${have_libngtcp2_crypto_boringssl} (CFLAGS='${LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_BORINGSSL_LIBS}') libngtcp2_crypto_boringssl: ${have_libngtcp2_crypto_boringssl} (CFLAGS='${LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_BORINGSSL_LIBS}')
libngtcp2_crypto_ossl: ${have_libngtcp2_crypto_ossl} (CFLAGS='${LIBNGTCP2_CRYPTO_OSSL_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_OSSL_LIBS}')
libnghttp3: ${have_libnghttp3} (CFLAGS='${LIBNGHTTP3_CFLAGS}' LIBS='${LIBNGHTTP3_LIBS}') libnghttp3: ${have_libnghttp3} (CFLAGS='${LIBNGHTTP3_CFLAGS}' LIBS='${LIBNGHTTP3_LIBS}')
libbpf: ${have_libbpf} (CFLAGS='${LIBBPF_CFLAGS}' LIBS='${LIBBPF_LIBS}') libbpf: ${have_libbpf} (CFLAGS='${LIBBPF_CFLAGS}' LIBS='${LIBBPF_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}')

View File

@@ -81,7 +81,6 @@ APIDOCS= \
nghttp2_option_set_max_outbound_ack.rst \ nghttp2_option_set_max_outbound_ack.rst \
nghttp2_option_set_max_settings.rst \ nghttp2_option_set_max_settings.rst \
nghttp2_option_set_stream_reset_rate_limit.rst \ nghttp2_option_set_stream_reset_rate_limit.rst \
nghttp2_option_set_glitch_rate_limit.rst \
nghttp2_pack_settings_payload.rst \ nghttp2_pack_settings_payload.rst \
nghttp2_pack_settings_payload2.rst \ nghttp2_pack_settings_payload2.rst \
nghttp2_priority_spec_check_default.rst \ nghttp2_priority_spec_check_default.rst \
@@ -115,7 +114,6 @@ APIDOCS= \
nghttp2_session_callbacks_set_on_stream_close_callback.rst \ nghttp2_session_callbacks_set_on_stream_close_callback.rst \
nghttp2_session_callbacks_set_pack_extension_callback.rst \ nghttp2_session_callbacks_set_pack_extension_callback.rst \
nghttp2_session_callbacks_set_pack_extension_callback2.rst \ nghttp2_session_callbacks_set_pack_extension_callback2.rst \
nghttp2_session_callbacks_set_rand_callback.rst \
nghttp2_session_callbacks_set_recv_callback.rst \ nghttp2_session_callbacks_set_recv_callback.rst \
nghttp2_session_callbacks_set_recv_callback2.rst \ nghttp2_session_callbacks_set_recv_callback2.rst \
nghttp2_session_callbacks_set_select_padding_callback.rst \ nghttp2_session_callbacks_set_select_padding_callback.rst \

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
"""
sphinxcontrib
~~~~~~~~~~~~~
This package is a namespace package that contains all extensions
distributed in the ``sphinx-contrib`` distribution.
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
__import__('pkg_resources').declare_namespace(__name__)

View File

@@ -8,7 +8,7 @@ _nghttp()
_get_comp_words_by_ref cur prev _get_comp_words_by_ref cur prev
case $cur in case $cur in
-*) -*)
COMPREPLY=( $( compgen -W '--verbose --null-out --remote-name --timeout --window-bits --connection-window-bits --get-assets --stat --header --trailer --cert --key --data --multiply --upgrade --extpri --peer-max-concurrent-streams --header-table-size --encoder-header-table-size --padding --har --color --continuation --no-content-length --hexdump --no-push --max-concurrent-streams --expect-continue --no-verify-peer --ktls --version --help ' -- "$cur" ) ) COMPREPLY=( $( compgen -W '--verbose --null-out --remote-name --timeout --window-bits --connection-window-bits --get-assets --stat --header --trailer --cert --key --data --multiply --upgrade --weight --peer-max-concurrent-streams --header-table-size --encoder-header-table-size --padding --har --color --continuation --no-content-length --no-dep --hexdump --no-push --max-concurrent-streams --expect-continue --no-verify-peer --ktls --no-rfc7540-pri --version --help ' -- "$cur" ) )
;; ;;
*) *)
_filedir _filedir

View File

@@ -8,7 +8,7 @@ _nghttpd()
_get_comp_words_by_ref cur prev _get_comp_words_by_ref cur prev
case $cur in case $cur in
-*) -*)
COMPREPLY=( $( compgen -W '--address --daemon --verify-client --htdocs --verbose --no-tls --header-table-size --encoder-header-table-size --color --push --padding --max-concurrent-streams --workers --error-gzip --window-bits --connection-window-bits --dh-param-file --early-response --trailer --hexdump --echo-upload --mime-types-file --no-content-length --ktls --version --help ' -- "$cur" ) ) COMPREPLY=( $( compgen -W '--address --daemon --verify-client --htdocs --verbose --no-tls --header-table-size --encoder-header-table-size --color --push --padding --max-concurrent-streams --workers --error-gzip --window-bits --connection-window-bits --dh-param-file --early-response --trailer --hexdump --echo-upload --mime-types-file --no-content-length --ktls --no-rfc7540-pri --version --help ' -- "$cur" ) )
;; ;;
*) *)
_filedir _filedir

View File

@@ -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 '--backend --frontend --backlog --backend-address-family --backend-http-proxy-uri --workers --single-thread --read-rate --read-burst --write-rate --write-burst --worker-read-rate --worker-read-burst --worker-write-rate --worker-write-burst --worker-frontend-connections --backend-connections-per-host --backend-connections-per-frontend --rlimit-nofile --rlimit-memlock --backend-request-buffer --backend-response-buffer --fastopen --no-kqueue --frontend-http2-idle-timeout --frontend-http3-idle-timeout --frontend-write-timeout --frontend-keep-alive-timeout --frontend-header-timeout --stream-read-timeout --stream-write-timeout --backend-read-timeout --backend-write-timeout --backend-connect-timeout --backend-keep-alive-timeout --listener-disable-timeout --frontend-http2-setting-timeout --backend-http2-settings-timeout --backend-max-backoff --ciphers --tls13-ciphers --client-ciphers --tls13-client-ciphers --ecdh-curves --insecure --cacert --private-key-passwd-file --subcert --dh-param-file --alpn-list --verify-client --verify-client-cacert --verify-client-tolerate-expired --client-private-key-file --client-cert-file --tls-min-proto-version --tls-max-proto-version --tls-ticket-key-file --tls-ticket-key-memcached --tls-ticket-key-memcached-address-family --tls-ticket-key-memcached-interval --tls-ticket-key-memcached-max-retry --tls-ticket-key-memcached-max-fail --tls-ticket-key-cipher --tls-ticket-key-memcached-cert-file --tls-ticket-key-memcached-private-key-file --tls-dyn-rec-warmup-threshold --tls-dyn-rec-idle-timeout --no-http2-cipher-block-list --client-no-http2-cipher-block-list --tls-sct-dir --psk-secrets --client-psk-secrets --tls-no-postpone-early-data --tls-max-early-data --tls-ktls --frontend-http2-max-concurrent-streams --backend-http2-max-concurrent-streams --frontend-http2-window-size --frontend-http2-connection-window-size --backend-http2-window-size --backend-http2-connection-window-size --http2-no-cookie-crumbling --padding --no-server-push --frontend-http2-optimize-write-buffer-size --frontend-http2-optimize-window-size --frontend-http2-encoder-dynamic-table-size --frontend-http2-decoder-dynamic-table-size --backend-http2-encoder-dynamic-table-size --backend-http2-decoder-dynamic-table-size --http2-proxy --log-level --accesslog-file --accesslog-syslog --accesslog-format --accesslog-write-early --errorlog-file --errorlog-syslog --syslog-facility --add-x-forwarded-for --strip-incoming-x-forwarded-for --no-add-x-forwarded-proto --no-strip-incoming-x-forwarded-proto --add-forwarded --strip-incoming-forwarded --forwarded-by --forwarded-for --no-via --no-strip-incoming-early-data --no-location-rewrite --host-rewrite --altsvc --http2-altsvc --add-request-header --add-response-header --request-header-field-buffer --max-request-header-fields --response-header-field-buffer --max-response-header-fields --error-page --server-name --no-server-rewrite --redirect-https-port --require-http-scheme --api-max-request-body --dns-cache-timeout --dns-lookup-timeout --dns-max-try --frontend-max-requests --frontend-http2-dump-request-header --frontend-http2-dump-response-header --frontend-frame-debug --daemon --pid-file --user --single-process --max-worker-processes --worker-process-grace-shutdown-period --mruby-file --ignore-per-pattern-mruby-error --frontend-quic-idle-timeout --frontend-quic-debug-log --quic-bpf-program-file --frontend-quic-early-data --frontend-quic-qlog-dir --frontend-quic-require-token --frontend-quic-congestion-controller --frontend-quic-secret-file --quic-server-id --frontend-quic-initial-rtt --no-quic-bpf --frontend-http3-window-size --frontend-http3-connection-window-size --frontend-http3-max-window-size --frontend-http3-max-connection-window-size --frontend-http3-max-concurrent-streams --conf --include --version --help ' -- "$cur" ) ) COMPREPLY=( $( compgen -W '--backend --frontend --backlog --backend-address-family --backend-http-proxy-uri --workers --single-thread --read-rate --read-burst --write-rate --write-burst --worker-read-rate --worker-read-burst --worker-write-rate --worker-write-burst --worker-frontend-connections --backend-connections-per-host --backend-connections-per-frontend --rlimit-nofile --rlimit-memlock --backend-request-buffer --backend-response-buffer --fastopen --no-kqueue --frontend-http2-idle-timeout --frontend-http3-idle-timeout --frontend-write-timeout --frontend-keep-alive-timeout --frontend-header-timeout --stream-read-timeout --stream-write-timeout --backend-read-timeout --backend-write-timeout --backend-connect-timeout --backend-keep-alive-timeout --listener-disable-timeout --frontend-http2-setting-timeout --backend-http2-settings-timeout --backend-max-backoff --ciphers --tls13-ciphers --client-ciphers --tls13-client-ciphers --ecdh-curves --insecure --cacert --private-key-passwd-file --subcert --dh-param-file --alpn-list --verify-client --verify-client-cacert --verify-client-tolerate-expired --client-private-key-file --client-cert-file --tls-min-proto-version --tls-max-proto-version --tls-ticket-key-file --tls-ticket-key-memcached --tls-ticket-key-memcached-address-family --tls-ticket-key-memcached-interval --tls-ticket-key-memcached-max-retry --tls-ticket-key-memcached-max-fail --tls-ticket-key-cipher --tls-ticket-key-memcached-cert-file --tls-ticket-key-memcached-private-key-file --fetch-ocsp-response-file --ocsp-update-interval --ocsp-startup --no-verify-ocsp --no-ocsp --tls-session-cache-memcached --tls-session-cache-memcached-address-family --tls-session-cache-memcached-cert-file --tls-session-cache-memcached-private-key-file --tls-dyn-rec-warmup-threshold --tls-dyn-rec-idle-timeout --no-http2-cipher-block-list --client-no-http2-cipher-block-list --tls-sct-dir --psk-secrets --client-psk-secrets --tls-no-postpone-early-data --tls-max-early-data --tls-ktls --frontend-http2-max-concurrent-streams --backend-http2-max-concurrent-streams --frontend-http2-window-size --frontend-http2-connection-window-size --backend-http2-window-size --backend-http2-connection-window-size --http2-no-cookie-crumbling --padding --no-server-push --frontend-http2-optimize-write-buffer-size --frontend-http2-optimize-window-size --frontend-http2-encoder-dynamic-table-size --frontend-http2-decoder-dynamic-table-size --backend-http2-encoder-dynamic-table-size --backend-http2-decoder-dynamic-table-size --http2-proxy --log-level --accesslog-file --accesslog-syslog --accesslog-format --accesslog-write-early --errorlog-file --errorlog-syslog --syslog-facility --add-x-forwarded-for --strip-incoming-x-forwarded-for --no-add-x-forwarded-proto --no-strip-incoming-x-forwarded-proto --add-forwarded --strip-incoming-forwarded --forwarded-by --forwarded-for --no-via --no-strip-incoming-early-data --no-location-rewrite --host-rewrite --altsvc --http2-altsvc --add-request-header --add-response-header --request-header-field-buffer --max-request-header-fields --response-header-field-buffer --max-response-header-fields --error-page --server-name --no-server-rewrite --redirect-https-port --require-http-scheme --api-max-request-body --dns-cache-timeout --dns-lookup-timeout --dns-max-try --frontend-max-requests --frontend-http2-dump-request-header --frontend-http2-dump-response-header --frontend-frame-debug --daemon --pid-file --user --single-process --max-worker-processes --worker-process-grace-shutdown-period --mruby-file --ignore-per-pattern-mruby-error --frontend-quic-idle-timeout --frontend-quic-debug-log --quic-bpf-program-file --frontend-quic-early-data --frontend-quic-qlog-dir --frontend-quic-require-token --frontend-quic-congestion-controller --frontend-quic-secret-file --quic-server-id --frontend-quic-initial-rtt --no-quic-bpf --frontend-http3-window-size --frontend-http3-connection-window-size --frontend-http3-max-window-size --frontend-http3-max-connection-window-size --frontend-http3-max-concurrent-streams --conf --include --version --help ' -- "$cur" ) )
;; ;;
*) *)
_filedir _filedir

View File

@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
.. ..
.TH "H2LOAD" "1" "Sep 02, 2025" "1.67.0" "nghttp2" .TH "H2LOAD" "1" "May 19, 2024" "1.62.1" "nghttp2"
.SH NAME .SH NAME
h2load \- HTTP/2 benchmarking tool h2load \- HTTP/2 benchmarking tool
.SH SYNOPSIS .SH SYNOPSIS
@@ -262,7 +262,7 @@ protocol comes first. The parameter must be delimited
by a single comma only and any white spaces are treated by a single comma only and any white spaces are treated
as a part of protocol string. as a part of protocol string.
.sp .sp
Default: \fBh2,http/1.1\fP Default: \fBh2,h2\-16,h2\-14,http/1.1\fP
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP

View File

@@ -221,7 +221,7 @@ OPTIONS
by a single comma only and any white spaces are treated by a single comma only and any white spaces are treated
as a part of protocol string. as a part of protocol string.
Default: ``h2,http/1.1`` Default: ``h2,h2-16,h2-14,http/1.1``
.. option:: --h1 .. option:: --h1

View File

@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
.. ..
.TH "NGHTTP" "1" "Sep 02, 2025" "1.67.0" "nghttp2" .TH "NGHTTP" "1" "May 19, 2024" "1.62.1" "nghttp2"
.SH NAME .SH NAME
nghttp \- HTTP/2 client nghttp \- HTTP/2 client
.SH SYNOPSIS .SH SYNOPSIS
@@ -141,15 +141,14 @@ HTTP upgrade request is performed with OPTIONS method.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-extpri=<PRI> .B \-p, \-\-weight=<WEIGHT>
Sets RFC 9218 priority of given URI. <PRI> must be the Sets weight of given URI. This option can be used
wire format of priority header field (e.g., \(dqu=3,i\(dq). multiple times, and N\-th \fI\%\-p\fP option sets weight of N\-th
This option can be used multiple times, and N\-th URI in the command line. If the number of \fI\%\-p\fP option is
\fI\%\-\-extpri\fP option sets priority of N\-th URI in the command less than the number of URI, the last \fI\%\-p\fP option value is
line. If the number of this option is less than the repeated. If there is no \fI\%\-p\fP option, default weight, 16,
number of URI, the last option value is repeated. If is assumed. The valid value range is
there is no \fI\%\-\-extpri\fP option, urgency is 3, and [1, 256], inclusive.
incremental is false.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -206,6 +205,11 @@ Don\(aqt send content\-length header field.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-no\-dep
Don\(aqt send dependency based priority hint to server.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-hexdump .B \-\-hexdump
Display the incoming traffic in hexadecimal (Canonical Display the incoming traffic in hexadecimal (Canonical
hex+ASCII display). If SSL/TLS is used, decrypted data hex+ASCII display). If SSL/TLS is used, decrypted data
@@ -243,6 +247,11 @@ Enable ktls.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-no\-rfc7540\-pri
Disable RFC7540 priorities.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-version .B \-\-version
Display version information and exit. Display version information and exit.
.UNINDENT .UNINDENT
@@ -259,6 +268,63 @@ The <DURATION> argument is an integer and an optional unit (e.g., 1s
is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit (hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit. is omitted, a second is used as unit.
.SH DEPENDENCY BASED PRIORITY
.sp
nghttp sends priority hints to server by default unless
\fI\%\-\-no\-dep\fP is used. nghttp mimics the way Firefox employs to
manages dependency using idle streams. We follows the behaviour of
Firefox Nightly as of April, 2015, and nghttp\(aqs behaviour is very
static and could be different from Firefox in detail. But reproducing
the same behaviour of Firefox is not our goal. The goal is provide
the easy way to test out the dependency priority in server
implementation.
.sp
When connection is established, nghttp sends 5 PRIORITY frames to idle
streams 3, 5, 7, 9 and 11 to create \(dqanchor\(dq nodes in dependency
tree:
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
+\-\-\-\-\-+
|id=0 |
+\-\-\-\-\-+
^ ^ ^
w=201 / | \e w=1
/ | \e
/ w=101| \e
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
|id=3 | |id=5 | |id=7 |
+\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
^ ^
w=1 | w=1 |
| |
+\-\-\-\-\-+ +\-\-\-\-\-+
|id=11| |id=9 |
+\-\-\-\-\-+ +\-\-\-\-\-+
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
In the above figure, \fBid\fP means stream ID, and \fBw\fP means weight.
The stream 0 is non\-existence stream, and forms the root of the tree.
The stream 7 and 9 are not used for now.
.sp
The URIs given in the command\-line depend on stream 11 with the weight
given in \fI\%\-p\fP option, which defaults to 16.
.sp
If \fI\%\-a\fP option is used, nghttp parses the resource pointed by
URI given in command\-line as html, and extracts resource links from
it. When requesting those resources, nghttp uses dependency according
to its resource type.
.sp
For CSS, and Javascript files inside \(dqhead\(dq element, they depend on
stream 3 with the weight 2. The Javascript files outside \(dqhead\(dq
element depend on stream 5 with the weight 2. The mages depend on
stream 11 with the weight 12. The other resources (e.g., icon) depend
on stream 11 with the weight 2.
.SH SEE ALSO .SH SEE ALSO
.sp .sp
\fBnghttpd(1)\fP, \fBnghttpx(1)\fP, \fBh2load(1)\fP \fBnghttpd(1)\fP, \fBnghttpx(1)\fP, \fBh2load(1)\fP

View File

@@ -105,16 +105,15 @@ OPTIONS
if the request URI has https scheme. If :option:`-d` is used, the if the request URI has https scheme. If :option:`-d` is used, the
HTTP upgrade request is performed with OPTIONS method. HTTP upgrade request is performed with OPTIONS method.
.. option:: --extpri=<PRI> .. option:: -p, --weight=<WEIGHT>
Sets RFC 9218 priority of given URI. <PRI> must be the Sets weight of given URI. This option can be used
wire format of priority header field (e.g., "u=3,i"). multiple times, and N-th :option:`-p` option sets weight of N-th
This option can be used multiple times, and N-th URI in the command line. If the number of :option:`-p` option is
:option:`--extpri` option sets priority of N-th URI in the command less than the number of URI, the last :option:`-p` option value is
line. If the number of this option is less than the repeated. If there is no :option:`-p` option, default weight, 16,
number of URI, the last option value is repeated. If is assumed. The valid value range is
there is no :option:`--extpri` option, urgency is 3, and [1, 256], inclusive.
incremental is false.
.. option:: -M, --peer-max-concurrent-streams=<N> .. option:: -M, --peer-max-concurrent-streams=<N>
@@ -161,6 +160,10 @@ OPTIONS
Don't send content-length header field. Don't send content-length header field.
.. option:: --no-dep
Don't send dependency based priority hint to server.
.. option:: --hexdump .. option:: --hexdump
Display the incoming traffic in hexadecimal (Canonical Display the incoming traffic in hexadecimal (Canonical
@@ -192,6 +195,10 @@ OPTIONS
Enable ktls. Enable ktls.
.. option:: --no-rfc7540-pri
Disable RFC7540 priorities.
.. option:: --version .. option:: --version
Display version information and exit. Display version information and exit.
@@ -210,6 +217,59 @@ is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit (hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit. is omitted, a second is used as unit.
DEPENDENCY BASED PRIORITY
-------------------------
nghttp sends priority hints to server by default unless
:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
manages dependency using idle streams. We follows the behaviour of
Firefox Nightly as of April, 2015, and nghttp's behaviour is very
static and could be different from Firefox in detail. But reproducing
the same behaviour of Firefox is not our goal. The goal is provide
the easy way to test out the dependency priority in server
implementation.
When connection is established, nghttp sends 5 PRIORITY frames to idle
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
tree:
.. code-block:: text
+-----+
|id=0 |
+-----+
^ ^ ^
w=201 / | \ w=1
/ | \
/ w=101| \
+-----+ +-----+ +-----+
|id=3 | |id=5 | |id=7 |
+-----+ +-----+ +-----+
^ ^
w=1 | w=1 |
| |
+-----+ +-----+
|id=11| |id=9 |
+-----+ +-----+
In the above figure, ``id`` means stream ID, and ``w`` means weight.
The stream 0 is non-existence stream, and forms the root of the tree.
The stream 7 and 9 are not used for now.
The URIs given in the command-line depend on stream 11 with the weight
given in :option:`-p` option, which defaults to 16.
If :option:`-a` option is used, nghttp parses the resource pointed by
URI given in command-line as html, and extracts resource links from
it. When requesting those resources, nghttp uses dependency according
to its resource type.
For CSS, and Javascript files inside "head" element, they depend on
stream 3 with the weight 2. The Javascript files outside "head"
element depend on stream 5 with the weight 2. The mages depend on
stream 11 with the weight 12. The other resources (e.g., icon) depend
on stream 11 with the weight 2.
SEE ALSO SEE ALSO
-------- --------

View File

@@ -1,3 +1,56 @@
DEPENDENCY BASED PRIORITY
-------------------------
nghttp sends priority hints to server by default unless
:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
manages dependency using idle streams. We follows the behaviour of
Firefox Nightly as of April, 2015, and nghttp's behaviour is very
static and could be different from Firefox in detail. But reproducing
the same behaviour of Firefox is not our goal. The goal is provide
the easy way to test out the dependency priority in server
implementation.
When connection is established, nghttp sends 5 PRIORITY frames to idle
streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
tree:
.. code-block:: text
+-----+
|id=0 |
+-----+
^ ^ ^
w=201 / | \ w=1
/ | \
/ w=101| \
+-----+ +-----+ +-----+
|id=3 | |id=5 | |id=7 |
+-----+ +-----+ +-----+
^ ^
w=1 | w=1 |
| |
+-----+ +-----+
|id=11| |id=9 |
+-----+ +-----+
In the above figure, ``id`` means stream ID, and ``w`` means weight.
The stream 0 is non-existence stream, and forms the root of the tree.
The stream 7 and 9 are not used for now.
The URIs given in the command-line depend on stream 11 with the weight
given in :option:`-p` option, which defaults to 16.
If :option:`-a` option is used, nghttp parses the resource pointed by
URI given in command-line as html, and extracts resource links from
it. When requesting those resources, nghttp uses dependency according
to its resource type.
For CSS, and Javascript files inside "head" element, they depend on
stream 3 with the weight 2. The Javascript files outside "head"
element depend on stream 5 with the weight 2. The mages depend on
stream 11 with the weight 12. The other resources (e.g., icon) depend
on stream 11 with the weight 2.
SEE ALSO SEE ALSO
-------- --------

View File

@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
.. ..
.TH "NGHTTPD" "1" "Sep 02, 2025" "1.67.0" "nghttp2" .TH "NGHTTPD" "1" "May 19, 2024" "1.62.1" "nghttp2"
.SH NAME .SH NAME
nghttpd \- HTTP/2 server nghttpd \- HTTP/2 server
.SH SYNOPSIS .SH SYNOPSIS
@@ -209,6 +209,11 @@ Enable ktls.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-no\-rfc7540\-pri
Disable RFC7540 priorities.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-version .B \-\-version
Display version information and exit. Display version information and exit.
.UNINDENT .UNINDENT

View File

@@ -163,6 +163,10 @@ OPTIONS
Enable ktls. Enable ktls.
.. option:: --no-rfc7540-pri
Disable RFC7540 priorities.
.. option:: --version .. option:: --version
Display version information and exit. Display version information and exit.

View File

@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
.. ..
.TH "NGHTTPX" "1" "Sep 02, 2025" "1.67.0" "nghttp2" .TH "NGHTTPX" "1" "May 19, 2024" "1.62.1" "nghttp2"
.SH NAME .SH NAME
nghttpx \- HTTP/2 proxy nghttpx \- HTTP/2 proxy
.SH SYNOPSIS .SH SYNOPSIS
@@ -46,7 +46,8 @@ Set path to server\(aqs private key. Required unless
.TP .TP
.B <CERT> .B <CERT>
Set path to server\(aqs certificate. Required unless Set path to server\(aqs certificate. Required unless
\(dqno\-tls\(dq parameter is used in \fI\%\-\-frontend\fP option. \(dqno\-tls\(dq parameter is used in \fI\%\-\-frontend\fP option. To
make OCSP stapling work, this must be an absolute path.
.UNINDENT .UNINDENT
.SH OPTIONS .SH OPTIONS
.sp .sp
@@ -744,10 +745,12 @@ enabled for backend connections.
.B \-\-cacert=<PATH> .B \-\-cacert=<PATH>
Set path to trusted CA certificate file. It is used in Set path to trusted CA certificate file. It is used in
backend TLS connections to verify peer\(aqs certificate. backend TLS connections to verify peer\(aqs certificate.
The file must be in PEM format. It can contain multiple It is also used to verify OCSP response from the script
certificates. If the linked OpenSSL is configured to set by \fI\%\-\-fetch\-ocsp\-response\-file\fP\&. The file must be in
load system wide certificates, they are loaded at PEM format. It can contain multiple certificates. If
startup regardless of this option. 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
@@ -767,7 +770,8 @@ curves (e.g., P\-256) between client and server are also
taken into consideration. This allows nghttpx to send taken into consideration. This allows nghttpx to send
ECDSA certificate to modern clients, while sending RSA ECDSA certificate to modern clients, while sending RSA
based certificate to older clients. This option can be based certificate to older clients. This option can be
used multiple times. used multiple times. To make OCSP stapling work,
<CERTPATH> must be absolute path.
.sp .sp
Additional parameter can be specified in <PARAM>. The Additional parameter can be specified in <PARAM>. The
available <PARAM> is \(dqsct\-dir=<DIR>\(dq. available <PARAM> is \(dqsct\-dir=<DIR>\(dq.
@@ -794,7 +798,7 @@ protocol comes first. The parameter must be delimited
by a single comma only and any white spaces are treated by a single comma only and any white spaces are treated
as a part of protocol string. as a part of protocol string.
.sp .sp
Default: \fBh2,http/1.1\fP Default: \fBh2,h2\-16,h2\-14,http/1.1\fP
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -958,6 +962,72 @@ get TLS ticket keys.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-fetch\-ocsp\-response\-file=<PATH>
Path to fetch\-ocsp\-response script file. It should be
absolute path.
.sp
Default: \fB/usr/local/share/nghttp2/fetch\-ocsp\-response\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-ocsp\-update\-interval=<DURATION>
Set interval to update OCSP response cache.
.sp
Default: \fB4h\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-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
Disable OCSP stapling.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-session\-cache\-memcached=<HOST>,<PORT>[;tls]
Specify address of memcached server to store session
cache. This enables shared session cache between
multiple nghttpx instances. Optionally, memcached
connection can be encrypted with TLS by specifying \(dqtls\(dq
parameter.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-session\-cache\-memcached\-address\-family=(auto|IPv4|IPv6)
Specify address family of memcached connections to store
session cache. If \(dqauto\(dq is given, both IPv4 and IPv6
are considered. If \(dqIPv4\(dq is given, only IPv4 address
is considered. If \(dqIPv6\(dq is given, only IPv6 address is
considered.
.sp
Default: \fBauto\fP
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-session\-cache\-memcached\-cert\-file=<PATH>
Path to client certificate for memcached connections to
store session cache.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-session\-cache\-memcached\-private\-key\-file=<PATH>
Path to client private key for memcached connections to
store session cache.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-tls\-dyn\-rec\-warmup\-threshold=<SIZE> .B \-\-tls\-dyn\-rec\-warmup\-threshold=<SIZE>
Specify the threshold size for TLS dynamic record size Specify the threshold size for TLS dynamic record size
behaviour. During a TLS session, after the threshold behaviour. During a TLS session, after the threshold
@@ -1065,7 +1135,8 @@ Default: \fB16K\fP
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-tls\-ktls .B \-\-tls\-ktls
Enable ktls. Enable ktls. For server, ktls is enable if
\fI\%\-\-tls\-session\-cache\-memcached\fP is not configured.
.UNINDENT .UNINDENT
.SS HTTP/2 .SS HTTP/2
.INDENT 0.0 .INDENT 0.0
@@ -1604,7 +1675,7 @@ initial DNS query. For the 2nd and later queries,
server is given time based on this timeout, and it is server is given time based on this timeout, and it is
scaled linearly. scaled linearly.
.sp .sp
Default: \fB250ms\fP Default: \fB5s\fP
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -1612,7 +1683,7 @@ Default: \fB250ms\fP
Set the number of DNS query before nghttpx gives up name Set the number of DNS query before nghttpx gives up name
lookup. lookup.
.sp .sp
Default: \fB3\fP Default: \fB2\fP
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
@@ -1932,9 +2003,11 @@ request header field, do this:
.INDENT 7.0 .INDENT 7.0
.INDENT 3.5 .INDENT 3.5
.sp .sp
.EX .nf
.ft C
add\-request\-header=foo: bar add\-request\-header=foo: bar
.EE .ft P
.fi
.UNINDENT .UNINDENT
.UNINDENT .UNINDENT
.sp .sp
@@ -1942,9 +2015,11 @@ instead of:
.INDENT 7.0 .INDENT 7.0
.INDENT 3.5 .INDENT 3.5
.sp .sp
.EX .nf
.ft C
add\-request\-header=\(dqfoo: bar\(dq add\-request\-header=\(dqfoo: bar\(dq
.EE .ft P
.fi
.UNINDENT .UNINDENT
.UNINDENT .UNINDENT
.sp .sp
@@ -2049,10 +2124,12 @@ header field to initiate server push:
.INDENT 0.0 .INDENT 0.0
.INDENT 3.5 .INDENT 3.5
.sp .sp
.EX .nf
.ft C
Link: </fonts/font.woff>; rel=preload Link: </fonts/font.woff>; rel=preload
Link: </css/theme.css>; rel=preload Link: </css/theme.css>; rel=preload
.EE .ft P
.fi
.UNINDENT .UNINDENT
.UNINDENT .UNINDENT
.sp .sp
@@ -2083,6 +2160,35 @@ specified socket already exists in the file system, nghttpx first
deletes it. However, if SIGUSR2 is used to execute new binary and deletes it. However, if SIGUSR2 is used to execute new binary and
both old and new configurations use same filename, new binary does not both old and new configurations use same filename, new binary does not
delete the socket and continues to use it. delete the socket and continues to use it.
.SH OCSP STAPLING
.sp
OCSP query is done using external Python script
\fBfetch\-ocsp\-response\fP, which has been originally developed in Perl
as part of h2o project (\X'tty: link https://github.com/h2o/h2o'\fI\%https://github.com/h2o/h2o\fP\X'tty: link'), and was
translated into Python.
.sp
The script file is usually installed under
\fB$(prefix)/share/nghttp2/\fP directory. The actual path to script can
be customized using \fI\%\-\-fetch\-ocsp\-response\-file\fP option.
.sp
If OCSP query is failed, previous OCSP response, if any, is continued
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
@@ -2090,6 +2196,16 @@ session ticket.
.SS SESSION ID RESUMPTION .SS SESSION ID RESUMPTION
.sp .sp
By default, session ID is shared by all worker threads. By default, session ID is shared by all worker threads.
.sp
If \fI\%\-\-tls\-session\-cache\-memcached\fP is given, nghttpx will
insert serialized session data to memcached with
\fBnghttpx:tls\-session\-cache:\fP + lowercase hex string of session ID
as a memcached entry key, with expiry time 12 hours. Session timeout
is set to 12 hours.
.sp
By default, connections to memcached server are not encrypted. To
enable encryption, use \fBtls\fP keyword in
\fI\%\-\-tls\-session\-cache\-memcached\fP option.
.SS TLS SESSION TICKET RESUMPTION .SS TLS SESSION TICKET RESUMPTION
.sp .sp
By default, session ticket is shared by all worker threads. The By default, session ticket is shared by all worker threads. The
@@ -2108,7 +2224,8 @@ memcached is the binary format described below:
.INDENT 0.0 .INDENT 0.0
.INDENT 3.5 .INDENT 3.5
.sp .sp
.EX .nf
.ft C
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+ +\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
| VERSION (4) |LEN (2)|KEY(48 or 80) ... | VERSION (4) |LEN (2)|KEY(48 or 80) ...
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+ +\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
@@ -2116,7 +2233,8 @@ memcached is the binary format described below:
| | | |
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+ +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
(LEN, KEY) pair can be repeated (LEN, KEY) pair can be repeated
.EE .ft P
.fi
.UNINDENT .UNINDENT
.UNINDENT .UNINDENT
.sp .sp
@@ -2533,7 +2651,8 @@ Modify request path:
.INDENT 0.0 .INDENT 0.0
.INDENT 3.5 .INDENT 3.5
.sp .sp
.EX .nf
.ft C
class App class App
def on_req(env) def on_req(env)
env.req.path = \(dq/apps#{env.req.path}\(dq env.req.path = \(dq/apps#{env.req.path}\(dq
@@ -2541,7 +2660,8 @@ class App
end end
App.new App.new
.EE .ft P
.fi
.UNINDENT .UNINDENT
.UNINDENT .UNINDENT
.sp .sp
@@ -2552,7 +2672,8 @@ addresses:
.INDENT 0.0 .INDENT 0.0
.INDENT 3.5 .INDENT 3.5
.sp .sp
.EX .nf
.ft C
class App class App
def on_req(env) def on_req(env)
allowed_clients = [\(dq127.0.0.1\(dq, \(dq::1\(dq] allowed_clients = [\(dq127.0.0.1\(dq, \(dq::1\(dq]
@@ -2566,7 +2687,8 @@ class App
end end
App.new App.new
.EE .ft P
.fi
.UNINDENT .UNINDENT
.UNINDENT .UNINDENT
.SH API ENDPOINTS .SH API ENDPOINTS

View File

@@ -25,7 +25,8 @@ A reverse proxy for HTTP/3, HTTP/2, and HTTP/1.
.. describe:: <CERT> .. describe:: <CERT>
Set path to server's certificate. Required unless Set path to server's certificate. Required unless
"no-tls" parameter is used in :option:`--frontend` option. "no-tls" parameter is used in :option:`--frontend` option. To
make OCSP stapling work, this must be an absolute path.
OPTIONS OPTIONS
@@ -694,10 +695,12 @@ SSL/TLS
Set path to trusted CA certificate file. It is used in Set path to trusted CA certificate file. It is used in
backend TLS connections to verify peer's certificate. backend TLS connections to verify peer's certificate.
The file must be in PEM format. It can contain multiple It is also used to verify OCSP response from the script
certificates. If the linked OpenSSL is configured to set by :option:`--fetch-ocsp-response-file`\. The file must be in
load system wide certificates, they are loaded at PEM format. It can contain multiple certificates. If
startup regardless of this option. 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>
@@ -715,7 +718,8 @@ SSL/TLS
taken into consideration. This allows nghttpx to send taken into consideration. This allows nghttpx to send
ECDSA certificate to modern clients, while sending RSA ECDSA certificate to modern clients, while sending RSA
based certificate to older clients. This option can be based certificate to older clients. This option can be
used multiple times. used multiple times. To make OCSP stapling work,
<CERTPATH> must be absolute path.
Additional parameter can be specified in <PARAM>. The Additional parameter can be specified in <PARAM>. The
available <PARAM> is "sct-dir=<DIR>". available <PARAM> is "sct-dir=<DIR>".
@@ -740,7 +744,7 @@ SSL/TLS
by a single comma only and any white spaces are treated by a single comma only and any white spaces are treated
as a part of protocol string. as a part of protocol string.
Default: ``h2,http/1.1`` Default: ``h2,h2-16,h2-14,http/1.1``
.. option:: --verify-client .. option:: --verify-client
@@ -886,6 +890,63 @@ SSL/TLS
Path to client private key for memcached connections to Path to client private key for memcached connections to
get TLS ticket keys. get TLS ticket keys.
.. option:: --fetch-ocsp-response-file=<PATH>
Path to fetch-ocsp-response script file. It should be
absolute path.
Default: ``/usr/local/share/nghttp2/fetch-ocsp-response``
.. option:: --ocsp-update-interval=<DURATION>
Set interval to update OCSP response cache.
Default: ``4h``
.. option:: --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
Disable OCSP stapling.
.. option:: --tls-session-cache-memcached=<HOST>,<PORT>[;tls]
Specify address of memcached server to store session
cache. This enables shared session cache between
multiple nghttpx instances. Optionally, memcached
connection can be encrypted with TLS by specifying "tls"
parameter.
.. option:: --tls-session-cache-memcached-address-family=(auto|IPv4|IPv6)
Specify address family of memcached connections to store
session cache. If "auto" is given, both IPv4 and IPv6
are considered. If "IPv4" is given, only IPv4 address
is considered. If "IPv6" is given, only IPv6 address is
considered.
Default: ``auto``
.. option:: --tls-session-cache-memcached-cert-file=<PATH>
Path to client certificate for memcached connections to
store session cache.
.. option:: --tls-session-cache-memcached-private-key-file=<PATH>
Path to client private key for memcached connections to
store session cache.
.. option:: --tls-dyn-rec-warmup-threshold=<SIZE> .. option:: --tls-dyn-rec-warmup-threshold=<SIZE>
Specify the threshold size for TLS dynamic record size Specify the threshold size for TLS dynamic record size
@@ -985,7 +1046,8 @@ SSL/TLS
.. option:: --tls-ktls .. option:: --tls-ktls
Enable ktls. Enable ktls. For server, ktls is enable if
:option:`--tls-session-cache-memcached` is not configured.
HTTP/2 HTTP/2
@@ -1462,14 +1524,14 @@ DNS
server is given time based on this timeout, and it is server is given time based on this timeout, and it is
scaled linearly. scaled linearly.
Default: ``250ms`` Default: ``5s``
.. option:: --dns-max-try=<N> .. option:: --dns-max-try=<N>
Set the number of DNS query before nghttpx gives up name Set the number of DNS query before nghttpx gives up name
lookup. lookup.
Default: ``3`` Default: ``2``
.. option:: --frontend-max-requests=<N> .. option:: --frontend-max-requests=<N>
@@ -1909,6 +1971,37 @@ deletes it. However, if SIGUSR2 is used to execute new binary and
both old and new configurations use same filename, new binary does not both old and new configurations use same filename, new binary does not
delete the socket and continues to use it. delete the socket and continues to use it.
OCSP STAPLING
-------------
OCSP query is done using external Python script
``fetch-ocsp-response``, which has been originally developed in Perl
as part of h2o project (https://github.com/h2o/h2o), and was
translated into Python.
The script file is usually installed under
``$(prefix)/share/nghttp2/`` directory. The actual path to script can
be customized using :option:`--fetch-ocsp-response-file` option.
If OCSP query is failed, previous OCSP response, if any, is continued
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
---------------------- ----------------------
@@ -1920,6 +2013,16 @@ SESSION ID RESUMPTION
By default, session ID is shared by all worker threads. By default, session ID is shared by all worker threads.
If :option:`--tls-session-cache-memcached` is given, nghttpx will
insert serialized session data to memcached with
``nghttpx:tls-session-cache:`` + lowercase hex string of session ID
as a memcached entry key, with expiry time 12 hours. Session timeout
is set to 12 hours.
By default, connections to memcached server are not encrypted. To
enable encryption, use ``tls`` keyword in
:option:`--tls-session-cache-memcached` option.
TLS SESSION TICKET RESUMPTION TLS SESSION TICKET RESUMPTION
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -156,6 +156,37 @@ deletes it. However, if SIGUSR2 is used to execute new binary and
both old and new configurations use same filename, new binary does not both old and new configurations use same filename, new binary does not
delete the socket and continues to use it. delete the socket and continues to use it.
OCSP STAPLING
-------------
OCSP query is done using external Python script
``fetch-ocsp-response``, which has been originally developed in Perl
as part of h2o project (https://github.com/h2o/h2o), and was
translated into Python.
The script file is usually installed under
``$(prefix)/share/nghttp2/`` directory. The actual path to script can
be customized using :option:`--fetch-ocsp-response-file` option.
If OCSP query is failed, previous OCSP response, if any, is continued
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
---------------------- ----------------------
@@ -167,6 +198,16 @@ SESSION ID RESUMPTION
By default, session ID is shared by all worker threads. By default, session ID is shared by all worker threads.
If :option:`--tls-session-cache-memcached` is given, nghttpx will
insert serialized session data to memcached with
``nghttpx:tls-session-cache:`` + lowercase hex string of session ID
as a memcached entry key, with expiry time 12 hours. Session timeout
is set to 12 hours.
By default, connections to memcached server are not encrypted. To
enable encryption, use ``tls`` keyword in
:option:`--tls-session-cache-memcached` option.
TLS SESSION TICKET RESUMPTION TLS SESSION TICKET RESUMPTION
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -482,22 +482,20 @@ be called as usual.
Stream priorities Stream priorities
----------------- -----------------
The stream prioritization scheme described in :rfc:`7540`, which has By default, the stream prioritization scheme described in :rfc:`7540`
been formally deprecated by :rfc:`9113`, has been removed. An is used. This scheme has been formally deprecated by :rfc:`9113`. In
application is advised to send order to disable it, send
:enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` of :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` of
value of 1 via `nghttp2_submit_settings()`, and migrate to value of 1 via `nghttp2_submit_settings()`. This settings ID is
:rfc:`9218`. defined by :rfc:`9218`. The sender of this settings value disables
RFC 7540 priorities, and instead it enables RFC 9218 Extensible
The sender of this settings value disables :rfc:`7540` priorities, and Prioritization Scheme. This new prioritization scheme has 2 methods
instead it enables :rfc:`9218` Extensible Prioritization Scheme. This to convey the stream priorities to a remote endpoint: Priority header
new prioritization scheme has 2 methods to convey the stream field and PRIORITY_UPDATE frame. nghttp2 supports both methods. In
priorities to a remote endpoint: Priority header field and order to receive and process PRIORITY_UPDATE frame, server has to call
PRIORITY_UPDATE frame. nghttp2 supports both methods. In order to ``nghttp2_option_set_builtin_recv_extension_type(option,
receive and process PRIORITY_UPDATE frame, server has to call NGHTTP2_PRIORITY_UPDATE)`` (see the above section), and pass the
`nghttp2_option_set_builtin_recv_extension_type()` with option to `nghttp2_session_server_new2()` or
NGHTTP2_PRIORITY_UPDATE as type argument (see the above section), and
pass the option to `nghttp2_session_server_new2()` or
`nghttp2_session_server_new3()` to create a server session. Client `nghttp2_session_server_new3()` to create a server session. Client
can send Priority header field via `nghttp2_submit_request2()`. It can send Priority header field via `nghttp2_submit_request2()`. It
can also send PRIORITY_UPDATE frame via can also send PRIORITY_UPDATE frame via
@@ -505,3 +503,24 @@ can also send PRIORITY_UPDATE frame via
field in a request header field and updates the stream priority unless field in a request header field and updates the stream priority unless
HTTP messaging rule enforcement is disabled (see HTTP messaging rule enforcement is disabled (see
`nghttp2_option_set_no_http_messaging()`). `nghttp2_option_set_no_http_messaging()`).
For the purpose of smooth migration from RFC 7540 priorities, client
is advised to send
:enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` of
value of 1. Until it receives the first server SETTINGS frame, it can
send both RFC 7540 and RFC 9128 priority signals. If client receives
SETTINGS_NO_RFC7540_PRIORITIES of value of 0, or it is omitted ,
client stops sending PRIORITY_UPDATE frame. Priority header field
will be sent in anyway since it is an end-to-end signal. If
SETTINGS_NO_RFC7540_PRIORITIES of value of 1 is received, client stops
sending RFC 7540 priority signals. This is the advice described in
:rfc:`9218#section-2.1.1`.
Server has an optional mechanism to fallback to RFC 7540 priorities.
By default, if server sends SETTINGS_NO_RFC7540_PRIORITIES of value of
1, it completely disables RFC 7540 priorities and no fallback. By
setting nonzero value to
`nghttp2_option_set_server_fallback_rfc7540_priorities()`, server
falls back to RFC 7540 priorities if it sends
SETTINGS_NO_RFC7540_PRIORITIES value of value of 1, and client omits
SETTINGS_NO_RFC7540_PRIORITIES in its SETTINGS frame.

View File

@@ -26,7 +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-19. between versions, we currently use clang-format-15.
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.
@@ -34,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-18 in debian), either add it to PATH variable or add clang-format-diff-14 in debian), either add it to PATH variable or add
git option ``clangformatdiff.binary`` to point to the script. 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.

View File

@@ -167,7 +167,8 @@ Enable SSL/TLS on memcached connection
By default, memcached connection is not encrypted. To enable By default, memcached connection is not encrypted. To enable
encryption, use ``tls`` keyword in encryption, use ``tls`` keyword in
:option:`--tls-ticket-key-memcached`. :option:`--tls-ticket-key-memcached` for TLS ticket key, and
:option:`--tls-session-cache-memcached` for TLS session cache.
Specifying additional server certificates Specifying additional server certificates
----------------------------------------- -----------------------------------------

View File

@@ -63,7 +63,7 @@ structure is defined as follows::
/* The NULL-terminated URI string to retrieve. */ /* The NULL-terminated URI string to retrieve. */
const char *uri; const char *uri;
/* Parsed result of the |uri| */ /* Parsed result of the |uri| */
urlparse_url *u; struct http_parser_url *u;
/* The authority portion of the |uri|, not NULL-terminated */ /* The authority portion of the |uri|, not NULL-terminated */
char *authority; char *authority;
/* The path portion of the |uri|, including query, not /* The path portion of the |uri|, including query, not
@@ -237,11 +237,11 @@ HTTP request in the ``submit_request()`` function::
int32_t stream_id; int32_t stream_id;
http2_stream_data *stream_data = session_data->stream_data; http2_stream_data *stream_data = session_data->stream_data;
const char *uri = stream_data->uri; const char *uri = stream_data->uri;
const urlparse_url *u = stream_data->u; const struct http_parser_url *u = stream_data->u;
nghttp2_nv hdrs[] = { nghttp2_nv hdrs[] = {
MAKE_NV2(":method", "GET"), MAKE_NV2(":method", "GET"),
MAKE_NV(":scheme", &uri[u->field_data[URLPARSE_SCHEMA].off], MAKE_NV(":scheme", &uri[u->field_data[UF_SCHEMA].off],
u->field_data[URLPARSE_SCHEMA].len), u->field_data[UF_SCHEMA].len),
MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen), MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
MAKE_NV(":path", stream_data->path, stream_data->pathlen)}; MAKE_NV(":path", stream_data->path, stream_data->pathlen)};
fprintf(stderr, "Request headers:\n"); fprintf(stderr, "Request headers:\n");

View File

@@ -4,36 +4,32 @@ ARG NGHTTP2_BRANCH=master
RUN apt-get update && \ RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
git clang-19 make binutils autoconf automake autotools-dev libtool \ git clang make binutils autoconf automake autotools-dev libtool \
pkg-config cmake cmake-data \ pkg-config cmake cmake-data \
zlib1g-dev libev-dev libjemalloc-dev ruby-dev libc-ares-dev bison \ zlib1g-dev libev-dev libjemalloc-dev ruby-dev libc-ares-dev bison \
libelf-dev libbrotli-dev libelf-dev libbrotli-dev
RUN git clone --recursive --shallow-submodules --depth 1 -b v1.58.1 https://github.com/aws/aws-lc && \ RUN git clone --recursive --depth 1 -b v1.26.0 https://github.com/aws/aws-lc && \
cd aws-lc && \ cd aws-lc && \
export CC=clang-19 CXX=clang++-19 && \
cmake -B build -DDISABLE_GO=ON && \ cmake -B build -DDISABLE_GO=ON && \
make -j$(nproc) -C build && \ make -j$(nproc) -C build && \
cmake --install build && \ cmake --install build && \
cd .. && \ cd .. && \
rm -rf aws-lc rm -rf aws-lc
RUN git clone --recursive --shallow-submodules --depth 1 -b v1.11.0 https://github.com/ngtcp2/nghttp3 && \ RUN git clone --recursive --depth 1 -b v1.3.0 https://github.com/ngtcp2/nghttp3 && \
cd nghttp3 && \ cd nghttp3 && \
autoreconf -i && \ autoreconf -i && \
./configure --disable-dependency-tracking --enable-lib-only \ ./configure --enable-lib-only && \
CC=clang-19 CXX=clang++-19 && \
make -j$(nproc) && \ make -j$(nproc) && \
make install-strip && \ make install-strip && \
cd .. && \ cd .. && \
rm -rf nghttp3 rm -rf nghttp3
RUN git clone --recursive --shallow-submodules --depth 1 -b v1.15.1 https://github.com/ngtcp2/ngtcp2 && \ RUN git clone --recursive --depth 1 -b v1.5.0 https://github.com/ngtcp2/ngtcp2 && \
cd ngtcp2 && \ cd ngtcp2 && \
autoreconf -i && \ autoreconf -i && \
./configure --disable-dependency-tracking --enable-lib-only \ ./configure --enable-lib-only --with-boringssl \
--with-boringssl \
CC=clang-19 CXX=clang++-19 \
LIBTOOL_LDFLAGS="-static-libtool-libs" \ LIBTOOL_LDFLAGS="-static-libtool-libs" \
BORINGSSL_LIBS="-l:libssl.a -l:libcrypto.a" \ BORINGSSL_LIBS="-l:libssl.a -l:libcrypto.a" \
PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \ PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \
@@ -42,21 +38,20 @@ RUN git clone --recursive --shallow-submodules --depth 1 -b v1.15.1 https://gith
cd .. && \ cd .. && \
rm -rf ngtcp2 rm -rf ngtcp2
RUN git clone --depth 1 -b v1.6.2 https://github.com/libbpf/libbpf && \ RUN git clone --depth 1 -b v1.3.0 https://github.com/libbpf/libbpf && \
cd libbpf && \ cd libbpf && \
CC=clang-19 PREFIX=/usr/local make -C src install && \ PREFIX=/usr/local make -C src install && \
cd .. && \ cd .. && \
rm -rf libbpf rm -rf libbpf
RUN git clone --recursive --shallow-submodules --depth 1 -b $NGHTTP2_BRANCH https://github.com/nghttp2/nghttp2 && \ RUN git clone --recursive --depth 1 -b $NGHTTP2_BRANCH https://github.com/nghttp2/nghttp2 && \
cd nghttp2 && \ cd nghttp2 && \
autoreconf -i && \ autoreconf -i && \
./configure --disable-dependency-tracking --disable-examples \ ./configure --disable-examples --disable-hpack-tools \
--disable-hpack-tools \
--with-mruby \ --with-mruby \
--enable-http3 --with-libbpf \ --enable-http3 --with-libbpf \
--with-libbrotlienc --with-libbrotlidec \ --with-libbrotlienc --with-libbrotlidec \
CC=clang-19 CXX=clang++-19 \ CC=clang CXX=clang++ \
LIBTOOL_LDFLAGS="-static-libtool-libs" \ LIBTOOL_LDFLAGS="-static-libtool-libs" \
OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a" \ OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a" \
LIBEV_LIBS="-l:libev.a" \ LIBEV_LIBS="-l:libev.a" \
@@ -74,6 +69,9 @@ RUN git clone --recursive --shallow-submodules --depth 1 -b $NGHTTP2_BRANCH http
FROM gcr.io/distroless/base-nossl-debian12 FROM gcr.io/distroless/base-nossl-debian12
COPY --from=build --link \
/usr/local/share/nghttp2/ \
/usr/local/share/nghttp2/
COPY --from=build --link \ COPY --from=build --link \
/usr/local/bin/h2load \ /usr/local/bin/h2load \
/usr/local/bin/nghttpx \ /usr/local/bin/nghttpx \

View File

@@ -8,7 +8,7 @@ if(ENABLE_EXAMPLES)
include_directories( include_directories(
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party/urlparse" "${CMAKE_CURRENT_SOURCE_DIR}/../third-party"
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party/llhttp/include" "${CMAKE_CURRENT_SOURCE_DIR}/../third-party/llhttp/include"
${LIBEVENT_INCLUDE_DIRS} ${LIBEVENT_INCLUDE_DIRS}
@@ -23,15 +23,15 @@ if(ENABLE_EXAMPLES)
) )
add_executable(client client.c $<TARGET_OBJECTS:llhttp> add_executable(client client.c $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:urlparse> $<TARGET_OBJECTS:url-parser>
) )
add_executable(libevent-client libevent-client.c $<TARGET_OBJECTS:llhttp> add_executable(libevent-client libevent-client.c $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:urlparse> $<TARGET_OBJECTS:url-parser>
) )
add_executable(libevent-server libevent-server.c $<TARGET_OBJECTS:llhttp> add_executable(libevent-server libevent-server.c $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:urlparse> $<TARGET_OBJECTS:url-parser>
) )
add_executable(deflate deflate.c $<TARGET_OBJECTS:llhttp> add_executable(deflate deflate.c $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:urlparse> $<TARGET_OBJECTS:url-parser>
) )
endif() endif()

View File

@@ -30,13 +30,13 @@ AM_CXXFLAGS = $(WARNCXXFLAGS) $(CXX1XCXXFLAGS)
AM_CPPFLAGS = \ AM_CPPFLAGS = \
-I$(top_srcdir)/lib/includes \ -I$(top_srcdir)/lib/includes \
-I$(top_builddir)/lib/includes \ -I$(top_builddir)/lib/includes \
-I$(top_srcdir)/third-party/urlparse \ -I$(top_srcdir)/third-party \
@LIBEVENT_OPENSSL_CFLAGS@ \ @LIBEVENT_OPENSSL_CFLAGS@ \
@OPENSSL_CFLAGS@ \ @OPENSSL_CFLAGS@ \
@DEFS@ @DEFS@
AM_LDFLAGS = @LIBTOOL_LDFLAGS@ AM_LDFLAGS = @LIBTOOL_LDFLAGS@
LDADD = $(top_builddir)/lib/libnghttp2.la \ LDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/liburlparse.la \ $(top_builddir)/third-party/liburl-parser.la \
@LIBEVENT_OPENSSL_LIBS@ \ @LIBEVENT_OPENSSL_LIBS@ \
@OPENSSL_LIBS@ \ @OPENSSL_LIBS@ \
@APPLDFLAGS@ @APPLDFLAGS@

View File

@@ -67,14 +67,14 @@ enum { IO_NONE, WANT_READ, WANT_WRITE };
#define MAKE_NV(NAME, VALUE) \ #define MAKE_NV(NAME, VALUE) \
{ \ { \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, \ (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
sizeof(VALUE) - 1, NGHTTP2_NV_FLAG_NONE, \ NGHTTP2_NV_FLAG_NONE \
} }
#define MAKE_NV_CS(NAME, VALUE) \ #define MAKE_NV_CS(NAME, VALUE) \
{ \ { \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, \ (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, strlen(VALUE), \
strlen(VALUE), NGHTTP2_NV_FLAG_NONE, \ NGHTTP2_NV_FLAG_NONE \
} }
struct Connection { struct Connection {
@@ -176,7 +176,7 @@ static nghttp2_ssize send_callback(nghttp2_session *session,
int err = SSL_get_error(connection->ssl, rv); int err = SSL_get_error(connection->ssl, rv);
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
connection->want_io = connection->want_io =
(err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE); (err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);
rv = NGHTTP2_ERR_WOULDBLOCK; rv = NGHTTP2_ERR_WOULDBLOCK;
} else { } else {
rv = NGHTTP2_ERR_CALLBACK_FAILURE; rv = NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -207,7 +207,7 @@ static nghttp2_ssize recv_callback(nghttp2_session *session, uint8_t *buf,
int err = SSL_get_error(connection->ssl, rv); int err = SSL_get_error(connection->ssl, rv);
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
connection->want_io = connection->want_io =
(err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE); (err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);
rv = NGHTTP2_ERR_WOULDBLOCK; rv = NGHTTP2_ERR_WOULDBLOCK;
} else { } else {
rv = NGHTTP2_ERR_CALLBACK_FAILURE; rv = NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -342,10 +342,10 @@ static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {
on_frame_recv_callback); on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback( nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback); callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback( nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
callbacks, on_data_chunk_recv_callback); callbacks, on_data_chunk_recv_callback);
} }
/* /*

View File

@@ -34,8 +34,8 @@
#define MAKE_NV(K, V) \ #define MAKE_NV(K, V) \
{ \ { \
(uint8_t *)K, (uint8_t *)V, sizeof(K) - 1, \ (uint8_t *)K, (uint8_t *)V, sizeof(K) - 1, sizeof(V) - 1, \
sizeof(V) - 1, NGHTTP2_NV_FLAG_NONE, \ NGHTTP2_NV_FLAG_NONE \
} }
static void deflate(nghttp2_hd_deflater *deflater, static void deflate(nghttp2_hd_deflater *deflater,
@@ -51,9 +51,9 @@ int main(void) {
nghttp2_hd_inflater *inflater; nghttp2_hd_inflater *inflater;
/* Define 1st header set. This is looks like a HTTP request. */ /* Define 1st header set. This is looks like a HTTP request. */
nghttp2_nv nva1[] = { nghttp2_nv nva1[] = {
MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "example.org"), MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "example.org"),
MAKE_NV(":path", "/"), MAKE_NV("user-agent", "libnghttp2"), MAKE_NV(":path", "/"), MAKE_NV("user-agent", "libnghttp2"),
MAKE_NV("accept-encoding", "gzip, deflate")}; MAKE_NV("accept-encoding", "gzip, deflate")};
/* Define 2nd header set */ /* Define 2nd header set */
nghttp2_nv nva2[] = {MAKE_NV(":scheme", "https"), nghttp2_nv nva2[] = {MAKE_NV(":scheme", "https"),
MAKE_NV(":authority", "example.org"), MAKE_NV(":authority", "example.org"),
@@ -175,7 +175,7 @@ int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
size_t proclen; size_t proclen;
rv = rv =
nghttp2_hd_inflate_hd3(inflater, &nv, &inflate_flags, in, inlen, final); nghttp2_hd_inflate_hd3(inflater, &nv, &inflate_flags, in, inlen, final);
if (rv < 0) { if (rv < 0) {
fprintf(stderr, "inflate failed with error code %td", rv); fprintf(stderr, "inflate failed with error code %td", rv);

View File

@@ -66,7 +66,7 @@ char *strndup(const char *s, size_t size);
#define NGHTTP2_NO_SSIZE_T #define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include "urlparse.h" #include "url-parser/url_parser.h"
#define ARRLEN(x) (sizeof(x) / sizeof(x[0])) #define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
@@ -74,7 +74,7 @@ typedef struct {
/* The NULL-terminated URI string to retrieve. */ /* The NULL-terminated URI string to retrieve. */
const char *uri; const char *uri;
/* Parsed result of the |uri| */ /* Parsed result of the |uri| */
urlparse_url *u; struct http_parser_url *u;
/* The authority portion of the |uri|, not NULL-terminated */ /* The authority portion of the |uri|, not NULL-terminated */
char *authority; char *authority;
/* The path portion of the |uri|, including query, not /* The path portion of the |uri|, including query, not
@@ -96,7 +96,7 @@ typedef struct {
} http2_session_data; } http2_session_data;
static http2_stream_data *create_http2_stream_data(const char *uri, static http2_stream_data *create_http2_stream_data(const char *uri,
urlparse_url *u) { struct http_parser_url *u) {
/* MAX 5 digits (max 65535) + 1 ':' + 1 NULL (because of snprintf) */ /* MAX 5 digits (max 65535) + 1 ':' + 1 NULL (because of snprintf) */
size_t extra = 7; size_t extra = 7;
http2_stream_data *stream_data = malloc(sizeof(http2_stream_data)); http2_stream_data *stream_data = malloc(sizeof(http2_stream_data));
@@ -105,41 +105,39 @@ static http2_stream_data *create_http2_stream_data(const char *uri,
stream_data->u = u; stream_data->u = u;
stream_data->stream_id = -1; stream_data->stream_id = -1;
stream_data->authoritylen = u->field_data[URLPARSE_HOST].len; stream_data->authoritylen = u->field_data[UF_HOST].len;
stream_data->authority = malloc(stream_data->authoritylen + extra); stream_data->authority = malloc(stream_data->authoritylen + extra);
memcpy(stream_data->authority, &uri[u->field_data[URLPARSE_HOST].off], memcpy(stream_data->authority, &uri[u->field_data[UF_HOST].off],
u->field_data[URLPARSE_HOST].len); u->field_data[UF_HOST].len);
if (u->field_set & (1 << URLPARSE_PORT)) { if (u->field_set & (1 << UF_PORT)) {
stream_data->authoritylen += (size_t)snprintf( stream_data->authoritylen +=
stream_data->authority + u->field_data[URLPARSE_HOST].len, extra, ":%u", (size_t)snprintf(stream_data->authority + u->field_data[UF_HOST].len,
u->port); extra, ":%u", u->port);
} }
/* If we don't have path in URI, we use "/" as path. */ /* If we don't have path in URI, we use "/" as path. */
stream_data->pathlen = 1; stream_data->pathlen = 1;
if (u->field_set & (1 << URLPARSE_PATH)) { if (u->field_set & (1 << UF_PATH)) {
stream_data->pathlen = u->field_data[URLPARSE_PATH].len; stream_data->pathlen = u->field_data[UF_PATH].len;
} }
if (u->field_set & (1 << URLPARSE_QUERY)) { if (u->field_set & (1 << UF_QUERY)) {
/* +1 for '?' character */ /* +1 for '?' character */
stream_data->pathlen += (size_t)(u->field_data[URLPARSE_QUERY].len + 1); stream_data->pathlen += (size_t)(u->field_data[UF_QUERY].len + 1);
} }
stream_data->path = malloc(stream_data->pathlen); stream_data->path = malloc(stream_data->pathlen);
if (u->field_set & (1 << URLPARSE_PATH)) { if (u->field_set & (1 << UF_PATH)) {
memcpy(stream_data->path, &uri[u->field_data[URLPARSE_PATH].off], memcpy(stream_data->path, &uri[u->field_data[UF_PATH].off],
u->field_data[URLPARSE_PATH].len); u->field_data[UF_PATH].len);
} else { } else {
stream_data->path[0] = '/'; stream_data->path[0] = '/';
} }
if (u->field_set & (1 << URLPARSE_QUERY)) { if (u->field_set & (1 << UF_QUERY)) {
stream_data stream_data->path[stream_data->pathlen - u->field_data[UF_QUERY].len - 1] =
->path[stream_data->pathlen - u->field_data[URLPARSE_QUERY].len - 1] = '?';
'?';
memcpy(stream_data->path + stream_data->pathlen - memcpy(stream_data->path + stream_data->pathlen -
u->field_data[URLPARSE_QUERY].len, u->field_data[UF_QUERY].len,
&uri[u->field_data[URLPARSE_QUERY].off], &uri[u->field_data[UF_QUERY].off], u->field_data[UF_QUERY].len);
u->field_data[URLPARSE_QUERY].len);
} }
return stream_data; return stream_data;
@@ -320,9 +318,10 @@ static SSL_CTX *create_ssl_ctx(void) {
errx(1, "Could not create SSL/TLS context: %s", errx(1, "Could not create SSL/TLS context: %s",
ERR_error_string(ERR_get_error(), NULL)); ERR_error_string(ERR_get_error(), NULL));
} }
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_CTX_set_options(ssl_ctx,
SSL_OP_NO_COMPRESSION | SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3); SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
@@ -351,16 +350,16 @@ static void initialize_nghttp2_session(http2_session_data *session_data) {
on_frame_recv_callback); on_frame_recv_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback( nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
callbacks, on_data_chunk_recv_callback); callbacks, on_data_chunk_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback( nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback); callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks, nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback); on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback( nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback); callbacks, on_begin_headers_callback);
nghttp2_session_client_new(&session_data->session, callbacks, session_data); nghttp2_session_client_new(&session_data->session, callbacks, session_data);
@@ -369,7 +368,7 @@ static void initialize_nghttp2_session(http2_session_data *session_data) {
static void send_client_connection_header(http2_session_data *session_data) { static void send_client_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = { nghttp2_settings_entry iv[1] = {
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}}; {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv; int rv;
/* client 24 bytes magic string will be sent by nghttp2 library */ /* client 24 bytes magic string will be sent by nghttp2 library */
@@ -382,14 +381,14 @@ static void send_client_connection_header(http2_session_data *session_data) {
#define MAKE_NV(NAME, VALUE, VALUELEN) \ #define MAKE_NV(NAME, VALUE, VALUELEN) \
{ \ { \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, \ (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, VALUELEN, \
VALUELEN, NGHTTP2_NV_FLAG_NONE, \ NGHTTP2_NV_FLAG_NONE \
} }
#define MAKE_NV2(NAME, VALUE) \ #define MAKE_NV2(NAME, VALUE) \
{ \ { \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, \ (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
sizeof(VALUE) - 1, NGHTTP2_NV_FLAG_NONE, \ NGHTTP2_NV_FLAG_NONE \
} }
/* Send HTTP request to the remote peer */ /* Send HTTP request to the remote peer */
@@ -397,13 +396,13 @@ static void submit_request(http2_session_data *session_data) {
int32_t stream_id; int32_t stream_id;
http2_stream_data *stream_data = session_data->stream_data; http2_stream_data *stream_data = session_data->stream_data;
const char *uri = stream_data->uri; const char *uri = stream_data->uri;
const urlparse_url *u = stream_data->u; const struct http_parser_url *u = stream_data->u;
nghttp2_nv hdrs[] = { nghttp2_nv hdrs[] = {
MAKE_NV2(":method", "GET"), MAKE_NV2(":method", "GET"),
MAKE_NV(":scheme", &uri[u->field_data[URLPARSE_SCHEMA].off], MAKE_NV(":scheme", &uri[u->field_data[UF_SCHEMA].off],
u->field_data[URLPARSE_SCHEMA].len), u->field_data[UF_SCHEMA].len),
MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen), MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
MAKE_NV(":path", stream_data->path, stream_data->pathlen)}; MAKE_NV(":path", stream_data->path, stream_data->pathlen)};
fprintf(stderr, "Request headers:\n"); fprintf(stderr, "Request headers:\n");
print_headers(stderr, hdrs, ARRLEN(hdrs)); print_headers(stderr, hdrs, ARRLEN(hdrs));
stream_id = nghttp2_submit_request2(session_data->session, NULL, hdrs, stream_id = nghttp2_submit_request2(session_data->session, NULL, hdrs,
@@ -528,8 +527,8 @@ static void initiate_connection(struct event_base *evbase, SSL_CTX *ssl_ctx,
ssl = create_ssl(ssl_ctx); ssl = create_ssl(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_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,
@@ -544,7 +543,7 @@ static void initiate_connection(struct event_base *evbase, SSL_CTX *ssl_ctx,
/* Get resource denoted by the |uri|. The debug and error messages are /* Get resource denoted by the |uri|. The debug and error messages are
printed in stderr, while the response body is printed in stdout. */ printed in stderr, while the response body is printed in stdout. */
static void run(const char *uri) { static void run(const char *uri) {
urlparse_url u; struct http_parser_url u;
char *host; char *host;
uint16_t port; uint16_t port;
int rv; int rv;
@@ -553,13 +552,12 @@ static void run(const char *uri) {
http2_session_data *session_data; http2_session_data *session_data;
/* Parse the |uri| and stores its components in |u| */ /* Parse the |uri| and stores its components in |u| */
rv = urlparse_parse_url(uri, strlen(uri), 0, &u); rv = http_parser_parse_url(uri, strlen(uri), 0, &u);
if (rv != 0) { if (rv != 0) {
errx(1, "Could not parse URI %s", uri); errx(1, "Could not parse URI %s", uri);
} }
host = strndup(&uri[u.field_data[URLPARSE_HOST].off], host = strndup(&uri[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len);
u.field_data[URLPARSE_HOST].len); if (!(u.field_set & (1 << UF_PORT))) {
if (!(u.field_set & (1 << URLPARSE_PORT))) {
port = 443; port = 443;
} else { } else {
port = u.port; port = u.port;

View File

@@ -80,8 +80,8 @@
#define MAKE_NV(NAME, VALUE) \ #define MAKE_NV(NAME, VALUE) \
{ \ { \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, \ (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
sizeof(VALUE) - 1, NGHTTP2_NV_FLAG_NONE, \ NGHTTP2_NV_FLAG_NONE \
} }
struct app_context; struct app_context;
@@ -132,9 +132,10 @@ static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
errx(1, "Could not create SSL/TLS context: %s", errx(1, "Could not create SSL/TLS context: %s",
ERR_error_string(ERR_get_error(), NULL)); ERR_error_string(ERR_get_error(), NULL));
} }
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_CTX_set_options(ssl_ctx,
SSL_OP_NO_COMPRESSION | SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L #if OPENSSL_VERSION_NUMBER >= 0x30000000L
if (SSL_CTX_set1_curves_list(ssl_ctx, "P-256") != 1) { if (SSL_CTX_set1_curves_list(ssl_ctx, "P-256") != 1) {
errx(1, "SSL_CTX_set1_curves_list failed: %s", errx(1, "SSL_CTX_set1_curves_list failed: %s",
@@ -232,8 +233,8 @@ static http2_session_data *create_http2_session_data(app_context *app_ctx,
session_data->app_ctx = app_ctx; session_data->app_ctx = app_ctx;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
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); 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);
@@ -359,7 +360,7 @@ static char *percent_decode(const uint8_t *value, size_t valuelen) {
continue; continue;
} }
res[j++] = res[j++] =
(char)((hex_to_uint(value[i + 1]) << 4) + hex_to_uint(value[i + 2])); (char)((hex_to_uint(value[i + 1]) << 4) + hex_to_uint(value[i + 2]));
i += 3; i += 3;
} }
memcpy(&res[j], &value[i], 2); memcpy(&res[j], &value[i], 2);
@@ -421,9 +422,9 @@ static int error_reply(nghttp2_session *session,
rv = pipe(pipefd); rv = pipe(pipefd);
if (rv != 0) { if (rv != 0) {
warn("Could not create pipe"); warn("Could not create pipe");
rv = rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, stream_data->stream_id,
stream_data->stream_id, NGHTTP2_INTERNAL_ERROR); NGHTTP2_INTERNAL_ERROR);
if (rv != 0) { if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv)); warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1; return -1;
@@ -466,7 +467,7 @@ static int on_header_callback(nghttp2_session *session,
break; break;
} }
stream_data = stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (!stream_data || stream_data->request_path) { if (!stream_data || stream_data->request_path) {
break; break;
} }
@@ -556,7 +557,7 @@ static int on_frame_recv_callback(nghttp2_session *session,
/* Check that the client request has finished */ /* Check that the client request has finished */
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data = stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
/* For DATA and HEADERS frame, this callback may be called after /* For DATA and HEADERS frame, this callback may be called after
on_stream_close_callback. Check that stream still alive. */ on_stream_close_callback. Check that stream still alive. */
if (!stream_data) { if (!stream_data) {
@@ -597,13 +598,13 @@ static void initialize_nghttp2_session(http2_session_data *session_data) {
on_frame_recv_callback); on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback( nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback); callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks, nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback); on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback( nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback); callbacks, on_begin_headers_callback);
nghttp2_session_server_new(&session_data->session, callbacks, session_data); nghttp2_session_server_new(&session_data->session, callbacks, session_data);
@@ -614,7 +615,7 @@ static void initialize_nghttp2_session(http2_session_data *session_data) {
magic octets and SETTINGS frame */ magic octets and SETTINGS frame */
static int send_server_connection_header(http2_session_data *session_data) { static int send_server_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = { nghttp2_settings_entry iv[1] = {
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}}; {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv; int rv;
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv, rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
@@ -736,8 +737,8 @@ static void start_listen(struct event_base *evbase, const char *service,
for (rp = res; rp; rp = rp->ai_next) { for (rp = res; rp; rp = rp->ai_next) {
struct evconnlistener *listener; struct evconnlistener *listener;
listener = evconnlistener_new_bind( listener = evconnlistener_new_bind(
evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 16, evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
rp->ai_addr, (int)rp->ai_addrlen); 16, rp->ai_addr, (int)rp->ai_addrlen);
if (listener) { if (listener) {
freeaddrinfo(res); freeaddrinfo(res);

View File

@@ -62,8 +62,8 @@ void check_frame_pack_headers(FuzzedDataProvider *data_provider) {
nvlen = HEADERS_LENGTH; nvlen = HEADERS_LENGTH;
nghttp2_priority_spec_default_init(&pri_spec); nghttp2_priority_spec_default_init(&pri_spec);
nghttp2_frame_headers_init( nghttp2_frame_headers_init(
&frame, NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS, 1000000007, &frame, NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS, 1000000007,
NGHTTP2_HCAT_REQUEST, &pri_spec, nva, nvlen); NGHTTP2_HCAT_REQUEST, &pri_spec, nva, nvlen);
/* Perform a set of operations with the fuzz data */ /* Perform a set of operations with the fuzz data */
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater); rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);

View File

@@ -56,11 +56,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback); on_frame_recv_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback( nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback); callbacks, on_begin_headers_callback);
nghttp2_session_callbacks_set_on_header_callback2(callbacks, nghttp2_session_callbacks_set_on_header_callback2(callbacks,
on_header_callback2); on_header_callback2);
nghttp2_session_callbacks_set_before_frame_send_callback( nghttp2_session_callbacks_set_before_frame_send_callback(
callbacks, before_frame_send_callback); callbacks, before_frame_send_callback);
nghttp2_session_callbacks_set_on_frame_send_callback(callbacks, nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
on_frame_send_callback); on_frame_send_callback);

View File

@@ -60,11 +60,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback); on_frame_recv_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback( nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback); callbacks, on_begin_headers_callback);
nghttp2_session_callbacks_set_on_header_callback2(callbacks, nghttp2_session_callbacks_set_on_header_callback2(callbacks,
on_header_callback2); on_header_callback2);
nghttp2_session_callbacks_set_before_frame_send_callback( nghttp2_session_callbacks_set_before_frame_send_callback(
callbacks, before_frame_send_callback); callbacks, before_frame_send_callback);
nghttp2_session_callbacks_set_on_frame_send_callback(callbacks, nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
on_frame_send_callback); on_frame_send_callback);

View File

@@ -35,7 +35,7 @@ enum {''')
def gen_index_header(tokens, prefix, comp_fun, return_type, fail_value): def gen_index_header(tokens, prefix, comp_fun, return_type, fail_value):
print('''\ print('''\
{} lookup_token(const std::string_view &name) {{ {} lookup_token(const StringRef &name) {{
switch (name.size()) {{'''.format(return_type)) switch (name.size()) {{'''.format(return_type))
b = build_header(tokens) b = build_header(tokens)
for size in sorted(b.keys()): for size in sorted(b.keys()):
@@ -50,7 +50,7 @@ def gen_index_header(tokens, prefix, comp_fun, return_type, fail_value):
case '{}':'''.format(c)) case '{}':'''.format(c))
for k in headers: for k in headers:
print('''\ print('''\
if ({}("{}"sv, name.substr(0, {}))) {{ if ({}("{}"_sr, name, {})) {{
return {}; return {};
}}'''.format(comp_fun, k[:-1], size - 1, to_enum_hd(k, prefix))) }}'''.format(comp_fun, k[:-1], size - 1, to_enum_hd(k, prefix)))
print('''\ print('''\

25
go.mod
View File

@@ -1,21 +1,24 @@
module github.com/nghttp2/nghttp2 module github.com/nghttp2/nghttp2
go 1.24.0 go 1.21.1
require ( require (
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874
github.com/quic-go/quic-go v0.54.0 github.com/quic-go/quic-go v0.43.1
github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20240121064059-46ccb0a462a8 github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20240121064059-46ccb0a462a8
golang.org/x/net v0.43.0 golang.org/x/net v0.24.0
) )
require ( require (
github.com/quic-go/qpack v0.5.1 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
go.uber.org/mock v0.5.0 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
golang.org/x/crypto v0.41.0 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect
golang.org/x/mod v0.26.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect
golang.org/x/sync v0.16.0 // indirect go.uber.org/mock v0.4.0 // indirect
golang.org/x/sys v0.35.0 // indirect golang.org/x/crypto v0.22.0 // indirect
golang.org/x/text v0.28.0 // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/tools v0.35.0 // indirect golang.org/x/mod v0.11.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.9.1 // indirect
) )

73
go.sum
View File

@@ -1,34 +1,59 @@
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= github.com/quic-go/quic-go v0.43.1 h1:fLiMNfQVe9q2JvSsiXo4fXOEguXHGGl9+6gLp4RPeZQ=
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= github.com/quic-go/quic-go v0.43.1/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20240121064059-46ccb0a462a8 h1:zKJxuRe+a0O34V81GAZWOrotuU6mveT30QLjJ7OPMMg= github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20240121064059-46ccb0a462a8 h1:zKJxuRe+a0O34V81GAZWOrotuU6mveT30QLjJ7OPMMg=
github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20240121064059-46ccb0a462a8/go.mod h1:gTqc3Q4boc+cKRlSFywTYdX9t6VGRcsThlNIWwaL3Dc= github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20240121064059-46ccb0a462a8/go.mod h1:gTqc3Q4boc+cKRlSFywTYdX9t6VGRcsThlNIWwaL3Dc=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -4,7 +4,6 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@@ -63,7 +62,6 @@ func TestH1H1InvalidMethod(t *testing.T) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -88,7 +86,6 @@ func TestH1H1MultipleRequestCL(t *testing.T) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -136,7 +133,6 @@ func TestH1H1AffinityCookie(t *testing.T) {
opts := options{ opts := options{
args: []string{"--affinity-cookie"}, args: []string{"--affinity-cookie"},
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -153,7 +149,6 @@ func TestH1H1AffinityCookie(t *testing.T) {
const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar` const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar`
validCookie := regexp.MustCompile(pattern) validCookie := regexp.MustCompile(pattern)
if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) { if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern) t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
} }
@@ -166,7 +161,6 @@ func TestH1H1AffinityCookieTLS(t *testing.T) {
args: []string{"--alpn-h1", "--affinity-cookie"}, args: []string{"--alpn-h1", "--affinity-cookie"},
tls: true, tls: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -183,7 +177,6 @@ func TestH1H1AffinityCookieTLS(t *testing.T) {
const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure` const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure`
validCookie := regexp.MustCompile(pattern) validCookie := regexp.MustCompile(pattern)
if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) { if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern) t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
} }
@@ -228,8 +221,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); !errors.Is(err, want) {
t.Errorf("st.conn.Read(): %v; want %v", err, want) t.Errorf("st.conn.Read(): %v; want %v", err, want)
} }
} }
@@ -242,7 +234,6 @@ func TestH1H1HostRewrite(t *testing.T) {
w.Header().Add("request-host", r.Host) w.Header().Add("request-host", r.Host)
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -252,11 +243,9 @@ func TestH1H1HostRewrite(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
if got, want := res.header.Get("request-host"), st.backendHost; got != want { if got, want := res.header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want) t.Errorf("request-host: %v; want %v", got, want)
} }
@@ -270,14 +259,12 @@ func TestH1H1BadHost(t *testing.T) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H1HBadHost\r\nHost: foo\"bar\r\n\r\n"); err != nil { if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H1HBadHost\r\nHost: foo\"bar\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err) t.Fatalf("Error io.WriteString() = %v", err)
} }
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil { if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err) t.Fatalf("Error http.ReadResponse() = %v", err)
@@ -298,14 +285,12 @@ func TestH1H1BadAuthority(t *testing.T) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
if _, err := io.WriteString(st.conn, "GET http://foo\"bar/ HTTP/1.1\r\nTest-Case: TestH1H1HBadAuthority\r\nHost: foobar\r\n\r\n"); err != nil { if _, err := io.WriteString(st.conn, "GET http://foo\"bar/ HTTP/1.1\r\nTest-Case: TestH1H1HBadAuthority\r\nHost: foobar\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err) t.Fatalf("Error io.WriteString() = %v", err)
} }
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil { if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err) t.Fatalf("Error http.ReadResponse() = %v", err)
@@ -326,14 +311,12 @@ func TestH1H1BadScheme(t *testing.T) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
if _, err := io.WriteString(st.conn, "GET http*://example.com/ HTTP/1.1\r\nTest-Case: TestH1H1HBadScheme\r\nHost: example.com\r\n\r\n"); err != nil { if _, err := io.WriteString(st.conn, "GET http*://example.com/ HTTP/1.1\r\nTest-Case: TestH1H1HBadScheme\r\nHost: example.com\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err) t.Fatalf("Error io.WriteString() = %v", err)
} }
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil { if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err) t.Fatalf("Error http.ReadResponse() = %v", err)
@@ -354,7 +337,6 @@ func TestH1H1HTTP10(t *testing.T) {
w.Header().Add("request-host", r.Host) w.Header().Add("request-host", r.Host)
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -372,7 +354,6 @@ func TestH1H1HTTP10(t *testing.T) {
if got, want := resp.StatusCode, http.StatusOK; got != want { if got, want := resp.StatusCode, http.StatusOK; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want { if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want) t.Errorf("request-host: %v; want %v", got, want)
} }
@@ -387,7 +368,6 @@ func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
w.Header().Add("request-host", r.Host) w.Header().Add("request-host", r.Host)
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -405,7 +385,6 @@ func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
if got, want := resp.StatusCode, http.StatusOK; got != want { if got, want := resp.StatusCode, http.StatusOK; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want { if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want) t.Errorf("request-host: %v; want %v", got, want)
} }
@@ -419,11 +398,10 @@ func TestH1H1RequestTrailer(t *testing.T) {
buf := make([]byte, 4096) buf := make([]byte, 4096)
for { for {
_, err := r.Body.Read(buf) _, err := r.Body.Read(buf)
if err == io.EOF {
break
}
if err != nil { if err != nil {
if errors.Is(err, io.EOF) {
break
}
t.Fatalf("r.Body.Read() = %v", err) t.Fatalf("r.Body.Read() = %v", err)
} }
} }
@@ -432,7 +410,6 @@ func TestH1H1RequestTrailer(t *testing.T) {
} }
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -446,7 +423,6 @@ func TestH1H1RequestTrailer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
@@ -464,7 +440,6 @@ func TestH1H1HeaderFieldBufferPath(t *testing.T) {
t.Fatal("execution path should not be here") t.Fatal("execution path should not be here")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -475,7 +450,6 @@ func TestH1H1HeaderFieldBufferPath(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want { if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
@@ -490,7 +464,6 @@ func TestH1H1HeaderFieldBuffer(t *testing.T) {
t.Fatal("execution path should not be here") t.Fatal("execution path should not be here")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -500,7 +473,6 @@ func TestH1H1HeaderFieldBuffer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want { if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
@@ -515,7 +487,6 @@ func TestH1H1HeaderFields(t *testing.T) {
t.Fatal("execution path should not be here") t.Fatal("execution path should not be here")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -530,7 +501,6 @@ func TestH1H1HeaderFields(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want { if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
@@ -545,7 +515,6 @@ func TestH1H1Websocket(t *testing.T) {
} }
}).ServeHTTP, }).ServeHTTP,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -554,7 +523,6 @@ func TestH1H1Websocket(t *testing.T) {
name: "TestH1H1Websocket", name: "TestH1H1Websocket",
body: content, body: content,
}) })
if got, want := res.body, content; !bytes.Equal(got, want) { if got, want := res.body, content; !bytes.Equal(got, want) {
t.Errorf("echo: %q; want %q", got, want) t.Errorf("echo: %q; want %q", got, want)
} }
@@ -571,7 +539,6 @@ func TestH1H1ReqPhaseSetHeader(t *testing.T) {
} }
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -596,7 +563,6 @@ func TestH1H1ReqPhaseReturn(t *testing.T) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -637,7 +603,6 @@ func TestH1H1ReqPhaseReturnCONNECTMethod(t *testing.T) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -705,7 +670,6 @@ func TestH1H1RespPhaseSetHeader(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/resp-set-header.rb"}, args: []string{"--mruby-file=" + testDir + "/resp-set-header.rb"},
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -731,7 +695,6 @@ func TestH1H1RespPhaseReturn(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/resp-return.rb"}, args: []string{"--mruby-file=" + testDir + "/resp-return.rb"},
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -769,7 +732,6 @@ func TestH1H1HTTPSRedirect(t *testing.T) {
opts := options{ opts := options{
args: []string{"--redirect-if-not-tls"}, args: []string{"--redirect-if-not-tls"},
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -783,7 +745,6 @@ func TestH1H1HTTPSRedirect(t *testing.T) {
if got, want := res.status, http.StatusPermanentRedirect; got != want { if got, want := res.status, http.StatusPermanentRedirect; got != want {
t.Errorf("status = %v; want %v", got, want) t.Errorf("status = %v; want %v", got, want)
} }
if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want { if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want {
t.Errorf("location: %v; want %v", got, want) t.Errorf("location: %v; want %v", got, want)
} }
@@ -798,7 +759,6 @@ func TestH1H1HTTPSRedirectPort(t *testing.T) {
"--redirect-https-port=8443", "--redirect-https-port=8443",
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -813,7 +773,6 @@ func TestH1H1HTTPSRedirectPort(t *testing.T) {
if got, want := res.status, http.StatusPermanentRedirect; got != want { if got, want := res.status, http.StatusPermanentRedirect; got != want {
t.Errorf("status = %v; want %v", got, want) t.Errorf("status = %v; want %v", got, want)
} }
if got, want := res.header.Get("location"), "https://127.0.0.1:8443/foo?bar"; got != want { if got, want := res.header.Get("location"), "https://127.0.0.1:8443/foo?bar"; got != want {
t.Errorf("location: %v; want %v", got, want) t.Errorf("location: %v; want %v", got, want)
} }
@@ -832,7 +791,6 @@ func TestH1H1POSTRequests(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
@@ -844,7 +802,6 @@ func TestH1H1POSTRequests(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
@@ -860,7 +817,6 @@ func TestH1H1CONNECTMethodFailure(t *testing.T) {
} }
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -882,39 +838,12 @@ func TestH1H1CONNECTMethodFailure(t *testing.T) {
if _, err := io.ReadAll(resp.Body); err != nil { if _, err := io.ReadAll(resp.Body); err != nil {
t.Fatalf("Error io.ReadAll() = %v", err) t.Fatalf("Error io.ReadAll() = %v", err)
} }
}
// TestH1H1CONNECTMethod tests that CONNECT request succeeds. if _, err := io.WriteString(st.conn, "CONNECT 127.0.0.1:443 HTTP/1.1\r\nTest-Case: TestH1H1CONNECTMethodFailure\r\nHost: 127.0.0.1:443\r\nrequired-header: foo\r\n\r\n"); err != nil {
func TestH1H1CONNECTMethod(t *testing.T) {
opts := options{
handler: 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
}
_, bufrw, err := hj.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if _, err := bufrw.WriteString("HTTP/1.1 200\r\n\r\n"); err != nil {
t.Fatalf("Error bufrw.WriteString() = %v", err)
}
bufrw.Flush()
},
}
st := newServerTester(t, opts)
defer st.Close()
if _, err := io.WriteString(st.conn, "CONNECT 127.0.0.1:443 HTTP/1.1\r\nTest-Case: TestH1H1CONNECTMethod\r\nHost: 127.0.0.1:443\r\n\r\n"); err != nil {
t.Fatalf("Error io.WriteString() = %v", err) t.Fatalf("Error io.WriteString() = %v", err)
} }
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) resp, err = http.ReadResponse(bufio.NewReader(st.conn), nil)
if err != nil { if err != nil {
t.Fatalf("Error http.ReadResponse() = %v", err) t.Fatalf("Error http.ReadResponse() = %v", err)
} }
@@ -959,7 +888,6 @@ func TestH1H2NoHost(t *testing.T) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -989,7 +917,6 @@ func TestH1H2HTTP10(t *testing.T) {
w.Header().Add("request-host", r.Host) w.Header().Add("request-host", r.Host)
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1007,7 +934,6 @@ func TestH1H2HTTP10(t *testing.T) {
if got, want := resp.StatusCode, http.StatusOK; got != want { if got, want := resp.StatusCode, http.StatusOK; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want { if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want) t.Errorf("request-host: %v; want %v", got, want)
} }
@@ -1023,7 +949,6 @@ func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
w.Header().Add("request-host", r.Host) w.Header().Add("request-host", r.Host)
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1041,7 +966,6 @@ func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
if got, want := resp.StatusCode, http.StatusOK; got != want { if got, want := resp.StatusCode, http.StatusOK; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want { if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
t.Errorf("request-host: %v; want %v", got, want) t.Errorf("request-host: %v; want %v", got, want)
} }
@@ -1060,7 +984,6 @@ func TestH1H2CrumbleCookie(t *testing.T) {
} }
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1073,7 +996,6 @@ func TestH1H2CrumbleCookie(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
@@ -1090,7 +1012,6 @@ func TestH1H2GenerateVia(t *testing.T) {
} }
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1100,7 +1021,6 @@ func TestH1H2GenerateVia(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.header.Get("Via"), "2 nghttpx"; got != want { if got, want := res.header.Get("Via"), "2 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want) t.Errorf("Via: %v; want %v", got, want)
} }
@@ -1118,7 +1038,6 @@ func TestH1H2AppendVia(t *testing.T) {
w.Header().Add("Via", "bar") w.Header().Add("Via", "bar")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1131,7 +1050,6 @@ func TestH1H2AppendVia(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.header.Get("Via"), "bar, 2 nghttpx"; got != want { if got, want := res.header.Get("Via"), "bar, 2 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want) t.Errorf("Via: %v; want %v", got, want)
} }
@@ -1149,7 +1067,6 @@ func TestH1H2NoVia(t *testing.T) {
w.Header().Add("Via", "bar") w.Header().Add("Via", "bar")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1162,7 +1079,6 @@ func TestH1H2NoVia(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.header.Get("Via"), "bar"; got != want { if got, want := res.header.Get("Via"), "bar"; got != want {
t.Errorf("Via: %v; want %v", got, want) t.Errorf("Via: %v; want %v", got, want)
} }
@@ -1180,7 +1096,6 @@ func TestH1H2ReqPhaseReturn(t *testing.T) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1221,7 +1136,6 @@ func TestH1H2RespPhaseReturn(t *testing.T) {
"--mruby-file=" + testDir + "/resp-return.rb", "--mruby-file=" + testDir + "/resp-return.rb",
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1264,7 +1178,6 @@ func TestH1H2TE(t *testing.T) {
} }
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1277,7 +1190,6 @@ func TestH1H2TE(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("status: %v; want %v", got, want) t.Errorf("status: %v; want %v", got, want)
} }
@@ -1293,7 +1205,6 @@ func TestH1APIBackendconfig(t *testing.T) {
}, },
connectPort: 3010, connectPort: 3010,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1309,21 +1220,18 @@ backend=127.0.0.1,3011
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
var apiResp APIResponse var apiResp APIResponse
err = json.Unmarshal(res.body, &apiResp)
if err := json.Unmarshal(res.body, &apiResp); err != nil { if err != nil {
t.Fatalf("Error unmarshaling API response: %v", err) t.Fatalf("Error unmarshaling API response: %v", err)
} }
if got, want := apiResp.Status, "Success"; got != want { if got, want := apiResp.Status, "Success"; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
if got, want := apiResp.Code, 200; got != want { if got, want := apiResp.Code, 200; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
@@ -1339,7 +1247,6 @@ func TestH1APIBackendconfigQuery(t *testing.T) {
}, },
connectPort: 3010, connectPort: 3010,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1355,21 +1262,18 @@ backend=127.0.0.1,3011
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
var apiResp APIResponse var apiResp APIResponse
err = json.Unmarshal(res.body, &apiResp)
if err := json.Unmarshal(res.body, &apiResp); err != nil { if err != nil {
t.Fatalf("Error unmarshaling API response: %v", err) t.Fatalf("Error unmarshaling API response: %v", err)
} }
if got, want := apiResp.Status, "Success"; got != want { if got, want := apiResp.Status, "Success"; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
if got, want := apiResp.Code, 200; got != want { if got, want := apiResp.Code, 200; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
@@ -1385,7 +1289,6 @@ func TestH1APIBackendconfigBadMethod(t *testing.T) {
}, },
connectPort: 3010, connectPort: 3010,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1401,21 +1304,18 @@ backend=127.0.0.1,3011
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusMethodNotAllowed; got != want { if got, want := res.status, http.StatusMethodNotAllowed; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
var apiResp APIResponse var apiResp APIResponse
err = json.Unmarshal(res.body, &apiResp)
if err := json.Unmarshal(res.body, &apiResp); err != nil { if err != nil {
t.Fatalf("Error unmarshaling API response: %v", err) t.Fatalf("Error unmarshaling API response: %v", err)
} }
if got, want := apiResp.Status, "Failure"; got != want { if got, want := apiResp.Status, "Failure"; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
if got, want := apiResp.Code, 405; got != want { if got, want := apiResp.Code, 405; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
@@ -1430,7 +1330,6 @@ func TestH1APIConfigrevision(t *testing.T) {
}, },
connectPort: 3010, connectPort: 3010,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1442,28 +1341,23 @@ func TestH1APIConfigrevision(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("res.status: %v; want = %v", got, want) t.Errorf("res.status: %v; want = %v", got, want)
} }
var apiResp APIResponse var apiResp APIResponse
d := json.NewDecoder(bytes.NewBuffer(res.body)) d := json.NewDecoder(bytes.NewBuffer(res.body))
d.UseNumber() d.UseNumber()
err = d.Decode(&apiResp)
if err := d.Decode(&apiResp); err != nil { if err != nil {
t.Fatalf("Error unmarshalling API response: %v", err) t.Fatalf("Error unmarshalling API response: %v", err)
} }
if got, want := apiResp.Status, "Success"; got != want { if got, want := apiResp.Status, "Success"; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
if got, want := apiResp.Code, 200; got != want { if got, want := apiResp.Code, 200; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
if got, want := apiResp.Data["configRevision"], json.Number("0"); got != want { if got, want := apiResp.Data["configRevision"], json.Number("0"); got != want {
t.Errorf(`apiResp.Data["configRevision"]: %v %t; want %v`, got, got, want) t.Errorf(`apiResp.Data["configRevision"]: %v %t; want %v`, got, got, want)
} }
@@ -1479,7 +1373,6 @@ func TestH1APINotFound(t *testing.T) {
}, },
connectPort: 3010, connectPort: 3010,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1495,21 +1388,18 @@ backend=127.0.0.1,3011
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusNotFound; got != want { if got, want := res.status, http.StatusNotFound; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
var apiResp APIResponse var apiResp APIResponse
err = json.Unmarshal(res.body, &apiResp)
if err := json.Unmarshal(res.body, &apiResp); err != nil { if err != nil {
t.Fatalf("Error unmarshaling API response: %v", err) t.Fatalf("Error unmarshaling API response: %v", err)
} }
if got, want := apiResp.Status, "Failure"; got != want { if got, want := apiResp.Status, "Failure"; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
if got, want := apiResp.Code, 404; got != want { if got, want := apiResp.Code, 404; got != want {
t.Errorf("apiResp.Status: %v; want %v", got, want) t.Errorf("apiResp.Status: %v; want %v", got, want)
} }
@@ -1524,7 +1414,6 @@ func TestH1Healthmon(t *testing.T) {
}, },
connectPort: 3011, connectPort: 3011,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1535,7 +1424,6 @@ func TestH1Healthmon(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
@@ -1550,7 +1438,6 @@ func TestH1ResponseBeforeRequestEnd(t *testing.T) {
t.Fatal("request should not be forwarded") t.Fatal("request should not be forwarded")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1593,7 +1480,6 @@ func TestH1H1ChunkedEndsPrematurely(t *testing.T) {
bufrw.Flush() bufrw.Flush()
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1613,7 +1499,6 @@ func TestH1H1RequestMalformedTransferEncoding(t *testing.T) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1656,7 +1541,6 @@ func TestH1H1ResponseMalformedTransferEncoding(t *testing.T) {
bufrw.Flush() bufrw.Flush()
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1666,7 +1550,6 @@ func TestH1H1ResponseMalformedTransferEncoding(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http1() = %v", err) t.Fatalf("Error st.http1() = %v", err)
} }
if got, want := res.status, http.StatusBadGateway; got != want { if got, want := res.status, http.StatusBadGateway; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
@@ -1694,7 +1577,6 @@ func TestH1H1ResponseUnknownTransferEncoding(t *testing.T) {
bufrw.Flush() bufrw.Flush()
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -1729,7 +1611,6 @@ func TestH1H1RequestHTTP10TransferEncoding(t *testing.T) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@ package nghttp2
import ( import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"errors"
"io" "io"
"net/http" "net/http"
"regexp" "regexp"
@@ -36,7 +35,6 @@ func TestH3H1PlainGET(t *testing.T) {
// TestH3H1RequestBody tests HTTP/3 request with body works. // TestH3H1RequestBody tests HTTP/3 request with body works.
func TestH3H1RequestBody(t *testing.T) { func TestH3H1RequestBody(t *testing.T) {
body := make([]byte, 3333) body := make([]byte, 3333)
_, err := rand.Read(body) _, err := rand.Read(body)
if err != nil { if err != nil {
t.Fatalf("Unable to create request body: %v", err) t.Fatalf("Unable to create request body: %v", err)
@@ -59,7 +57,7 @@ func TestH3H1RequestBody(t *testing.T) {
buflen += n buflen += n
if err != nil { if err != nil {
if errors.Is(err, io.EOF) { if err == io.EOF {
break break
} }
@@ -75,7 +73,6 @@ func TestH3H1RequestBody(t *testing.T) {
}, },
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -86,7 +83,6 @@ func TestH3H1RequestBody(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http3() = %v", err) t.Fatalf("Error st.http3() = %v", err)
} }
if got, want := res.status, http.StatusOK; got != want { if got, want := res.status, http.StatusOK; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
@@ -103,7 +99,6 @@ func TestH3H1GenerateVia(t *testing.T) {
}, },
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -113,7 +108,6 @@ func TestH3H1GenerateVia(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http3() = %v", err) t.Fatalf("Error st.http3() = %v", err)
} }
if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want { if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want) t.Errorf("Via: %v; want %v", got, want)
} }
@@ -131,7 +125,6 @@ func TestH3H1AppendVia(t *testing.T) {
}, },
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -144,7 +137,6 @@ func TestH3H1AppendVia(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http3() = %v", err) t.Fatalf("Error st.http3() = %v", err)
} }
if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want { if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want) t.Errorf("Via: %v; want %v", got, want)
} }
@@ -163,7 +155,6 @@ func TestH3H1NoVia(t *testing.T) {
}, },
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -176,7 +167,6 @@ func TestH3H1NoVia(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http3() = %v", err) t.Fatalf("Error st.http3() = %v", err)
} }
if got, want := res.header.Get("Via"), "bar"; got != want { if got, want := res.header.Get("Via"), "bar"; got != want {
t.Errorf("Via: %v; want %v", got, want) t.Errorf("Via: %v; want %v", got, want)
} }
@@ -196,7 +186,6 @@ func TestH3H1BadResponseCL(t *testing.T) {
}, },
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -215,7 +204,6 @@ func TestH3H1HTTPSRedirect(t *testing.T) {
args: []string{"--redirect-if-not-tls"}, args: []string{"--redirect-if-not-tls"},
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -238,7 +226,6 @@ func TestH3H1AffinityCookieTLS(t *testing.T) {
args: []string{"--affinity-cookie"}, args: []string{"--affinity-cookie"},
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -256,7 +243,6 @@ func TestH3H1AffinityCookieTLS(t *testing.T) {
const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure` const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure`
validCookie := regexp.MustCompile(pattern) validCookie := regexp.MustCompile(pattern)
if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) { if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern) t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
} }
@@ -275,7 +261,6 @@ func TestH3H2ReqPhaseReturn(t *testing.T) {
}, },
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -317,7 +302,6 @@ func TestH3H2RespPhaseReturn(t *testing.T) {
}, },
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -359,7 +343,6 @@ func TestH3ResponseBeforeRequestEnd(t *testing.T) {
}, },
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()
@@ -370,7 +353,6 @@ func TestH3ResponseBeforeRequestEnd(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Error st.http3() = %v", err) t.Fatalf("Error st.http3() = %v", err)
} }
if got, want := res.status, http.StatusNotFound; got != want { if got, want := res.status, http.StatusNotFound; got != want {
t.Errorf("res.status: %v; want %v", got, want) t.Errorf("res.status: %v; want %v", got, want)
} }
@@ -399,7 +381,6 @@ func TestH3H1ChunkedEndsPrematurely(t *testing.T) {
}, },
quic: true, quic: true,
} }
st := newServerTester(t, opts) st := newServerTester(t, opts)
defer st.Close() defer st.Close()

View File

@@ -3,7 +3,6 @@ package nghttp2
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"cmp"
"context" "context"
"crypto/tls" "crypto/tls"
"encoding/binary" "encoding/binary"
@@ -16,7 +15,7 @@ import (
"net/url" "net/url"
"os" "os"
"os/exec" "os/exec"
"slices" "sort"
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
@@ -95,17 +94,14 @@ func newServerTester(t *testing.T, opts options) *serverTester {
if opts.handler == nil { if opts.handler == nil {
opts.handler = noopHandler opts.handler = noopHandler
} }
if opts.connectPort == 0 { if opts.connectPort == 0 {
opts.connectPort = serverPort opts.connectPort = serverPort
} }
ts := httptest.NewUnstartedServer(opts.handler) ts := httptest.NewUnstartedServer(opts.handler)
var ( var args []string
args []string var backendTLS, dns, externalDNS, acceptProxyProtocol, redirectIfNotTLS, affinityCookie, alpnH1 bool
backendTLS, dns, externalDNS, acceptProxyProtocol, redirectIfNotTLS, affinityCookie, alpnH1 bool
)
for _, k := range opts.args { for _, k := range opts.args {
switch k { switch k {
@@ -128,7 +124,6 @@ func newServerTester(t *testing.T, opts options) *serverTester {
args = append(args, k) args = append(args, k)
} }
} }
if backendTLS { if backendTLS {
nghttp2.ConfigureServer(ts.Config, &nghttp2.Server{}) nghttp2.ConfigureServer(ts.Config, &nghttp2.Server{})
// According to httptest/server.go, we have to set // According to httptest/server.go, we have to set
@@ -137,17 +132,13 @@ func newServerTester(t *testing.T, opts options) *serverTester {
ts.TLS = new(tls.Config) ts.TLS = new(tls.Config)
ts.TLS.NextProtos = append(ts.TLS.NextProtos, "h2") ts.TLS.NextProtos = append(ts.TLS.NextProtos, "h2")
ts.StartTLS() ts.StartTLS()
args = append(args, "-k") args = append(args, "-k")
} else { } else {
ts.Start() ts.Start()
} }
scheme := "http" scheme := "http"
if opts.tls { if opts.tls {
scheme = "https" scheme = "https"
args = append(args, testDir+"/server.key", testDir+"/server.crt") args = append(args, testDir+"/server.key", testDir+"/server.crt")
} }
@@ -159,25 +150,20 @@ func newServerTester(t *testing.T, opts options) *serverTester {
// URL.Host looks like "127.0.0.1:8080", but we want // URL.Host looks like "127.0.0.1:8080", but we want
// "127.0.0.1,8080" // "127.0.0.1,8080"
b := "-b" b := "-b"
if !externalDNS { if !externalDNS {
b += fmt.Sprintf("%v;", strings.ReplaceAll(backendURL.Host, ":", ",")) b += fmt.Sprintf("%v;", strings.Replace(backendURL.Host, ":", ",", -1))
} else { } else {
sep := strings.LastIndex(backendURL.Host, ":") sep := strings.LastIndex(backendURL.Host, ":")
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 nip.io. // We use awesome service nip.io.
b += fmt.Sprintf("%v.nip.io,%v;", backendURL.Host[:sep], backendURL.Host[sep+1:]) b += fmt.Sprintf("%v.nip.io,%v;", backendURL.Host[:sep], backendURL.Host[sep+1:])
// Make external DNS tests less flaky.
args = append(args, "--backend-address-family=IPv4")
} }
if backendTLS { if backendTLS {
b += ";proto=h2;tls" b += ";proto=h2;tls"
} }
if dns { if dns {
b += ";dns" b += ";dns"
} }
@@ -191,13 +177,11 @@ func newServerTester(t *testing.T, opts options) *serverTester {
} }
noTLS := ";no-tls" noTLS := ";no-tls"
if opts.tls { if opts.tls {
noTLS = "" noTLS = ""
} }
var proxyProto string var proxyProto string
if acceptProxyProtocol { if acceptProxyProtocol {
proxyProto = ";proxyproto" proxyProto = ";proxyproto"
} }
@@ -208,19 +192,7 @@ func newServerTester(t *testing.T, opts options) *serverTester {
if opts.quic { if opts.quic {
args = append(args, args = append(args,
fmt.Sprintf("-f127.0.0.1,%v;quic", serverPort), fmt.Sprintf("-f127.0.0.1,%v;quic", serverPort),
"--no-quic-bpf", "--no-quic-bpf")
// quic-go client just closes connection after
// receiving the first GOAWAY without any
// indication like sending CONNECTION_CLOSE if
// there is no active stream. If that
// happens, server keeps resending 2nd GOAWAY
// until idle timeout passes. If that happens
// during Close(), the process will be killed
// because the default idle timeout is longer
// than the close timeout. Shorten the idle
// timeout to prevent it from happening.
"--frontend-quic-idle-timeout=5",
)
} }
authority := fmt.Sprintf("127.0.0.1:%v", opts.connectPort) authority := fmt.Sprintf("127.0.0.1:%v", opts.connectPort)
@@ -246,7 +218,6 @@ func newServerTester(t *testing.T, opts options) *serverTester {
} }
retry := 0 retry := 0
for { for {
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
@@ -260,41 +231,32 @@ func newServerTester(t *testing.T, opts options) *serverTester {
} }
var tlsConfig *tls.Config var tlsConfig *tls.Config
if opts.tlsConfig == nil { if opts.tlsConfig == nil {
tlsConfig = new(tls.Config) tlsConfig = new(tls.Config)
} else { } else {
tlsConfig = opts.tlsConfig.Clone() tlsConfig = opts.tlsConfig.Clone()
} }
tlsConfig.InsecureSkipVerify = true tlsConfig.InsecureSkipVerify = true
if alpnH1 { if alpnH1 {
tlsConfig.NextProtos = []string{"http/1.1"} tlsConfig.NextProtos = []string{"http/1.1"}
} else { } else {
tlsConfig.NextProtos = []string{"h2"} tlsConfig.NextProtos = []string{"h2"}
} }
tlsConn := tls.Client(conn, tlsConfig) tlsConn := tls.Client(conn, tlsConfig)
err = tlsConn.Handshake() err = tlsConn.Handshake()
if err == nil { if err == nil {
conn = tlsConn conn = tlsConn
} }
} }
if err != nil { if err != nil {
retry++ retry++
if retry >= 100 { if retry >= 100 {
st.Close() st.Close()
st.t.Fatalf("Error server is not responding too long; server command-line arguments may be invalid") st.t.Fatalf("Error server is not responding too long; server command-line arguments may be invalid")
} }
continue continue
} }
st.conn = conn st.conn = conn
break break
} }
@@ -311,15 +273,12 @@ func (st *serverTester) Close() {
if st.conn != nil { if st.conn != nil {
st.conn.Close() st.conn.Close()
} }
if st.cmd != nil { if st.cmd != nil {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
if err := st.cmd.Wait(); err != nil { if err := st.cmd.Wait(); err != nil {
st.t.Errorf("Error st.cmd.Wait() = %v", err) st.t.Errorf("Error st.cmd.Wait() = %v", err)
} }
close(done) close(done)
}() }()
@@ -333,11 +292,9 @@ func (st *serverTester) Close() {
if err := st.cmd.Process.Kill(); err != nil { if err := st.cmd.Process.Kill(); err != nil {
st.t.Errorf("Error st.cmd.Process.Kill() = %v", err) st.t.Errorf("Error st.cmd.Process.Kill() = %v", err)
} }
<-done <-done
} }
} }
if st.ts != nil { if st.ts != nil {
st.ts.Close() st.ts.Close()
} }
@@ -350,7 +307,6 @@ func (st *serverTester) readFrame() (http2.Frame, error) {
st.errCh <- err st.errCh <- err
return return
} }
st.frCh <- f st.frCh <- f
}() }()
@@ -391,12 +347,10 @@ func (cbr *chunkedBodyReader) Read(p []byte) (n int, err error) {
// after request was sent and before body returns EOF. // after request was sent and before body returns EOF.
if !cbr.trailerWritten { if !cbr.trailerWritten {
cbr.trailerWritten = true cbr.trailerWritten = true
for _, h := range cbr.trailer { for _, h := range cbr.trailer {
cbr.req.Trailer.Set(h.Name, h.Value) cbr.req.Trailer.Set(h.Name, h.Value)
} }
} }
return cbr.body.Read(p) return cbr.body.Read(p)
} }
@@ -409,7 +363,6 @@ func (st *serverTester) websocket(rp requestParam) *serverResponse {
} }
config.Header.Add("Test-Case", rp.name) config.Header.Add("Test-Case", rp.name)
for _, h := range rp.header { for _, h := range rp.header {
config.Header.Add(h.Name, h.Value) config.Header.Add(h.Name, h.Value)
} }
@@ -424,9 +377,7 @@ func (st *serverTester) websocket(rp requestParam) *serverResponse {
} }
msg := make([]byte, 1024) msg := make([]byte, 1024)
var n int var n int
if n, err = ws.Read(msg); err != nil { if n, err = ws.Read(msg); err != nil {
st.t.Fatalf("ws.Read() returned error: %v", err) st.t.Fatalf("ws.Read() returned error: %v", err)
} }
@@ -440,25 +391,19 @@ func (st *serverTester) websocket(rp requestParam) *serverResponse {
func (st *serverTester) http1(rp requestParam) (*serverResponse, error) { func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
method := "GET" method := "GET"
if rp.method != "" { if rp.method != "" {
method = rp.method method = rp.method
} }
var ( var body io.Reader
body io.Reader var cbr *chunkedBodyReader
cbr *chunkedBodyReader
)
if rp.body != nil { if rp.body != nil {
body = bytes.NewBuffer(rp.body) body = bytes.NewBuffer(rp.body)
if len(rp.trailer) != 0 { if len(rp.trailer) != 0 {
cbr = &chunkedBodyReader{ cbr = &chunkedBodyReader{
trailer: rp.trailer, trailer: rp.trailer,
body: body, body: body,
} }
body = cbr body = cbr
} }
} }
@@ -470,7 +415,6 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
if err != nil { if err != nil {
st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err) st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err)
} }
u.Path = "" u.Path = ""
u.RawQuery = "" u.RawQuery = ""
reqURL = u.String() + rp.path reqURL = u.String() + rp.path
@@ -483,38 +427,30 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, h := range rp.header { for _, h := range rp.header {
req.Header.Add(h.Name, h.Value) req.Header.Add(h.Name, h.Value)
} }
req.Header.Add("Test-Case", rp.name) req.Header.Add("Test-Case", rp.name)
if cbr != nil { if cbr != nil {
cbr.req = req cbr.req = req
// this makes request use chunked encoding // this makes request use chunked encoding
req.ContentLength = -1 req.ContentLength = -1
req.Trailer = make(http.Header) req.Trailer = make(http.Header)
for _, h := range cbr.trailer { for _, h := range cbr.trailer {
req.Trailer.Set(h.Name, "") req.Trailer.Set(h.Name, "")
} }
} }
if err := req.Write(st.conn); err != nil { if err := req.Write(st.conn); err != nil {
return nil, err return nil, err
} }
resp, err := http.ReadResponse(bufio.NewReader(st.conn), req) resp, err := http.ReadResponse(bufio.NewReader(st.conn), req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
respBody, err := io.ReadAll(resp.Body) respBody, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp.Body.Close() resp.Body.Close()
res := &serverResponse{ res := &serverResponse{
@@ -532,7 +468,6 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
st.header = make(http.Header) st.header = make(http.Header)
var id uint32 var id uint32
if rp.streamID != 0 { if rp.streamID != 0 {
id = rp.streamID id = rp.streamID
if id >= st.nextStreamID && id%2 == 1 { if id >= st.nextStreamID && id%2 == 1 {
@@ -546,7 +481,6 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
if !st.h2PrefaceSent { if !st.h2PrefaceSent {
st.h2PrefaceSent = true st.h2PrefaceSent = true
fmt.Fprint(st.conn, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") fmt.Fprint(st.conn, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
if err := st.fr.WriteSettings(); err != nil { if err := st.fr.WriteSettings(); err != nil {
return nil, err return nil, err
} }
@@ -564,32 +498,26 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
if rp.method != "" { if rp.method != "" {
method = rp.method method = rp.method
} }
_ = st.enc.WriteField(pair(":method", method)) _ = st.enc.WriteField(pair(":method", method))
scheme := "http" scheme := "http"
if rp.scheme != "" { if rp.scheme != "" {
scheme = rp.scheme scheme = rp.scheme
} }
_ = st.enc.WriteField(pair(":scheme", scheme)) _ = st.enc.WriteField(pair(":scheme", scheme))
authority := st.authority authority := st.authority
if rp.authority != "" { if rp.authority != "" {
authority = rp.authority authority = rp.authority
} }
_ = st.enc.WriteField(pair(":authority", authority)) _ = st.enc.WriteField(pair(":authority", authority))
path := "/" path := "/"
if rp.path != "" { if rp.path != "" {
path = rp.path path = rp.path
} }
_ = st.enc.WriteField(pair(":path", path)) _ = st.enc.WriteField(pair(":path", path))
_ = st.enc.WriteField(pair("test-case", rp.name)) _ = st.enc.WriteField(pair("test-case", rp.name))
for _, h := range rp.header { for _, h := range rp.header {
@@ -615,11 +543,9 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
if len(rp.trailer) != 0 { if len(rp.trailer) != 0 {
st.headerBlkBuf.Reset() st.headerBlkBuf.Reset()
for _, h := range rp.trailer { for _, h := range rp.trailer {
_ = st.enc.WriteField(h) _ = st.enc.WriteField(h)
} }
err := st.fr.WriteHeaders(http2.HeadersFrameParam{ err := st.fr.WriteHeaders(http2.HeadersFrameParam{
StreamID: id, StreamID: id,
EndStream: true, EndStream: true,
@@ -637,65 +563,56 @@ loop:
if err != nil { if err != nil {
return res, err return res, err
} }
switch f := fr.(type) { switch f := fr.(type) {
case *http2.HeadersFrame: case *http2.HeadersFrame:
_, err := st.dec.Write(f.HeaderBlockFragment()) _, err := st.dec.Write(f.HeaderBlockFragment())
if err != nil { if err != nil {
return res, err return res, err
} }
sr, ok := streams[f.FrameHeader.StreamID]
sr, ok := streams[f.StreamID]
if !ok { if !ok {
st.header = make(http.Header) st.header = make(http.Header)
break break
} }
sr.header = cloneHeader(st.header) sr.header = cloneHeader(st.header)
var status int var status int
status, err = strconv.Atoi(sr.header.Get(":status")) status, err = strconv.Atoi(sr.header.Get(":status"))
if err != nil { if err != nil {
return res, fmt.Errorf("could not parse :status: %w", err) return res, fmt.Errorf("Error parsing status code: %w", err)
} }
sr.status = status sr.status = status
if f.StreamEnded() {
if f.StreamEnded() && streamEnded(res, streams, sr) { if streamEnded(res, streams, sr) {
break loop break loop
}
} }
case *http2.PushPromiseFrame: case *http2.PushPromiseFrame:
_, err := st.dec.Write(f.HeaderBlockFragment()) _, err := st.dec.Write(f.HeaderBlockFragment())
if err != nil { if err != nil {
return res, err return res, err
} }
sr := &serverResponse{ sr := &serverResponse{
streamID: f.PromiseID, streamID: f.PromiseID,
reqHeader: cloneHeader(st.header), reqHeader: cloneHeader(st.header),
} }
streams[sr.streamID] = sr streams[sr.streamID] = sr
case *http2.DataFrame: case *http2.DataFrame:
sr, ok := streams[f.StreamID] sr, ok := streams[f.FrameHeader.StreamID]
if !ok { if !ok {
break break
} }
sr.body = append(sr.body, f.Data()...) sr.body = append(sr.body, f.Data()...)
if f.StreamEnded() {
if f.StreamEnded() && streamEnded(res, streams, sr) { if streamEnded(res, streams, sr) {
break loop break loop
}
} }
case *http2.RSTStreamFrame: case *http2.RSTStreamFrame:
sr, ok := streams[f.StreamID] sr, ok := streams[f.FrameHeader.StreamID]
if !ok { if !ok {
break break
} }
sr.errCode = f.ErrCode sr.errCode = f.ErrCode
if streamEnded(res, streams, sr) { if streamEnded(res, streams, sr) {
break loop break loop
} }
@@ -703,36 +620,27 @@ loop:
if f.ErrCode == http2.ErrCodeNo { if f.ErrCode == http2.ErrCodeNo {
break break
} }
res.errCode = f.ErrCode res.errCode = f.ErrCode
res.connErr = true res.connErr = true
break loop break loop
case *http2.SettingsFrame: case *http2.SettingsFrame:
if f.IsAck() { if f.IsAck() {
break break
} }
if err := st.fr.WriteSettingsAck(); err != nil { if err := st.fr.WriteSettingsAck(); err != nil {
return res, err return res, err
} }
} }
} }
sort.Sort(ByStreamID(res.pushResponse))
slices.SortFunc(res.pushResponse, func(a, b *serverResponse) int {
return cmp.Compare(a.streamID, b.streamID)
})
return res, nil return res, nil
} }
func streamEnded(mainSr *serverResponse, streams map[uint32]*serverResponse, sr *serverResponse) bool { func streamEnded(mainSr *serverResponse, streams map[uint32]*serverResponse, sr *serverResponse) bool {
delete(streams, sr.streamID) delete(streams, sr.streamID)
if mainSr.streamID != sr.streamID { if mainSr.streamID != sr.streamID {
mainSr.pushResponse = append(mainSr.pushResponse, sr) mainSr.pushResponse = append(mainSr.pushResponse, sr)
} }
return len(streams) == 0 return len(streams) == 0
} }
@@ -748,15 +656,27 @@ type serverResponse struct {
pushResponse []*serverResponse // pushed response pushResponse []*serverResponse // pushed response
} }
type ByStreamID []*serverResponse
func (b ByStreamID) Len() int {
return len(b)
}
func (b ByStreamID) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
func (b ByStreamID) Less(i, j int) bool {
return b[i].streamID < b[j].streamID
}
func cloneHeader(h http.Header) http.Header { func cloneHeader(h http.Header) http.Header {
h2 := make(http.Header, len(h)) h2 := make(http.Header, len(h))
for k, vv := range h { for k, vv := range h {
vv2 := make([]string, len(vv)) vv2 := make([]string, len(vv))
copy(vv2, vv) copy(vv2, vv)
h2[k] = vv2 h2[k] = vv2
} }
return h2 return h2
} }
@@ -807,7 +727,6 @@ func writeProxyProtocolV2(w io.Writer, hdr proxyProtocolV2) error {
if _, err := w.Write([]byte{0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A}); err != nil { if _, err := w.Write([]byte{0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A}); err != nil {
return err return err
} }
if _, err := w.Write([]byte{byte(0x20 | hdr.command)}); err != nil { if _, err := w.Write([]byte{byte(0x20 | hdr.command)}); err != nil {
return err return err
} }
@@ -815,59 +734,44 @@ func writeProxyProtocolV2(w io.Writer, hdr proxyProtocolV2) error {
switch srcAddr := hdr.sourceAddress.(type) { switch srcAddr := hdr.sourceAddress.(type) {
case *net.TCPAddr: case *net.TCPAddr:
dstAddr := hdr.destinationAddress.(*net.TCPAddr) dstAddr := hdr.destinationAddress.(*net.TCPAddr)
if len(srcAddr.IP) != len(dstAddr.IP) { if len(srcAddr.IP) != len(dstAddr.IP) {
panic("len(srcAddr.IP) != len(dstAddr.IP)") panic("len(srcAddr.IP) != len(dstAddr.IP)")
} }
var fam byte var fam byte
if len(srcAddr.IP) == 4 { if len(srcAddr.IP) == 4 {
fam = byte(proxyProtocolV2FamilyInet << 4) fam = byte(proxyProtocolV2FamilyInet << 4)
} else { } else {
fam = byte(proxyProtocolV2FamilyInet6 << 4) fam = byte(proxyProtocolV2FamilyInet6 << 4)
} }
fam |= byte(proxyProtocolV2ProtocolStream) fam |= byte(proxyProtocolV2ProtocolStream)
if _, err := w.Write([]byte{fam}); err != nil { if _, err := w.Write([]byte{fam}); err != nil {
return err return err
} }
length := uint16(len(srcAddr.IP)*2 + 4 + len(hdr.additionalData)) length := uint16(len(srcAddr.IP)*2 + 4 + len(hdr.additionalData))
if err := binary.Write(w, binary.BigEndian, length); err != nil { if err := binary.Write(w, binary.BigEndian, length); err != nil {
return err return err
} }
if _, err := w.Write(srcAddr.IP); err != nil { if _, err := w.Write(srcAddr.IP); err != nil {
return err return err
} }
if _, err := w.Write(dstAddr.IP); err != nil { if _, err := w.Write(dstAddr.IP); err != nil {
return err return err
} }
if err := binary.Write(w, binary.BigEndian, uint16(srcAddr.Port)); err != nil { if err := binary.Write(w, binary.BigEndian, uint16(srcAddr.Port)); err != nil {
return err return err
} }
if err := binary.Write(w, binary.BigEndian, uint16(dstAddr.Port)); err != nil { if err := binary.Write(w, binary.BigEndian, uint16(dstAddr.Port)); err != nil {
return err return err
} }
case *net.UnixAddr: case *net.UnixAddr:
dstAddr := hdr.destinationAddress.(*net.UnixAddr) dstAddr := hdr.destinationAddress.(*net.UnixAddr)
if len(srcAddr.Name) > 108 { if len(srcAddr.Name) > 108 {
panic("too long Unix source address") panic("too long Unix source address")
} }
if len(dstAddr.Name) > 108 { if len(dstAddr.Name) > 108 {
panic("too long Unix destination address") panic("too long Unix destination address")
} }
fam := byte(proxyProtocolV2FamilyUnix << 4) fam := byte(proxyProtocolV2FamilyUnix << 4)
switch srcAddr.Net { switch srcAddr.Net {
case "unix": case "unix":
fam |= byte(proxyProtocolV2ProtocolStream) fam |= byte(proxyProtocolV2ProtocolStream)
@@ -876,43 +780,32 @@ func writeProxyProtocolV2(w io.Writer, hdr proxyProtocolV2) error {
default: default:
fam |= byte(proxyProtocolV2ProtocolUnspec) fam |= byte(proxyProtocolV2ProtocolUnspec)
} }
if _, err := w.Write([]byte{fam}); err != nil { if _, err := w.Write([]byte{fam}); err != nil {
return err return err
} }
length := uint16(216 + len(hdr.additionalData)) length := uint16(216 + len(hdr.additionalData))
if err := binary.Write(w, binary.BigEndian, length); err != nil { if err := binary.Write(w, binary.BigEndian, length); err != nil {
return err return err
} }
zeros := make([]byte, 108) zeros := make([]byte, 108)
if _, err := w.Write([]byte(srcAddr.Name)); err != nil { if _, err := w.Write([]byte(srcAddr.Name)); err != nil {
return err return err
} }
if _, err := w.Write(zeros[:108-len(srcAddr.Name)]); err != nil { if _, err := w.Write(zeros[:108-len(srcAddr.Name)]); err != nil {
return err return err
} }
if _, err := w.Write([]byte(dstAddr.Name)); err != nil { if _, err := w.Write([]byte(dstAddr.Name)); err != nil {
return err return err
} }
if _, err := w.Write(zeros[:108-len(dstAddr.Name)]); err != nil { if _, err := w.Write(zeros[:108-len(dstAddr.Name)]); err != nil {
return err return err
} }
default: default:
fam := byte(proxyProtocolV2FamilyUnspec<<4) | byte(proxyProtocolV2ProtocolUnspec) fam := byte(proxyProtocolV2FamilyUnspec<<4) | byte(proxyProtocolV2ProtocolUnspec)
if _, err := w.Write([]byte{fam}); err != nil { if _, err := w.Write([]byte{fam}); err != nil {
return err return err
} }
length := uint16(len(hdr.additionalData)) length := uint16(len(hdr.additionalData))
if err := binary.Write(w, binary.BigEndian, length); err != nil { if err := binary.Write(w, binary.BigEndian, length); err != nil {
return err return err
} }

View File

@@ -15,7 +15,7 @@ import (
) )
func (st *serverTester) http3(rp requestParam) (*serverResponse, error) { func (st *serverTester) http3(rp requestParam) (*serverResponse, error) {
rt := &http3.Transport{ rt := &http3.RoundTripper{
TLSClientConfig: &tls.Config{ TLSClientConfig: &tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
}, },
@@ -45,7 +45,6 @@ func (st *serverTester) http3(rp requestParam) (*serverResponse, error) {
if err != nil { if err != nil {
st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err) st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err)
} }
u.Path = "" u.Path = ""
u.RawQuery = "" u.RawQuery = ""
reqURL = u.String() + rp.path reqURL = u.String() + rp.path

View File

@@ -47,29 +47,7 @@ if(WIN32)
set(NGHTTP2_RES ${CMAKE_CURRENT_BINARY_DIR}/version.rc) set(NGHTTP2_RES ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif() endif()
set(NGHTTP2_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") set(EXPORT_SET "${PROJECT_NAME}-targets")
set(NGHTTP2_VERSION_CONFIG "${NGHTTP2_GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
set(NGHTTP2_PROJECT_CONFIG "${NGHTTP2_GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
set(NGHTTP2_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(NGHTTP2_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
set(NGHTTP2_NAMESPACE "${PROJECT_NAME}::")
set(NGHTTP2_VERSION ${PROJECT_VERSION})
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${NGHTTP2_VERSION_CONFIG}" VERSION ${NGHTTP2_VERSION} COMPATIBILITY SameMajorVersion
)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.cmake.in" "${NGHTTP2_PROJECT_CONFIG}" @ONLY)
# Install cmake config files
install(
FILES "${NGHTTP2_PROJECT_CONFIG}" "${NGHTTP2_VERSION_CONFIG}"
DESTINATION "${NGHTTP2_CONFIG_INSTALL_DIR}")
install(
EXPORT "${NGHTTP2_TARGETS_EXPORT_NAME}"
NAMESPACE "${NGHTTP2_NAMESPACE}"
DESTINATION "${NGHTTP2_CONFIG_INSTALL_DIR}")
# Public shared library # Public shared library
if(BUILD_SHARED_LIBS) if(BUILD_SHARED_LIBS)
@@ -87,11 +65,7 @@ if(BUILD_SHARED_LIBS)
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
) )
install(TARGETS ${SHARED_LIB} install(TARGETS ${SHARED_LIB} EXPORT ${EXPORT_SET})
EXPORT ${NGHTTP2_TARGETS_EXPORT_NAME}
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
list(APPEND nghttp2_exports ${SHARED_LIB}) list(APPEND nghttp2_exports ${SHARED_LIB})
endif() endif()
@@ -113,9 +87,7 @@ if(BUILD_STATIC_LIBS)
target_compile_definitions(${STATIC_LIB} PUBLIC "-DNGHTTP2_STATICLIB") target_compile_definitions(${STATIC_LIB} PUBLIC "-DNGHTTP2_STATICLIB")
install(TARGETS ${STATIC_LIB} install(TARGETS ${STATIC_LIB} EXPORT ${EXPORT_SET})
EXPORT ${NGHTTP2_TARGETS_EXPORT_NAME}
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
list(APPEND nghttp2_exports ${STATIC_LIB}) list(APPEND nghttp2_exports ${STATIC_LIB})
endif() endif()
@@ -125,7 +97,11 @@ else()
set(LIB_SELECTED ${STATIC_LIB}) set(LIB_SELECTED ${STATIC_LIB})
endif() endif()
add_library(nghttp2 ALIAS ${LIB_SELECTED}) add_library(${PROJECT_NAME}::nghttp2 ALIAS ${LIB_SELECTED})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnghttp2.pc" install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnghttp2.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
install(EXPORT ${EXPORT_SET}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
NAMESPACE ${PROJECT_NAME}::)

View File

@@ -22,7 +22,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = includes SUBDIRS = includes
EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in config.cmake.in EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in
AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG) AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG)
AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \ AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \

View File

@@ -1,3 +0,0 @@
include(CMakeFindDependencyMacro)
include("${CMAKE_CURRENT_LIST_DIR}/@NGHTTP2_TARGETS_EXPORT_NAME@.cmake")

File diff suppressed because it is too large Load Diff

View File

@@ -41,168 +41,163 @@ void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks) {
} }
void nghttp2_session_callbacks_set_send_callback( void nghttp2_session_callbacks_set_send_callback(
nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback) { nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback) {
cbs->send_callback = send_callback; cbs->send_callback = send_callback;
} }
void nghttp2_session_callbacks_set_send_callback2( void nghttp2_session_callbacks_set_send_callback2(
nghttp2_session_callbacks *cbs, nghttp2_send_callback2 send_callback) { nghttp2_session_callbacks *cbs, nghttp2_send_callback2 send_callback) {
cbs->send_callback2 = send_callback; cbs->send_callback2 = send_callback;
} }
void nghttp2_session_callbacks_set_recv_callback( void nghttp2_session_callbacks_set_recv_callback(
nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback) { nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback) {
cbs->recv_callback = recv_callback; cbs->recv_callback = recv_callback;
} }
void nghttp2_session_callbacks_set_recv_callback2( void nghttp2_session_callbacks_set_recv_callback2(
nghttp2_session_callbacks *cbs, nghttp2_recv_callback2 recv_callback) { nghttp2_session_callbacks *cbs, nghttp2_recv_callback2 recv_callback) {
cbs->recv_callback2 = recv_callback; cbs->recv_callback2 = recv_callback;
} }
void nghttp2_session_callbacks_set_on_frame_recv_callback( void nghttp2_session_callbacks_set_on_frame_recv_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_frame_recv_callback on_frame_recv_callback) { nghttp2_on_frame_recv_callback on_frame_recv_callback) {
cbs->on_frame_recv_callback = on_frame_recv_callback; cbs->on_frame_recv_callback = on_frame_recv_callback;
} }
void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback( void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback) { nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback) {
cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback; cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
} }
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback( void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback) { nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback) {
cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback; cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
} }
void nghttp2_session_callbacks_set_before_frame_send_callback( void nghttp2_session_callbacks_set_before_frame_send_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_before_frame_send_callback before_frame_send_callback) { nghttp2_before_frame_send_callback before_frame_send_callback) {
cbs->before_frame_send_callback = before_frame_send_callback; cbs->before_frame_send_callback = before_frame_send_callback;
} }
void nghttp2_session_callbacks_set_on_frame_send_callback( void nghttp2_session_callbacks_set_on_frame_send_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_frame_send_callback on_frame_send_callback) { nghttp2_on_frame_send_callback on_frame_send_callback) {
cbs->on_frame_send_callback = on_frame_send_callback; cbs->on_frame_send_callback = on_frame_send_callback;
} }
void nghttp2_session_callbacks_set_on_frame_not_send_callback( void nghttp2_session_callbacks_set_on_frame_not_send_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_frame_not_send_callback on_frame_not_send_callback) { nghttp2_on_frame_not_send_callback on_frame_not_send_callback) {
cbs->on_frame_not_send_callback = on_frame_not_send_callback; cbs->on_frame_not_send_callback = on_frame_not_send_callback;
} }
void nghttp2_session_callbacks_set_on_stream_close_callback( void nghttp2_session_callbacks_set_on_stream_close_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_stream_close_callback on_stream_close_callback) { nghttp2_on_stream_close_callback on_stream_close_callback) {
cbs->on_stream_close_callback = on_stream_close_callback; cbs->on_stream_close_callback = on_stream_close_callback;
} }
void nghttp2_session_callbacks_set_on_begin_headers_callback( void nghttp2_session_callbacks_set_on_begin_headers_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_begin_headers_callback on_begin_headers_callback) { nghttp2_on_begin_headers_callback on_begin_headers_callback) {
cbs->on_begin_headers_callback = on_begin_headers_callback; cbs->on_begin_headers_callback = on_begin_headers_callback;
} }
void nghttp2_session_callbacks_set_on_header_callback( void nghttp2_session_callbacks_set_on_header_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_header_callback on_header_callback) { nghttp2_on_header_callback on_header_callback) {
cbs->on_header_callback = on_header_callback; cbs->on_header_callback = on_header_callback;
} }
void nghttp2_session_callbacks_set_on_header_callback2( void nghttp2_session_callbacks_set_on_header_callback2(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_header_callback2 on_header_callback2) { nghttp2_on_header_callback2 on_header_callback2) {
cbs->on_header_callback2 = on_header_callback2; cbs->on_header_callback2 = on_header_callback2;
} }
void nghttp2_session_callbacks_set_on_invalid_header_callback( void nghttp2_session_callbacks_set_on_invalid_header_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_invalid_header_callback on_invalid_header_callback) { nghttp2_on_invalid_header_callback on_invalid_header_callback) {
cbs->on_invalid_header_callback = on_invalid_header_callback; cbs->on_invalid_header_callback = on_invalid_header_callback;
} }
void nghttp2_session_callbacks_set_on_invalid_header_callback2( void nghttp2_session_callbacks_set_on_invalid_header_callback2(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_invalid_header_callback2 on_invalid_header_callback2) { nghttp2_on_invalid_header_callback2 on_invalid_header_callback2) {
cbs->on_invalid_header_callback2 = on_invalid_header_callback2; cbs->on_invalid_header_callback2 = on_invalid_header_callback2;
} }
void nghttp2_session_callbacks_set_select_padding_callback( void nghttp2_session_callbacks_set_select_padding_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_select_padding_callback select_padding_callback) { nghttp2_select_padding_callback select_padding_callback) {
cbs->select_padding_callback = select_padding_callback; cbs->select_padding_callback = select_padding_callback;
} }
void nghttp2_session_callbacks_set_select_padding_callback2( void nghttp2_session_callbacks_set_select_padding_callback2(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_select_padding_callback2 select_padding_callback) { nghttp2_select_padding_callback2 select_padding_callback) {
cbs->select_padding_callback2 = select_padding_callback; cbs->select_padding_callback2 = select_padding_callback;
} }
void nghttp2_session_callbacks_set_data_source_read_length_callback( void nghttp2_session_callbacks_set_data_source_read_length_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_data_source_read_length_callback data_source_read_length_callback) { nghttp2_data_source_read_length_callback data_source_read_length_callback) {
cbs->read_length_callback = data_source_read_length_callback; cbs->read_length_callback = data_source_read_length_callback;
} }
void nghttp2_session_callbacks_set_data_source_read_length_callback2( void nghttp2_session_callbacks_set_data_source_read_length_callback2(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs, nghttp2_data_source_read_length_callback2
nghttp2_data_source_read_length_callback2 data_source_read_length_callback) { data_source_read_length_callback) {
cbs->read_length_callback2 = data_source_read_length_callback; cbs->read_length_callback2 = data_source_read_length_callback;
} }
void nghttp2_session_callbacks_set_on_begin_frame_callback( void nghttp2_session_callbacks_set_on_begin_frame_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_begin_frame_callback on_begin_frame_callback) { nghttp2_on_begin_frame_callback on_begin_frame_callback) {
cbs->on_begin_frame_callback = on_begin_frame_callback; cbs->on_begin_frame_callback = on_begin_frame_callback;
} }
void nghttp2_session_callbacks_set_send_data_callback( void nghttp2_session_callbacks_set_send_data_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_send_data_callback send_data_callback) { nghttp2_send_data_callback send_data_callback) {
cbs->send_data_callback = send_data_callback; cbs->send_data_callback = send_data_callback;
} }
void nghttp2_session_callbacks_set_pack_extension_callback( void nghttp2_session_callbacks_set_pack_extension_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_pack_extension_callback pack_extension_callback) { nghttp2_pack_extension_callback pack_extension_callback) {
cbs->pack_extension_callback = pack_extension_callback; cbs->pack_extension_callback = pack_extension_callback;
} }
void nghttp2_session_callbacks_set_pack_extension_callback2( void nghttp2_session_callbacks_set_pack_extension_callback2(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_pack_extension_callback2 pack_extension_callback) { nghttp2_pack_extension_callback2 pack_extension_callback) {
cbs->pack_extension_callback2 = pack_extension_callback; cbs->pack_extension_callback2 = pack_extension_callback;
} }
void nghttp2_session_callbacks_set_unpack_extension_callback( void nghttp2_session_callbacks_set_unpack_extension_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_unpack_extension_callback unpack_extension_callback) { nghttp2_unpack_extension_callback unpack_extension_callback) {
cbs->unpack_extension_callback = unpack_extension_callback; cbs->unpack_extension_callback = unpack_extension_callback;
} }
void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback( void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
nghttp2_session_callbacks *cbs, nghttp2_session_callbacks *cbs,
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) { nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) {
cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback; cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback;
} }
void nghttp2_session_callbacks_set_error_callback( 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( void nghttp2_session_callbacks_set_error_callback2(
nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2) { nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2) {
cbs->error_callback2 = error_callback2; cbs->error_callback2 = error_callback2;
} }
void nghttp2_session_callbacks_set_rand_callback(
nghttp2_session_callbacks *cbs, nghttp2_rand_callback rand_callback) {
cbs->rand_callback = rand_callback;
}

View File

@@ -151,7 +151,6 @@ struct nghttp2_session_callbacks {
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; nghttp2_error_callback2 error_callback2;
nghttp2_rand_callback rand_callback;
}; };
#endif /* NGHTTP2_CALLBACKS_H */ #endif /* NGHTTP2_CALLBACKS_H */

View File

@@ -34,7 +34,7 @@ static void nghttp2_default_debug_vfprintf_callback(const char *fmt,
} }
static nghttp2_debug_vprintf_callback static_debug_vprintf_callback = static nghttp2_debug_vprintf_callback static_debug_vprintf_callback =
nghttp2_default_debug_vfprintf_callback; nghttp2_default_debug_vfprintf_callback;
void nghttp2_debug_vprintf(const char *format, ...) { void nghttp2_debug_vprintf(const char *format, ...) {
if (static_debug_vprintf_callback) { if (static_debug_vprintf_callback) {
@@ -46,14 +46,14 @@ void nghttp2_debug_vprintf(const char *format, ...) {
} }
void nghttp2_set_debug_vprintf_callback( void nghttp2_set_debug_vprintf_callback(
nghttp2_debug_vprintf_callback debug_vprintf_callback) { nghttp2_debug_vprintf_callback debug_vprintf_callback) {
static_debug_vprintf_callback = debug_vprintf_callback; static_debug_vprintf_callback = 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) { nghttp2_debug_vprintf_callback debug_vprintf_callback) {
(void)debug_vprintf_callback; (void)debug_vprintf_callback;
} }

View File

@@ -60,6 +60,6 @@ void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri);
* nghttp2_extpri_uint8_inc extracts inc from |PRI| which is supposed to * nghttp2_extpri_uint8_inc extracts inc from |PRI| which is supposed to
* be constructed by nghttp2_extpri_to_uint8. * be constructed by nghttp2_extpri_to_uint8.
*/ */
#define nghttp2_extpri_uint8_inc(PRI) (((PRI) & NGHTTP2_EXTPRI_INC_MASK) != 0) #define nghttp2_extpri_uint8_inc(PRI) (((PRI)&NGHTTP2_EXTPRI_INC_MASK) != 0)
#endif /* NGHTTP2_EXTPRI_H */ #endif /* NGHTTP2_EXTPRI_H */

View File

@@ -492,7 +492,7 @@ int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame) {
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
buf->last += buf->last +=
nghttp2_frame_pack_settings_payload(buf->last, frame->iv, frame->niv); nghttp2_frame_pack_settings_payload(buf->last, frame->iv, frame->niv);
return 0; return 0;
} }
@@ -537,7 +537,7 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
} }
*iv_ptr = *iv_ptr =
nghttp2_mem_malloc(mem, (*niv_ptr) * sizeof(nghttp2_settings_entry)); nghttp2_mem_malloc(mem, (*niv_ptr) * sizeof(nghttp2_settings_entry));
if (*iv_ptr == NULL) { if (*iv_ptr == NULL) {
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
@@ -589,7 +589,7 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
const uint8_t *payload) { const uint8_t *payload) {
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;
frame->nvlen = 0; frame->nvlen = 0;
} }
@@ -608,7 +608,7 @@ void nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
buf->last = buf->last =
nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data)); nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data));
} }
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame, void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
@@ -709,7 +709,7 @@ void 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) {
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;
} }
void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) { void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
@@ -926,7 +926,7 @@ void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
priority_update = frame->payload; priority_update = frame->payload;
priority_update->stream_id = priority_update->stream_id =
nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
if (payloadlen > 4) { if (payloadlen > 4) {
priority_update->field_value = payload + 4; priority_update->field_value = payload + 4;

View File

@@ -36,10 +36,9 @@
#define MAKE_STATIC_ENT(N, V, T, H) \ #define MAKE_STATIC_ENT(N, V, T, H) \
{ \ { \
{NULL, NULL, (uint8_t *)(N), sizeof((N)) - 1, -1}, \ {NULL, NULL, (uint8_t *)(N), sizeof((N)) - 1, -1}, \
{NULL, NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, \ {NULL, NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, \
{(uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0}, \ {(uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0}, \
T, \ T, H \
H, \
} }
/* Generated by mkstatictbl.py */ /* Generated by mkstatictbl.py */
@@ -47,67 +46,67 @@
first enum value if same header names are repeated (e.g., first enum value if same header names are repeated (e.g.,
:status). */ :status). */
static const nghttp2_hd_static_entry static_table[] = { static const nghttp2_hd_static_entry static_table[] = {
MAKE_STATIC_ENT(":authority", "", 0, 3153725150u), MAKE_STATIC_ENT(":authority", "", 0, 3153725150u),
MAKE_STATIC_ENT(":method", "GET", 1, 695666056u), MAKE_STATIC_ENT(":method", "GET", 1, 695666056u),
MAKE_STATIC_ENT(":method", "POST", 1, 695666056u), MAKE_STATIC_ENT(":method", "POST", 1, 695666056u),
MAKE_STATIC_ENT(":path", "/", 3, 3292848686u), MAKE_STATIC_ENT(":path", "/", 3, 3292848686u),
MAKE_STATIC_ENT(":path", "/index.html", 3, 3292848686u), MAKE_STATIC_ENT(":path", "/index.html", 3, 3292848686u),
MAKE_STATIC_ENT(":scheme", "http", 5, 2510477674u), MAKE_STATIC_ENT(":scheme", "http", 5, 2510477674u),
MAKE_STATIC_ENT(":scheme", "https", 5, 2510477674u), MAKE_STATIC_ENT(":scheme", "https", 5, 2510477674u),
MAKE_STATIC_ENT(":status", "200", 7, 4000288983u), MAKE_STATIC_ENT(":status", "200", 7, 4000288983u),
MAKE_STATIC_ENT(":status", "204", 7, 4000288983u), MAKE_STATIC_ENT(":status", "204", 7, 4000288983u),
MAKE_STATIC_ENT(":status", "206", 7, 4000288983u), MAKE_STATIC_ENT(":status", "206", 7, 4000288983u),
MAKE_STATIC_ENT(":status", "304", 7, 4000288983u), MAKE_STATIC_ENT(":status", "304", 7, 4000288983u),
MAKE_STATIC_ENT(":status", "400", 7, 4000288983u), MAKE_STATIC_ENT(":status", "400", 7, 4000288983u),
MAKE_STATIC_ENT(":status", "404", 7, 4000288983u), MAKE_STATIC_ENT(":status", "404", 7, 4000288983u),
MAKE_STATIC_ENT(":status", "500", 7, 4000288983u), MAKE_STATIC_ENT(":status", "500", 7, 4000288983u),
MAKE_STATIC_ENT("accept-charset", "", 14, 3664010344u), MAKE_STATIC_ENT("accept-charset", "", 14, 3664010344u),
MAKE_STATIC_ENT("accept-encoding", "gzip, deflate", 15, 3379649177u), MAKE_STATIC_ENT("accept-encoding", "gzip, deflate", 15, 3379649177u),
MAKE_STATIC_ENT("accept-language", "", 16, 1979086614u), MAKE_STATIC_ENT("accept-language", "", 16, 1979086614u),
MAKE_STATIC_ENT("accept-ranges", "", 17, 1713753958u), MAKE_STATIC_ENT("accept-ranges", "", 17, 1713753958u),
MAKE_STATIC_ENT("accept", "", 18, 136609321u), MAKE_STATIC_ENT("accept", "", 18, 136609321u),
MAKE_STATIC_ENT("access-control-allow-origin", "", 19, 2710797292u), MAKE_STATIC_ENT("access-control-allow-origin", "", 19, 2710797292u),
MAKE_STATIC_ENT("age", "", 20, 742476188u), MAKE_STATIC_ENT("age", "", 20, 742476188u),
MAKE_STATIC_ENT("allow", "", 21, 2930878514u), MAKE_STATIC_ENT("allow", "", 21, 2930878514u),
MAKE_STATIC_ENT("authorization", "", 22, 2436257726u), MAKE_STATIC_ENT("authorization", "", 22, 2436257726u),
MAKE_STATIC_ENT("cache-control", "", 23, 1355326669u), MAKE_STATIC_ENT("cache-control", "", 23, 1355326669u),
MAKE_STATIC_ENT("content-disposition", "", 24, 3889184348u), MAKE_STATIC_ENT("content-disposition", "", 24, 3889184348u),
MAKE_STATIC_ENT("content-encoding", "", 25, 65203592u), MAKE_STATIC_ENT("content-encoding", "", 25, 65203592u),
MAKE_STATIC_ENT("content-language", "", 26, 24973587u), MAKE_STATIC_ENT("content-language", "", 26, 24973587u),
MAKE_STATIC_ENT("content-length", "", 27, 1308181789u), MAKE_STATIC_ENT("content-length", "", 27, 1308181789u),
MAKE_STATIC_ENT("content-location", "", 28, 2302364718u), MAKE_STATIC_ENT("content-location", "", 28, 2302364718u),
MAKE_STATIC_ENT("content-range", "", 29, 3555523146u), MAKE_STATIC_ENT("content-range", "", 29, 3555523146u),
MAKE_STATIC_ENT("content-type", "", 30, 4244048277u), MAKE_STATIC_ENT("content-type", "", 30, 4244048277u),
MAKE_STATIC_ENT("cookie", "", 31, 2007449791u), MAKE_STATIC_ENT("cookie", "", 31, 2007449791u),
MAKE_STATIC_ENT("date", "", 32, 3564297305u), MAKE_STATIC_ENT("date", "", 32, 3564297305u),
MAKE_STATIC_ENT("etag", "", 33, 113792960u), MAKE_STATIC_ENT("etag", "", 33, 113792960u),
MAKE_STATIC_ENT("expect", "", 34, 2530896728u), MAKE_STATIC_ENT("expect", "", 34, 2530896728u),
MAKE_STATIC_ENT("expires", "", 35, 1049544579u), MAKE_STATIC_ENT("expires", "", 35, 1049544579u),
MAKE_STATIC_ENT("from", "", 36, 2513272949u), MAKE_STATIC_ENT("from", "", 36, 2513272949u),
MAKE_STATIC_ENT("host", "", 37, 2952701295u), MAKE_STATIC_ENT("host", "", 37, 2952701295u),
MAKE_STATIC_ENT("if-match", "", 38, 3597694698u), MAKE_STATIC_ENT("if-match", "", 38, 3597694698u),
MAKE_STATIC_ENT("if-modified-since", "", 39, 2213050793u), MAKE_STATIC_ENT("if-modified-since", "", 39, 2213050793u),
MAKE_STATIC_ENT("if-none-match", "", 40, 2536202615u), MAKE_STATIC_ENT("if-none-match", "", 40, 2536202615u),
MAKE_STATIC_ENT("if-range", "", 41, 2340978238u), MAKE_STATIC_ENT("if-range", "", 41, 2340978238u),
MAKE_STATIC_ENT("if-unmodified-since", "", 42, 3794814858u), MAKE_STATIC_ENT("if-unmodified-since", "", 42, 3794814858u),
MAKE_STATIC_ENT("last-modified", "", 43, 3226950251u), MAKE_STATIC_ENT("last-modified", "", 43, 3226950251u),
MAKE_STATIC_ENT("link", "", 44, 232457833u), MAKE_STATIC_ENT("link", "", 44, 232457833u),
MAKE_STATIC_ENT("location", "", 45, 200649126u), MAKE_STATIC_ENT("location", "", 45, 200649126u),
MAKE_STATIC_ENT("max-forwards", "", 46, 1826162134u), MAKE_STATIC_ENT("max-forwards", "", 46, 1826162134u),
MAKE_STATIC_ENT("proxy-authenticate", "", 47, 2709445359u), MAKE_STATIC_ENT("proxy-authenticate", "", 47, 2709445359u),
MAKE_STATIC_ENT("proxy-authorization", "", 48, 2686392507u), MAKE_STATIC_ENT("proxy-authorization", "", 48, 2686392507u),
MAKE_STATIC_ENT("range", "", 49, 4208725202u), MAKE_STATIC_ENT("range", "", 49, 4208725202u),
MAKE_STATIC_ENT("referer", "", 50, 3969579366u), MAKE_STATIC_ENT("referer", "", 50, 3969579366u),
MAKE_STATIC_ENT("refresh", "", 51, 3572655668u), MAKE_STATIC_ENT("refresh", "", 51, 3572655668u),
MAKE_STATIC_ENT("retry-after", "", 52, 3336180598u), MAKE_STATIC_ENT("retry-after", "", 52, 3336180598u),
MAKE_STATIC_ENT("server", "", 53, 1085029842u), MAKE_STATIC_ENT("server", "", 53, 1085029842u),
MAKE_STATIC_ENT("set-cookie", "", 54, 1848371000u), MAKE_STATIC_ENT("set-cookie", "", 54, 1848371000u),
MAKE_STATIC_ENT("strict-transport-security", "", 55, 4138147361u), MAKE_STATIC_ENT("strict-transport-security", "", 55, 4138147361u),
MAKE_STATIC_ENT("transfer-encoding", "", 56, 3719590988u), MAKE_STATIC_ENT("transfer-encoding", "", 56, 3719590988u),
MAKE_STATIC_ENT("user-agent", "", 57, 606444526u), MAKE_STATIC_ENT("user-agent", "", 57, 606444526u),
MAKE_STATIC_ENT("vary", "", 58, 1085005381u), MAKE_STATIC_ENT("vary", "", 58, 1085005381u),
MAKE_STATIC_ENT("via", "", 59, 1762798611u), MAKE_STATIC_ENT("via", "", 59, 1762798611u),
MAKE_STATIC_ENT("www-authenticate", "", 60, 779865858u), MAKE_STATIC_ENT("www-authenticate", "", 60, 779865858u),
}; };
static int memeq(const void *s1, const void *s2, size_t n) { static int memeq(const void *s1, const void *s2, size_t n) {
@@ -594,19 +593,8 @@ static void hd_map_remove(nghttp2_hd_map *map, nghttp2_hd_entry *ent) {
static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize, static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize,
nghttp2_mem *mem) { nghttp2_mem *mem) {
size_t size; size_t size;
const size_t max_size = SIZE_MAX / sizeof(nghttp2_hd_entry *);
if (bufsize > max_size) {
return NGHTTP2_ERR_NOMEM;
}
for (size = 1; size < bufsize; size <<= 1) for (size = 1; size < bufsize; size <<= 1)
; ;
if (size > max_size) {
return NGHTTP2_ERR_NOMEM;
}
ringbuf->buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size); ringbuf->buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size);
if (ringbuf->buffer == NULL) { if (ringbuf->buffer == NULL) {
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
@@ -689,8 +677,8 @@ static int hd_context_init(nghttp2_hd_context *context, nghttp2_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( rv = hd_ringbuf_init(
&context->hd_table, &context->hd_table,
context->hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD, mem); context->hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD, mem);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
} }
@@ -707,7 +695,7 @@ static void hd_context_free(nghttp2_hd_context *context) {
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem) { int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem) {
return nghttp2_hd_deflate_init2( return nghttp2_hd_deflate_init2(
deflater, NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE, mem); deflater, NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE, mem);
} }
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
@@ -1089,8 +1077,8 @@ static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
int rv; int rv;
DEBUGF( DEBUGF(
"deflatehd: emit newname namelen=%zu, valuelen=%zu, indexing_mode=%d\n", "deflatehd: emit newname namelen=%zu, valuelen=%zu, indexing_mode=%d\n",
nv->namelen, nv->valuelen, indexing_mode); nv->namelen, nv->valuelen, indexing_mode);
rv = nghttp2_bufs_addb(bufs, pack_first_byte(indexing_mode)); rv = nghttp2_bufs_addb(bufs, pack_first_byte(indexing_mode));
if (rv != 0) { if (rv != 0) {
@@ -1123,11 +1111,12 @@ static int add_hd_table_incremental(nghttp2_hd_context *context,
while (context->hd_table_bufsize + room > context->hd_table_bufsize_max && while (context->hd_table_bufsize + room > context->hd_table_bufsize_max &&
context->hd_table.len > 0) { context->hd_table.len > 0) {
size_t idx = context->hd_table.len - 1; size_t idx = context->hd_table.len - 1;
nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx); nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx);
context->hd_table_bufsize -= context->hd_table_bufsize -=
entry_room(ent->nv.name->len, ent->nv.value->len); entry_room(ent->nv.name->len, ent->nv.value->len);
DEBUGF("hpack: remove item from header table: %s: %s\n", DEBUGF("hpack: remove item from header table: %s: %s\n",
(char *)ent->nv.name->base, (char *)ent->nv.value->base); (char *)ent->nv.name->base, (char *)ent->nv.value->base);
@@ -1243,7 +1232,7 @@ static void hd_context_shrink_table_size(nghttp2_hd_context *context,
size_t idx = context->hd_table.len - 1; size_t idx = context->hd_table.len - 1;
nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx); nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx);
context->hd_table_bufsize -= context->hd_table_bufsize -=
entry_room(ent->nv.name->len, ent->nv.value->len); entry_room(ent->nv.name->len, ent->nv.value->len);
hd_ringbuf_pop_back(&context->hd_table); hd_ringbuf_pop_back(&context->hd_table);
if (map) { if (map) {
hd_map_remove(map, ent); hd_map_remove(map, ent);
@@ -1255,14 +1244,14 @@ static void hd_context_shrink_table_size(nghttp2_hd_context *context,
} }
int nghttp2_hd_deflate_change_table_size( int nghttp2_hd_deflate_change_table_size(
nghttp2_hd_deflater *deflater, size_t settings_max_dynamic_table_size) { nghttp2_hd_deflater *deflater, size_t settings_max_dynamic_table_size) {
size_t next_bufsize = nghttp2_min_size( size_t next_bufsize = nghttp2_min_size(
settings_max_dynamic_table_size, deflater->deflate_hd_table_bufsize_max); settings_max_dynamic_table_size, deflater->deflate_hd_table_bufsize_max);
deflater->ctx.hd_table_bufsize_max = next_bufsize; deflater->ctx.hd_table_bufsize_max = next_bufsize;
deflater->min_hd_table_bufsize_max = deflater->min_hd_table_bufsize_max =
nghttp2_min_size(deflater->min_hd_table_bufsize_max, next_bufsize); nghttp2_min_size(deflater->min_hd_table_bufsize_max, next_bufsize);
deflater->notify_table_size_change = 1; deflater->notify_table_size_change = 1;
@@ -1271,7 +1260,7 @@ int nghttp2_hd_deflate_change_table_size(
} }
int nghttp2_hd_inflate_change_table_size( int nghttp2_hd_inflate_change_table_size(
nghttp2_hd_inflater *inflater, size_t settings_max_dynamic_table_size) { nghttp2_hd_inflater *inflater, size_t settings_max_dynamic_table_size) {
switch (inflater->state) { switch (inflater->state) {
case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE: case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE:
case NGHTTP2_HD_STATE_INFLATE_START: case NGHTTP2_HD_STATE_INFLATE_START:
@@ -1314,7 +1303,7 @@ nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) {
assert(INDEX_RANGE_VALID(context, idx)); assert(INDEX_RANGE_VALID(context, idx));
if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) { if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) {
return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH) return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH)
->nv; ->nv;
} else { } else {
const nghttp2_hd_static_entry *ent = &static_table[idx]; const nghttp2_hd_static_entry *ent = &static_table[idx];
nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name, nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name,
@@ -1330,7 +1319,7 @@ static const nghttp2_nv *nghttp2_hd_table_get2(nghttp2_hd_context *context,
if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) { if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) {
return &hd_ringbuf_get(&context->hd_table, return &hd_ringbuf_get(&context->hd_table,
idx - NGHTTP2_STATIC_TABLE_LENGTH) idx - NGHTTP2_STATIC_TABLE_LENGTH)
->cnv; ->cnv;
} }
return &static_table[idx].cnv; return &static_table[idx].cnv;
@@ -1344,7 +1333,7 @@ static int hd_deflate_decide_indexing(nghttp2_hd_deflater *deflater,
token == NGHTTP2_TOKEN_IF_NONE_MATCH || token == NGHTTP2_TOKEN_LOCATION || token == NGHTTP2_TOKEN_IF_NONE_MATCH || token == NGHTTP2_TOKEN_LOCATION ||
token == NGHTTP2_TOKEN_SET_COOKIE || token == NGHTTP2_TOKEN_SET_COOKIE ||
entry_room(nv->namelen, nv->valuelen) > entry_room(nv->namelen, nv->valuelen) >
deflater->ctx.hd_table_bufsize_max * 3 / 4) { deflater->ctx.hd_table_bufsize_max * 3 / 4) {
return NGHTTP2_HD_WITHOUT_INDEXING; return NGHTTP2_HD_WITHOUT_INDEXING;
} }
@@ -1377,11 +1366,12 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
entropy secret data (e.g., id/password). Also cookie header entropy secret data (e.g., id/password). Also cookie header
field with less than 20 bytes value is also never indexed. This field with less than 20 bytes value is also never indexed. This
is the same criteria used in Firefox codebase. */ is the same criteria used in Firefox codebase. */
indexing_mode = token == NGHTTP2_TOKEN_AUTHORIZATION || indexing_mode =
(token == NGHTTP2_TOKEN_COOKIE && nv->valuelen < 20) || token == NGHTTP2_TOKEN_AUTHORIZATION ||
(nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) (token == NGHTTP2_TOKEN_COOKIE && nv->valuelen < 20) ||
? NGHTTP2_HD_NEVER_INDEXING (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX)
: hd_deflate_decide_indexing(deflater, nv, token); ? NGHTTP2_HD_NEVER_INDEXING
: hd_deflate_decide_indexing(deflater, nv, token);
res = search_hd_table(&deflater->ctx, nv, token, indexing_mode, res = search_hd_table(&deflater->ctx, nv, token, indexing_mode,
&deflater->map, hash); &deflater->map, hash);
@@ -1389,6 +1379,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
idx = res.index; idx = res.index;
if (res.name_value_match) { if (res.name_value_match) {
DEBUGF("deflatehd: name/value match index=%td\n", idx); DEBUGF("deflatehd: name/value match index=%td\n", idx);
rv = emit_indexed_block(bufs, (size_t)idx); rv = emit_indexed_block(bufs, (size_t)idx);
@@ -1466,6 +1457,7 @@ int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
deflater->min_hd_table_bufsize_max = UINT32_MAX; deflater->min_hd_table_bufsize_max = UINT32_MAX;
if (deflater->ctx.hd_table_bufsize_max > min_hd_table_bufsize_max) { if (deflater->ctx.hd_table_bufsize_max > min_hd_table_bufsize_max) {
rv = emit_table_size(bufs, min_hd_table_bufsize_max); rv = emit_table_size(bufs, min_hd_table_bufsize_max);
if (rv != 0) { if (rv != 0) {
@@ -1969,9 +1961,9 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
case NGHTTP2_HD_STATE_READ_TABLE_SIZE: case NGHTTP2_HD_STATE_READ_TABLE_SIZE:
rfin = 0; rfin = 0;
rv = hd_inflate_read_len( rv = hd_inflate_read_len(
inflater, &rfin, in, last, 5, inflater, &rfin, in, last, 5,
nghttp2_min_size(inflater->min_hd_table_bufsize_max, nghttp2_min_size(inflater->min_hd_table_bufsize_max,
inflater->settings_hd_table_bufsize_max)); inflater->settings_hd_table_bufsize_max));
if (rv < 0) { if (rv < 0) {
goto fail; goto fail;
} }
@@ -2058,8 +2050,8 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF; inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF;
rv = rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left * 2 + 1,
nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left * 2 + 1, mem); mem);
} else { } else {
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME; inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME;
rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left + 1, mem); rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left + 1, mem);
@@ -2143,8 +2135,8 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF; inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF;
rv = rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left * 2 + 1,
nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left * 2 + 1, mem); mem);
} else { } else {
inflater->state = NGHTTP2_HD_STATE_READ_VALUE; inflater->state = NGHTTP2_HD_STATE_READ_VALUE;
@@ -2315,6 +2307,7 @@ void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater) {
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx, int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx,
nghttp2_nv *nv, int indexing_mode) { nghttp2_nv *nv, int indexing_mode) {
return emit_indname_block(bufs, idx, nv, indexing_mode); return emit_indname_block(bufs, idx, nv, indexing_mode);
} }

View File

@@ -94,7 +94,7 @@ int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
if (nbits) { if (nbits) {
rv = nghttp2_bufs_addb( rv = nghttp2_bufs_addb(
bufs, (uint8_t)((uint8_t)(code >> 56) | ((1 << (8 - nbits)) - 1))); bufs, (uint8_t)((uint8_t)(code >> 56) | ((1 << (8 - nbits)) - 1)));
if (rv != 0) { if (rv != 0) {
return rv; return rv;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -53,70 +53,70 @@ uint32_t nghttp2_get_uint32(const uint8_t *data) {
/* Generated by gendowncasetbl.py */ /* Generated by gendowncasetbl.py */
static const uint8_t DOWNCASE_TBL[] = { static const uint8_t DOWNCASE_TBL[] = {
0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */, 0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */,
4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */, 4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */,
8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */, 8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */,
12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */, 12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */,
16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */, 16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */,
20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */, 20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */,
24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */, 24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */,
28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */, 28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */,
32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */, 32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */,
36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */, 36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */,
40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */, 40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */,
44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */, 44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */,
48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */, 48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */,
52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */, 52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */, 56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */,
60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */, 60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */,
64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */, 64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */,
100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */, 100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */,
104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */, 104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */,
108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */, 108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */,
112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */, 112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */,
116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */, 116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */,
120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */, 120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */,
92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */, 92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */,
96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */, 96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */,
100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */, 100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */, 104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */, 108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */, 112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */, 116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */, 120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */,
124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */, 124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */,
128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */, 128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */,
132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */, 132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */,
136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */, 136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */,
140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */, 140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */,
144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */, 144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */,
148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */, 148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */,
152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */, 152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */,
156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */, 156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */,
160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */, 160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */,
164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */, 164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */,
168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */, 168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */,
172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */, 172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */,
176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */, 176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */,
180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */, 180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */,
184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */, 184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */,
188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */, 188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */,
192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */, 192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */,
196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */, 196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */,
200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */, 200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */,
204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */, 204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */,
208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */, 208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */,
212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */, 212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */,
216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */, 216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */,
220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */, 220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */,
224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */, 224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */,
228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */, 228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */,
232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */, 232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */,
236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */, 236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */,
240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */, 240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */,
244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */, 244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */,
248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */, 248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */,
252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */, 252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */,
}; };
void nghttp2_downcase(uint8_t *s, size_t len) { void nghttp2_downcase(uint8_t *s, size_t len) {
@@ -160,7 +160,7 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
int32_t recv_reduction_delta; int32_t recv_reduction_delta;
int32_t delta; int32_t delta;
int32_t new_recv_window_size = int32_t new_recv_window_size =
nghttp2_max_int32(0, *recv_window_size_ptr) - *delta_ptr; nghttp2_max_int32(0, *recv_window_size_ptr) - *delta_ptr;
if (new_recv_window_size >= 0) { if (new_recv_window_size >= 0) {
*recv_window_size_ptr = new_recv_window_size; *recv_window_size_ptr = new_recv_window_size;
@@ -345,70 +345,70 @@ const char *nghttp2_strerror(int error_code) {
/* Generated by gennmchartbl.py */ /* Generated by gennmchartbl.py */
static const int VALID_HD_NAME_CHARS[] = { static const int VALID_HD_NAME_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */, 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */, 0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */,
0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */, 0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */,
0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */, 0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */,
0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */,
0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */, 0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */,
0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */, 0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */,
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
}; };
int nghttp2_check_header_name(const uint8_t *name, size_t len) { int nghttp2_check_header_name(const uint8_t *name, size_t len) {
@@ -433,70 +433,70 @@ int nghttp2_check_header_name(const uint8_t *name, size_t len) {
/* Generated by genvchartbl.py */ /* Generated by genvchartbl.py */
static const int VALID_HD_VALUE_CHARS[] = { static const int VALID_HD_VALUE_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */, 0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */, 1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */, 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */, 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */, 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */, 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */, 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */, 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */, 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */, 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */, 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */, 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */, 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */, 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */, 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */, 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */, 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */, 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */, 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */, 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */, 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */, 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */, 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */, 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */, 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */, 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */, 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */, 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */, 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */, 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */, 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */, 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */, 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */, 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */, 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */, 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */ 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
}; };
int nghttp2_check_header_value(const uint8_t *value, size_t len) { int nghttp2_check_header_value(const uint8_t *value, size_t len) {
@@ -524,70 +524,70 @@ int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) {
/* Generated by genmethodchartbl.py */ /* Generated by genmethodchartbl.py */
static char VALID_METHOD_CHARS[] = { static char VALID_METHOD_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */, 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, 0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 0 /* [ */, 1 /* X */, 1 /* Y */, 1 /* Z */, 0 /* [ */,
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
}; };
int nghttp2_check_method(const uint8_t *value, size_t len) { int nghttp2_check_method(const uint8_t *value, size_t len) {
@@ -605,70 +605,70 @@ int nghttp2_check_method(const uint8_t *value, size_t len) {
/* Generated by genpathchartbl.py */ /* Generated by genpathchartbl.py */
static char VALID_PATH_CHARS[] = { static char VALID_PATH_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */, 0 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */, 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */, 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */, 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */, 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */, 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */, 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */, 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */, 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */, 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */, 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */, 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */, 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */, 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */, 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */, 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */, 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */, 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */, 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */, 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */, 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */, 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */, 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */, 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */, 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */, 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */, 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */, 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */, 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */, 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */, 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */, 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */, 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */, 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */, 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */ 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
}; };
int nghttp2_check_path(const uint8_t *value, size_t len) { int nghttp2_check_path(const uint8_t *value, size_t len) {
@@ -683,70 +683,70 @@ int nghttp2_check_path(const uint8_t *value, size_t len) {
/* Generated by genauthoritychartbl.py */ /* Generated by genauthoritychartbl.py */
static char VALID_AUTHORITY_CHARS[] = { static char VALID_AUTHORITY_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */, 0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, 1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */,
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */, 0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */,
0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
}; };
int nghttp2_check_authority(const uint8_t *value, size_t len) { int nghttp2_check_authority(const uint8_t *value, size_t len) {

View File

@@ -38,33 +38,33 @@
#define nghttp2_max_def(SUFFIX, T) \ #define nghttp2_max_def(SUFFIX, T) \
static inline T nghttp2_max_##SUFFIX(T a, T b) { return a < b ? b : a; } static inline T nghttp2_max_##SUFFIX(T a, T b) { return a < b ? b : a; }
nghttp2_max_def(int8, int8_t) nghttp2_max_def(int8, int8_t);
nghttp2_max_def(int16, int16_t) nghttp2_max_def(int16, int16_t);
nghttp2_max_def(int32, int32_t) nghttp2_max_def(int32, int32_t);
nghttp2_max_def(int64, int64_t) nghttp2_max_def(int64, int64_t);
nghttp2_max_def(uint8, uint8_t) nghttp2_max_def(uint8, uint8_t);
nghttp2_max_def(uint16, uint16_t) nghttp2_max_def(uint16, uint16_t);
nghttp2_max_def(uint32, uint32_t) nghttp2_max_def(uint32, uint32_t);
nghttp2_max_def(uint64, uint64_t) nghttp2_max_def(uint64, uint64_t);
nghttp2_max_def(size, size_t) nghttp2_max_def(size, size_t);
#define nghttp2_min_def(SUFFIX, T) \ #define nghttp2_min_def(SUFFIX, T) \
static inline T nghttp2_min_##SUFFIX(T a, T b) { return a < b ? a : b; } static inline T nghttp2_min_##SUFFIX(T a, T b) { return a < b ? a : b; }
nghttp2_min_def(int8, int8_t) nghttp2_min_def(int8, int8_t);
nghttp2_min_def(int16, int16_t) nghttp2_min_def(int16, int16_t);
nghttp2_min_def(int32, int32_t) nghttp2_min_def(int32, int32_t);
nghttp2_min_def(int64, int64_t) nghttp2_min_def(int64, int64_t);
nghttp2_min_def(uint8, uint8_t) nghttp2_min_def(uint8, uint8_t);
nghttp2_min_def(uint16, uint16_t) nghttp2_min_def(uint16, uint16_t);
nghttp2_min_def(uint32, uint32_t) nghttp2_min_def(uint32, uint32_t);
nghttp2_min_def(uint64, uint64_t) nghttp2_min_def(uint64, uint64_t);
nghttp2_min_def(size, size_t) nghttp2_min_def(size, size_t);
#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0) #define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
#define nghttp2_struct_of(ptr, type, member) \ #define nghttp2_struct_of(ptr, type, member) \
((type *)(void *)((char *)(ptr) - offsetof(type, member))) ((type *)(void *)((char *)(ptr)-offsetof(type, member)))
/* /*
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in * Copies 2 byte unsigned integer |n| in host byte order to |buf| in

View File

@@ -207,6 +207,7 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
if (!trailer && if (!trailer &&
/* Do not parse the header field in PUSH_PROMISE. */ /* Do not parse the header field in PUSH_PROMISE. */
(stream->stream_id & 1) && (stream->stream_id & 1) &&
(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
!(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) { !(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) {
nghttp2_extpri_from_uint8(&extpri, stream->http_extpri); nghttp2_extpri_from_uint8(&extpri, stream->http_extpri);
if (nghttp2_http_parse_priority(&extpri, nv->value->base, if (nghttp2_http_parse_priority(&extpri, nv->value->base,
@@ -346,84 +347,6 @@ static int lws(const uint8_t *s, size_t n) {
return 1; return 1;
} }
/* Generated by genauthoritychartbl.py, but '@' is not allowed */
static char VALID_AUTHORITY_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */,
0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */,
0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
};
static int check_authority(const uint8_t *value, size_t len) {
const uint8_t *last;
for (last = value + len; value != last; ++value) {
if (!VALID_AUTHORITY_CHARS[*value]) {
return 0;
}
}
return 1;
}
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream, int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
nghttp2_frame *frame, nghttp2_hd_nv *nv, nghttp2_frame *frame, nghttp2_hd_nv *nv,
int trailer) { int trailer) {
@@ -465,10 +388,10 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
case NGHTTP2_TOKEN__AUTHORITY: case NGHTTP2_TOKEN__AUTHORITY:
case NGHTTP2_TOKEN_HOST: case NGHTTP2_TOKEN_HOST:
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) { if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
rv = check_authority(nv->value->base, nv->value->len); rv = nghttp2_check_authority(nv->value->base, nv->value->len);
} else if ( } else if (
stream->flags & stream->flags &
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) { NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
rv = nghttp2_check_header_value(nv->value->base, nv->value->len); rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
} else { } else {
rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len); rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
@@ -512,7 +435,7 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) { if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
return http_request_on_header(stream, nv, trailer, return http_request_on_header(stream, nv, trailer,
session->server && session->server &&
session->pending_enable_connect_protocol); session->pending_enable_connect_protocol);
} }
return http_response_on_header(stream, nv, trailer); return http_response_on_header(stream, nv, trailer);
@@ -530,7 +453,7 @@ int nghttp2_http_on_request_headers(nghttp2_stream *stream,
stream->content_length = -1; stream->content_length = -1;
} else { } else {
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) != if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
NGHTTP2_HTTP_FLAG_REQ_HEADERS || NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
(stream->http_flags & (stream->http_flags &
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) { (NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
return -1; return -1;
@@ -570,7 +493,7 @@ int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
} }
stream->http_flags = stream->http_flags =
stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE; stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
if (!expect_response_body(stream)) { if (!expect_response_body(stream)) {
stream->content_length = 0; stream->content_length = 0;
@@ -659,17 +582,17 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream,
int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
size_t valuelen) { size_t valuelen) {
nghttp2_extpri pri = *dest; nghttp2_extpri pri = *dest;
sfparse_parser sfp; sf_parser sfp;
sfparse_vec key; sf_vec key;
sfparse_value val; sf_value val;
int rv; int rv;
sfparse_parser_init(&sfp, value, valuelen); sf_parser_init(&sfp, value, valuelen);
for (;;) { for (;;) {
rv = sfparse_parser_dict(&sfp, &key, &val); rv = sf_parser_dict(&sfp, &key, &val);
if (rv != 0) { if (rv != 0) {
if (rv == SFPARSE_ERR_EOF) { if (rv == SF_ERR_EOF) {
break; break;
} }
@@ -682,7 +605,7 @@ int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
switch (key.base[0]) { switch (key.base[0]) {
case 'i': case 'i':
if (val.type != SFPARSE_TYPE_BOOLEAN) { if (val.type != SF_TYPE_BOOLEAN) {
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
@@ -690,7 +613,7 @@ int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
break; break;
case 'u': case 'u':
if (val.type != SFPARSE_TYPE_INTEGER || if (val.type != SF_TYPE_INTEGER ||
val.integer < NGHTTP2_EXTPRI_URGENCY_HIGH || val.integer < NGHTTP2_EXTPRI_URGENCY_HIGH ||
NGHTTP2_EXTPRI_URGENCY_LOW < val.integer) { NGHTTP2_EXTPRI_URGENCY_LOW < val.integer) {
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;

View File

@@ -52,11 +52,7 @@ typedef enum {
* Unlike NGHTTP2_ERR_IGN_HTTP_HEADER, this does not invoke * Unlike NGHTTP2_ERR_IGN_HTTP_HEADER, this does not invoke
* nghttp2_on_invalid_header_callback. * nghttp2_on_invalid_header_callback.
*/ */
NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106, NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106
/*
* Cancel pushed stream.
*/
NGHTTP2_ERR_PUSH_CANCEL = -107,
} nghttp2_internal_error; } nghttp2_internal_error;
#endif /* NGHTTP2_INT_H */ #endif /* NGHTTP2_INT_H */

View File

@@ -31,13 +31,13 @@
#include "nghttp2_helper.h" #include "nghttp2_helper.h"
#define NGHTTP2_INITIAL_HASHBITS 4 #define NGHTTP2_INITIAL_TABLE_LENBITS 4
void nghttp2_map_init(nghttp2_map *map, uint32_t seed, nghttp2_mem *mem) { void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
map->mem = mem; map->mem = mem;
map->hashbits = 0; map->tablelen = 0;
map->tablelenbits = 0;
map->table = NULL; map->table = NULL;
map->seed = seed;
map->size = 0; map->size = 0;
} }
@@ -49,20 +49,33 @@ void nghttp2_map_free(nghttp2_map *map) {
nghttp2_mem_free(map->mem, map->table); nghttp2_mem_free(map->mem, map->table);
} }
int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr), void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
uint32_t i;
nghttp2_map_bucket *bkt;
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
continue;
}
func(bkt->data, ptr);
}
}
int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) { void *ptr) {
int rv; int rv;
size_t i; uint32_t i;
nghttp2_map_bucket *bkt; nghttp2_map_bucket *bkt;
size_t tablelen;
if (map->size == 0) { if (map->size == 0) {
return 0; return 0;
} }
tablelen = 1u << map->hashbits; for (i = 0; i < map->tablelen; ++i) {
for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i]; bkt = &map->table[i];
if (bkt->data == NULL) { if (bkt->data == NULL) {
@@ -78,70 +91,82 @@ int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr),
return 0; return 0;
} }
static size_t map_hash(const nghttp2_map *map, nghttp2_map_key_type key) { static uint32_t hash(nghttp2_map_key_type key) {
/* hasher from return (uint32_t)key * 2654435769u;
https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
We do not perform finalization here because we use top bits
anyway. */
uint32_t h = ((uint32_t)key + map->seed) * 0x93d765dd;
return (size_t)((h * 2654435769u) >> (32 - map->hashbits));
} }
static void map_bucket_swap(nghttp2_map_bucket *a, nghttp2_map_bucket *b) { static size_t h2idx(uint32_t hash, uint32_t bits) {
nghttp2_map_bucket c = *a; return hash >> (32 - bits);
}
*a = *b; static size_t distance(uint32_t tablelen, uint32_t tablelenbits,
*b = c; nghttp2_map_bucket *bkt, size_t idx) {
return (idx - h2idx(bkt->hash, tablelenbits)) & (tablelen - 1);
}
static void map_bucket_swap(nghttp2_map_bucket *bkt, uint32_t *phash,
nghttp2_map_key_type *pkey, void **pdata) {
uint32_t h = bkt->hash;
nghttp2_map_key_type key = bkt->key;
void *data = bkt->data;
bkt->hash = *phash;
bkt->key = *pkey;
bkt->data = *pdata;
*phash = h;
*pkey = key;
*pdata = data;
}
static void map_bucket_set_data(nghttp2_map_bucket *bkt, uint32_t hash,
nghttp2_map_key_type key, void *data) {
bkt->hash = hash;
bkt->key = key;
bkt->data = data;
} }
#ifndef WIN32 #ifndef WIN32
void nghttp2_map_print_distance(const nghttp2_map *map) { void nghttp2_map_print_distance(nghttp2_map *map) {
size_t i; uint32_t i;
size_t idx; size_t idx;
nghttp2_map_bucket *bkt; nghttp2_map_bucket *bkt;
size_t tablelen;
if (map->size == 0) { for (i = 0; i < map->tablelen; ++i) {
return;
}
tablelen = 1u << map->hashbits;
for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i]; bkt = &map->table[i];
if (bkt->data == NULL) { if (bkt->data == NULL) {
fprintf(stderr, "@%zu <EMPTY>\n", i); fprintf(stderr, "@%u <EMPTY>\n", i);
continue; continue;
} }
idx = map_hash(map, bkt->key); idx = h2idx(bkt->hash, map->tablelenbits);
fprintf(stderr, "@%zu hash=%zu key=%d base=%zu distance=%u\n", i, fprintf(stderr, "@%u hash=%08x key=%d base=%zu distance=%zu\n", i,
map_hash(map, bkt->key), bkt->key, idx, bkt->psl); bkt->hash, bkt->key, idx,
distance(map->tablelen, map->tablelenbits, bkt, idx));
} }
} }
#endif /* !defined(WIN32) */ #endif /* !WIN32 */
static int map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) { static int insert(nghttp2_map_bucket *table, uint32_t tablelen,
size_t idx = map_hash(map, key); uint32_t tablelenbits, uint32_t hash,
nghttp2_map_bucket b = { nghttp2_map_key_type key, void *data) {
.key = key, size_t idx = h2idx(hash, tablelenbits);
.data = data, size_t d = 0, dd;
};
nghttp2_map_bucket *bkt; nghttp2_map_bucket *bkt;
size_t mask = (1u << map->hashbits) - 1;
for (;;) { for (;;) {
bkt = &map->table[idx]; bkt = &table[idx];
if (bkt->data == NULL) { if (bkt->data == NULL) {
*bkt = b; map_bucket_set_data(bkt, hash, key, data);
++map->size;
return 0; return 0;
} }
if (b.psl > bkt->psl) { dd = distance(tablelen, tablelenbits, bkt, idx);
map_bucket_swap(bkt, &b); if (d > dd) {
map_bucket_swap(bkt, &hash, &key, &data);
d = dd;
} else if (bkt->key == key) { } else if (bkt->key == key) {
/* TODO This check is just a waste after first swap or if this /* TODO This check is just a waste after first swap or if this
function is called from map_resize. That said, there is no function is called from map_resize. That said, there is no
@@ -150,47 +175,42 @@ static int map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
++b.psl; ++d;
idx = (idx + 1) & mask; idx = (idx + 1) & (tablelen - 1);
} }
} }
static int map_resize(nghttp2_map *map, size_t new_hashbits) { /* new_tablelen must be power of 2 and new_tablelen == (1 <<
size_t i; new_tablelenbits) must hold. */
static int map_resize(nghttp2_map *map, uint32_t new_tablelen,
uint32_t new_tablelenbits) {
uint32_t i;
nghttp2_map_bucket *new_table;
nghttp2_map_bucket *bkt; nghttp2_map_bucket *bkt;
size_t tablelen;
int rv; int rv;
nghttp2_map new_map = {
.table = nghttp2_mem_calloc(map->mem, 1u << new_hashbits,
sizeof(nghttp2_map_bucket)),
.mem = map->mem,
.seed = map->seed,
.hashbits = new_hashbits,
};
(void)rv; (void)rv;
if (new_map.table == NULL) { new_table =
nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_bucket));
if (new_table == NULL) {
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }
if (map->size) { for (i = 0; i < map->tablelen; ++i) {
tablelen = 1u << map->hashbits; bkt = &map->table[i];
if (bkt->data == NULL) {
for (i = 0; i < tablelen; ++i) { continue;
bkt = &map->table[i];
if (bkt->data == NULL) {
continue;
}
rv = map_insert(&new_map, bkt->key, bkt->data);
assert(0 == rv);
} }
rv = insert(new_table, new_tablelen, new_tablelenbits, bkt->hash, bkt->key,
bkt->data);
assert(0 == rv);
} }
nghttp2_mem_free(map->mem, map->table); nghttp2_mem_free(map->mem, map->table);
map->table = new_map.table; map->tablelen = new_tablelen;
map->hashbits = new_hashbits; map->tablelenbits = new_tablelenbits;
map->table = new_table;
return 0; return 0;
} }
@@ -200,48 +220,49 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
assert(data); assert(data);
/* Load factor is 7/8 */ /* Load factor is 0.75 */
/* Under the very initial condition, that is map->size == 0 and if ((map->size + 1) * 4 > map->tablelen * 3) {
map->hashbits == 0, 8 > 7 still holds nicely. */ if (map->tablelen) {
if ((map->size + 1) * 8 > (1u << map->hashbits) * 7) { rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
if (map->hashbits) {
rv = map_resize(map, map->hashbits + 1);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
} }
} else { } else {
rv = map_resize(map, NGHTTP2_INITIAL_HASHBITS); rv = map_resize(map, 1 << NGHTTP2_INITIAL_TABLE_LENBITS,
NGHTTP2_INITIAL_TABLE_LENBITS);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
} }
} }
} }
rv = map_insert(map, key, data); rv = insert(map->table, map->tablelen, map->tablelenbits, hash(key), key,
data);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
} }
++map->size;
return 0; return 0;
} }
void *nghttp2_map_find(const nghttp2_map *map, nghttp2_map_key_type key) { void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
uint32_t h;
size_t idx; size_t idx;
nghttp2_map_bucket *bkt; nghttp2_map_bucket *bkt;
size_t psl = 0; size_t d = 0;
size_t mask;
if (map->size == 0) { if (map->size == 0) {
return NULL; return NULL;
} }
idx = map_hash(map, key); h = hash(key);
mask = (1u << map->hashbits) - 1; idx = h2idx(h, map->tablelenbits);
for (;;) { for (;;) {
bkt = &map->table[idx]; bkt = &map->table[idx];
if (bkt->data == NULL || psl > bkt->psl) { if (bkt->data == NULL ||
d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
return NULL; return NULL;
} }
@@ -249,47 +270,50 @@ void *nghttp2_map_find(const nghttp2_map *map, nghttp2_map_key_type key) {
return bkt->data; return bkt->data;
} }
++psl; ++d;
idx = (idx + 1) & mask; idx = (idx + 1) & (map->tablelen - 1);
} }
} }
int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) { int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
size_t idx; uint32_t h;
nghttp2_map_bucket *b, *bkt; size_t idx, didx;
size_t psl = 0; nghttp2_map_bucket *bkt;
size_t mask; size_t d = 0;
if (map->size == 0) { if (map->size == 0) {
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
idx = map_hash(map, key); h = hash(key);
mask = (1u << map->hashbits) - 1; idx = h2idx(h, map->tablelenbits);
for (;;) { for (;;) {
bkt = &map->table[idx]; bkt = &map->table[idx];
if (bkt->data == NULL || psl > bkt->psl) { if (bkt->data == NULL ||
d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
if (bkt->key == key) { if (bkt->key == key) {
b = bkt; map_bucket_set_data(bkt, 0, 0, NULL);
idx = (idx + 1) & mask;
didx = idx;
idx = (idx + 1) & (map->tablelen - 1);
for (;;) { for (;;) {
bkt = &map->table[idx]; bkt = &map->table[idx];
if (bkt->data == NULL || bkt->psl == 0) { if (bkt->data == NULL ||
b->data = NULL; distance(map->tablelen, map->tablelenbits, bkt, idx) == 0) {
break; break;
} }
--bkt->psl; map->table[didx] = *bkt;
*b = *bkt; map_bucket_set_data(bkt, 0, 0, NULL);
b = bkt; didx = idx;
idx = (idx + 1) & mask; idx = (idx + 1) & (map->tablelen - 1);
} }
--map->size; --map->size;
@@ -297,18 +321,18 @@ int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
return 0; return 0;
} }
++psl; ++d;
idx = (idx + 1) & mask; idx = (idx + 1) & (map->tablelen - 1);
} }
} }
void nghttp2_map_clear(nghttp2_map *map) { void nghttp2_map_clear(nghttp2_map *map) {
if (map->size == 0) { if (map->tablelen == 0) {
return; return;
} }
memset(map->table, 0, sizeof(*map->table) * (1u << map->hashbits)); memset(map->table, 0, sizeof(*map->table) * map->tablelen);
map->size = 0; map->size = 0;
} }
size_t nghttp2_map_size(const nghttp2_map *map) { return map->size; } size_t nghttp2_map_size(nghttp2_map *map) { return map->size; }

View File

@@ -28,7 +28,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
#endif /* defined(HAVE_CONFIG_H) */ #endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
@@ -39,7 +39,7 @@
typedef int32_t nghttp2_map_key_type; typedef int32_t nghttp2_map_key_type;
typedef struct nghttp2_map_bucket { typedef struct nghttp2_map_bucket {
uint32_t psl; uint32_t hash;
nghttp2_map_key_type key; nghttp2_map_key_type key;
void *data; void *data;
} nghttp2_map_bucket; } nghttp2_map_bucket;
@@ -47,26 +47,34 @@ typedef struct nghttp2_map_bucket {
typedef struct nghttp2_map { typedef struct nghttp2_map {
nghttp2_map_bucket *table; nghttp2_map_bucket *table;
nghttp2_mem *mem; nghttp2_mem *mem;
uint32_t seed;
size_t size; size_t size;
size_t hashbits; uint32_t tablelen;
uint32_t tablelenbits;
} nghttp2_map; } nghttp2_map;
/* /*
* nghttp2_map_init initializes the map |map|. * Initializes the map |map|.
*/ */
void nghttp2_map_init(nghttp2_map *map, uint32_t seed, nghttp2_mem *mem); void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
/* /*
* nghttp2_map_free deallocates any resources allocated for |map|. * Deallocates any resources allocated for |map|. The stored entries
* The stored entries are not freed by this function. Use * are not freed by this function. Use nghttp2_map_each_free() to free
* nghttp2_map_each() to free each entry. * each entries.
*/ */
void nghttp2_map_free(nghttp2_map *map); void nghttp2_map_free(nghttp2_map *map);
/* /*
* nghttp2_map_insert inserts the new |data| with the |key| to the map * Deallocates each entries using |func| function and any resources
* |map|. * allocated for |map|. The |func| function is responsible for freeing
* given the |data| object. The |ptr| will be passed to the |func| as
* send argument. The return value of the |func| will be ignored.
*/
void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr);
/*
* Inserts the new |data| with the |key| to the map |map|.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@@ -74,56 +82,57 @@ void nghttp2_map_free(nghttp2_map *map);
* NGHTTP2_ERR_INVALID_ARGUMENT * NGHTTP2_ERR_INVALID_ARGUMENT
* The item associated by |key| already exists. * The item associated by |key| already exists.
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory * Out of memory
*/ */
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data); int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data);
/* /*
* nghttp2_map_find returns the entry associated by the key |key|. If * Returns the data associated by the key |key|. If there is no such
* there is no such entry, this function returns NULL. * data, this function returns NULL.
*/ */
void *nghttp2_map_find(const nghttp2_map *map, nghttp2_map_key_type key); void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key);
/* /*
* nghttp2_map_remove removes the entry associated by the key |key| * Removes the data associated by the key |key| from the |map|. The
* from the |map|. The removed entry is not freed by this function. * removed data is not freed by this function.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* NGHTTP2_ERR_INVALID_ARGUMENT * NGHTTP2_ERR_INVALID_ARGUMENT
* The entry associated by |key| does not exist. * The data associated by |key| does not exist.
*/ */
int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key); int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key);
/* /*
* nghttp2_map_clear removes all entries from |map|. The removed * Removes all entries from |map|.
* entry is not freed by this function.
*/ */
void nghttp2_map_clear(nghttp2_map *map); void nghttp2_map_clear(nghttp2_map *map);
/* /*
* nghttp2_map_size returns the number of items stored in the map * Returns the number of items stored in the map |map|.
* |map|.
*/ */
size_t nghttp2_map_size(const nghttp2_map *map); size_t nghttp2_map_size(nghttp2_map *map);
/* /*
* nghttp2_map_each applies the function |func| to each entry in the * Applies the function |func| to each data in the |map| with the
* |map| with the optional user supplied pointer |ptr|. * optional user supplied pointer |ptr|.
* *
* If the |func| returns 0, this function calls the |func| with the * If the |func| returns 0, this function calls the |func| with the
* next entry. If the |func| returns nonzero, it will not call the * next data. If the |func| returns nonzero, it will not call the
* |func| for further entries and return the return value of the * |func| for further entries and return the return value of the
* |func| immediately. Thus, this function returns 0 if all the * |func| immediately. Thus, this function returns 0 if all the
* invocations of the |func| return 0, or nonzero value which the last * invocations of the |func| return 0, or nonzero value which the last
* invocation of |func| returns. * invocation of |func| returns.
*
* Don't use this function to free each data. Use
* nghttp2_map_each_free() instead.
*/ */
int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr), int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr); void *ptr);
#ifndef WIN32 #ifndef WIN32
void nghttp2_map_print_distance(const nghttp2_map *map); void nghttp2_map_print_distance(nghttp2_map *map);
#endif /* !defined(WIN32) */ #endif /* !WIN32 */
#endif /* !defined(NGHTTP2_MAP_H) */ #endif /* NGHTTP2_MAP_H */

View File

@@ -132,15 +132,15 @@ void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
} }
void nghttp2_option_set_server_fallback_rfc7540_priorities( void nghttp2_option_set_server_fallback_rfc7540_priorities(
nghttp2_option *option, int val) { nghttp2_option *option, int val) {
option->opt_set_mask |= NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES; option->opt_set_mask |= NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES;
option->server_fallback_rfc7540_priorities = val; option->server_fallback_rfc7540_priorities = val;
} }
void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation( void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
nghttp2_option *option, int val) { nghttp2_option *option, int val) {
option->opt_set_mask |= option->opt_set_mask |=
NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION; NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
option->no_rfc9113_leading_and_trailing_ws_validation = val; option->no_rfc9113_leading_and_trailing_ws_validation = val;
} }
@@ -155,10 +155,3 @@ void nghttp2_option_set_max_continuations(nghttp2_option *option, size_t val) {
option->opt_set_mask |= NGHTTP2_OPT_MAX_CONTINUATIONS; option->opt_set_mask |= NGHTTP2_OPT_MAX_CONTINUATIONS;
option->max_continuations = val; option->max_continuations = val;
} }
void nghttp2_option_set_glitch_rate_limit(nghttp2_option *option,
uint64_t burst, uint64_t rate) {
option->opt_set_mask |= NGHTTP2_OPT_GLITCH_RATE_LIMIT;
option->glitch_burst = burst;
option->glitch_rate = rate;
}

View File

@@ -72,7 +72,6 @@ typedef enum {
NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14, NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14,
NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15, NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15,
NGHTTP2_OPT_MAX_CONTINUATIONS = 1 << 16, NGHTTP2_OPT_MAX_CONTINUATIONS = 1 << 16,
NGHTTP2_OPT_GLITCH_RATE_LIMIT = 1 << 17,
} nghttp2_option_flag; } nghttp2_option_flag;
/** /**
@@ -84,11 +83,6 @@ struct nghttp2_option {
*/ */
uint64_t stream_reset_burst; uint64_t stream_reset_burst;
uint64_t stream_reset_rate; uint64_t stream_reset_rate;
/**
* NGHTTP2_OPT_GLITCH_RATE_LIMIT
*/
uint64_t glitch_burst;
uint64_t glitch_rate;
/** /**
* NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH * NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
*/ */

View File

@@ -46,7 +46,7 @@ void nghttp2_queue_free(nghttp2_queue *queue) {
int nghttp2_queue_push(nghttp2_queue *queue, void *data) { int nghttp2_queue_push(nghttp2_queue *queue, void *data) {
nghttp2_queue_cell *new_cell = nghttp2_queue_cell *new_cell =
(nghttp2_queue_cell *)malloc(sizeof(nghttp2_queue_cell)); (nghttp2_queue_cell *)malloc(sizeof(nghttp2_queue_cell));
if (!new_cell) { if (!new_cell) {
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -45,8 +45,6 @@
preface handling. */ preface handling. */
extern int nghttp2_enable_strict_preface; extern int nghttp2_enable_strict_preface;
extern nghttp2_stream nghttp2_stream_root;
/* /*
* Option flags. * Option flags.
*/ */
@@ -55,6 +53,8 @@ typedef enum {
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1, NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2, NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3, NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4,
NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 5,
NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6, NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6,
} nghttp2_optmask; } nghttp2_optmask;
@@ -89,6 +89,10 @@ typedef struct {
/* The default maximum number of incoming reserved streams */ /* The default maximum number of incoming reserved streams */
#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200 #define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200
/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this
number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */
#define NGHTTP2_MIN_IDLE_STREAMS 16
/* The maximum number of items in outbound queue, which is considered /* The maximum number of items in outbound queue, which is considered
as flooding caused by peer. All frames are not considered here. as flooding caused by peer. All frames are not considered here.
We only consider PING + ACK and SETTINGS + ACK. This is because We only consider PING + ACK and SETTINGS + ACK. This is because
@@ -106,10 +110,6 @@ typedef struct {
#define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000 #define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000
#define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33 #define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33
/* The default values for glitch rate limiter. */
#define NGHTTP2_DEFAULT_GLITCH_BURST 1000
#define NGHTTP2_DEFAULT_GLITCH_RATE 33
/* The default max number of CONTINUATION frames following an incoming /* The default max number of CONTINUATION frames following an incoming
HEADER frame. */ HEADER frame. */
#define NGHTTP2_DEFAULT_MAX_CONTINUATIONS 8 #define NGHTTP2_DEFAULT_MAX_CONTINUATIONS 8
@@ -205,6 +205,8 @@ typedef struct nghttp2_inflight_settings nghttp2_inflight_settings;
struct nghttp2_session { struct nghttp2_session {
nghttp2_map /* <nghttp2_stream*> */ streams; nghttp2_map /* <nghttp2_stream*> */ streams;
/* root of dependency tree*/
nghttp2_stream root;
/* Queue for outbound urgent frames (PING and SETTINGS) */ /* Queue for outbound urgent frames (PING and SETTINGS) */
nghttp2_outbound_queue ob_urgent; nghttp2_outbound_queue ob_urgent;
/* Queue for non-DATA frames */ /* Queue for non-DATA frames */
@@ -227,14 +229,26 @@ struct nghttp2_session {
/* Memory allocator */ /* Memory allocator */
nghttp2_mem mem; nghttp2_mem mem;
void *user_data; void *user_data;
/* Points to the latest incoming closed stream. NULL if there is no
closed stream. Only used when session is initialized as
server. */
nghttp2_stream *closed_stream_head;
/* Points to the oldest incoming closed stream. NULL if there is no
closed stream. Only used when session is initialized as
server. */
nghttp2_stream *closed_stream_tail;
/* Points to the latest idle stream. NULL if there is no idle
stream. Only used when session is initialized as server .*/
nghttp2_stream *idle_stream_head;
/* Points to the oldest idle stream. NULL if there is no idle
stream. Only used when session is initialized as erver. */
nghttp2_stream *idle_stream_tail;
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not /* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
considered as in-flight. */ considered as in-flight. */
nghttp2_inflight_settings *inflight_settings_head; nghttp2_inflight_settings *inflight_settings_head;
/* Stream reset rate limiter. If receiving excessive amount of /* Stream reset rate limiter. If receiving excessive amount of
stream resets, GOAWAY will be sent. */ stream resets, GOAWAY will be sent. */
nghttp2_ratelim stream_reset_ratelim; nghttp2_ratelim stream_reset_ratelim;
/* Rate limiter for all kinds of glitches. */
nghttp2_ratelim glitch_ratelim;
/* Sequential number across all streams to process streams in /* Sequential number across all streams to process streams in
FIFO. */ FIFO. */
uint64_t stream_seq; uint64_t stream_seq;
@@ -262,9 +276,10 @@ struct nghttp2_session {
|closed_stream_head|. The current implementation only keeps |closed_stream_head|. The current implementation only keeps
incoming streams and session is initialized as server. */ incoming streams and session is initialized as server. */
size_t num_closed_streams; size_t num_closed_streams;
/* The number of idle streams kept in |streams| hash. The current /* The number of idle streams kept in |streams| hash. The idle
implementation only keeps idle streams if session is initialized streams can be accessed through doubly linked list
as server. */ |idle_stream_head|. The current implementation only keeps idle
streams if session is initialized as server. */
size_t num_idle_streams; size_t num_idle_streams;
/* The number of bytes allocated for nvbuf */ /* The number of bytes allocated for nvbuf */
size_t nvbuflen; size_t nvbuflen;
@@ -347,6 +362,8 @@ struct nghttp2_session {
/* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is /* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is
effective before it is acknowledged. */ effective before it is acknowledged. */
uint8_t pending_no_rfc7540_priorities; uint8_t pending_no_rfc7540_priorities;
/* Turn on fallback to RFC 7540 priorities; for server use only. */
uint8_t fallback_rfc7540_priorities;
/* 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 received. The flags are /* Flags indicating GOAWAY is sent and/or received. The flags are
@@ -408,13 +425,6 @@ int nghttp2_session_is_my_stream_id(nghttp2_session *session,
int nghttp2_session_add_item(nghttp2_session *session, int nghttp2_session_add_item(nghttp2_session *session,
nghttp2_outbound_item *item); nghttp2_outbound_item *item);
/*
* This function wraps around nghttp2_session_add_rst_stream_continue
* with continue_without_stream = 1.
*/
int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
uint32_t error_code);
/* /*
* Adds RST_STREAM frame for the stream |stream_id| with the error * Adds RST_STREAM frame for the stream |stream_id| with the error
* code |error_code|. This is a convenient function built on top of * code |error_code|. This is a convenient function built on top of
@@ -422,9 +432,7 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
* *
* This function simply returns 0 without adding RST_STREAM frame if * This function simply returns 0 without adding RST_STREAM frame if
* given stream is in NGHTTP2_STREAM_CLOSING state, because multiple * given stream is in NGHTTP2_STREAM_CLOSING state, because multiple
* RST_STREAM for a stream is redundant. It also returns 0 without * RST_STREAM for a stream is redundant.
* adding the frame if |continue_without_stream| is nonzero, and
* stream was already gone.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@@ -432,10 +440,8 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
int nghttp2_session_add_rst_stream_continue(nghttp2_session *session, int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
int32_t stream_id, uint32_t error_code);
uint32_t error_code,
int continue_without_stream);
/* /*
* Adds PING frame. This is a convenient function built on top of * Adds PING frame. This is a convenient function built on top of
@@ -521,9 +527,15 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
* *
* This function returns a pointer to created new stream object, or * This function returns a pointer to created new stream object, or
* NULL. * NULL.
*
* This function adjusts neither the number of closed streams or idle
* streams. The caller should manually call
* nghttp2_session_adjust_closed_stream() or
* nghttp2_session_adjust_idle_stream() respectively.
*/ */
nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
int32_t stream_id, uint8_t flags, int32_t stream_id, uint8_t flags,
nghttp2_priority_spec *pri_spec,
nghttp2_stream_state initial_state, nghttp2_stream_state initial_state,
void *stream_user_data); void *stream_user_data);
@@ -532,6 +544,11 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
* is indicated by the |error_code|. When closing the stream, * is indicated by the |error_code|. When closing the stream,
* on_stream_close_callback will be called. * on_stream_close_callback will be called.
* *
* If the session is initialized as server and |stream| is incoming
* stream, stream is just marked closed and this function calls
* nghttp2_session_keep_closed_stream() with |stream|. Otherwise,
* |stream| will be deleted from memory.
*
* This function returns 0 if it succeeds, or one the following * This function returns 0 if it succeeds, or one the following
* negative error codes: * negative error codes:
* *
@@ -548,9 +565,63 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
/* /*
* Deletes |stream| from memory. After this function returns, stream * Deletes |stream| from memory. After this function returns, stream
* cannot be accessed. * cannot be accessed.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/ */
void nghttp2_session_destroy_stream(nghttp2_session *session, int nghttp2_session_destroy_stream(nghttp2_session *session,
nghttp2_stream *stream); nghttp2_stream *stream);
/*
* Tries to keep incoming closed stream |stream|. Due to the
* limitation of maximum number of streams in memory, |stream| is not
* closed and just deleted from memory (see
* nghttp2_session_destroy_stream).
*/
void nghttp2_session_keep_closed_stream(nghttp2_session *session,
nghttp2_stream *stream);
/*
* Appends |stream| to linked list |session->idle_stream_head|. We
* apply fixed limit for list size. To fit into that limit, one or
* more oldest streams are removed from list as necessary.
*/
void nghttp2_session_keep_idle_stream(nghttp2_session *session,
nghttp2_stream *stream);
/*
* Detaches |stream| from idle streams linked list.
*/
void nghttp2_session_detach_idle_stream(nghttp2_session *session,
nghttp2_stream *stream);
/*
* Deletes closed stream to ensure that number of incoming streams
* including active and closed is in the maximum number of allowed
* stream.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_adjust_closed_stream(nghttp2_session *session);
/*
* Deletes idle stream to ensure that number of idle streams is in
* certain limit.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_adjust_idle_stream(nghttp2_session *session);
/* /*
* If further receptions and transmissions over the stream |stream_id| * If further receptions and transmissions over the stream |stream_id|
@@ -844,6 +915,24 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
nghttp2_settings_entry *iv, nghttp2_settings_entry *iv,
size_t niv); size_t niv);
/*
* Re-prioritize |stream|. The new priority specification is
* |pri_spec|. Caller must ensure that stream->hd.stream_id !=
* pri_spec->stream_id.
*
* This function does not adjust the number of idle streams. The
* caller should call nghttp2_session_adjust_idle_stream() later.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_reprioritize_stream(nghttp2_session *session,
nghttp2_stream *stream,
const nghttp2_priority_spec *pri_spec);
/* /*
* Terminates current |session| with the |error_code|. The |reason| * Terminates current |session| with the |error_code|. The |reason|
* is NULL-terminated debug string. * is NULL-terminated debug string.

View File

@@ -25,17 +25,45 @@
#include "nghttp2_stream.h" #include "nghttp2_stream.h"
#include <assert.h> #include <assert.h>
#include <stdio.h>
#include "nghttp2_session.h" #include "nghttp2_session.h"
#include "nghttp2_helper.h" #include "nghttp2_helper.h"
#include "nghttp2_debug.h" #include "nghttp2_debug.h"
#include "nghttp2_frame.h" #include "nghttp2_frame.h"
/* Maximum distance between any two stream's cycle in the same
priority queue. Imagine stream A's cycle is A, and stream B's
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
may get overflow. Because of how we calculate the next cycle
value, if B - A is less than or equals to
NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other
words, B is really greater than or equal to A. Otherwise, A is a
result of overflow, and it is actually A > B if we consider that
fact. */
#define NGHTTP2_MAX_CYCLE_DISTANCE \
((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX * 256 + 255)
static int stream_less(const void *lhsx, const void *rhsx) {
const nghttp2_stream *lhs, *rhs;
lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
if (lhs->cycle == rhs->cycle) {
return lhs->seq < rhs->seq;
}
return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE;
}
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
uint8_t flags, nghttp2_stream_state initial_state, uint8_t flags, nghttp2_stream_state initial_state,
int32_t remote_initial_window_size, int32_t weight, int32_t remote_initial_window_size,
int32_t local_initial_window_size, int32_t local_initial_window_size,
void *stream_user_data) { void *stream_user_data, nghttp2_mem *mem) {
nghttp2_pq_init(&stream->obq, stream_less, mem);
stream->stream_id = stream_id; stream->stream_id = stream_id;
stream->flags = flags; stream->flags = flags;
stream->state = initial_state; stream->state = initial_state;
@@ -49,36 +77,428 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->recv_reduction = 0; stream->recv_reduction = 0;
stream->window_update_queued = 0; stream->window_update_queued = 0;
stream->dep_prev = NULL;
stream->dep_next = NULL;
stream->sib_prev = NULL;
stream->sib_next = NULL;
stream->closed_prev = NULL;
stream->closed_next = NULL; stream->closed_next = NULL;
stream->weight = weight;
stream->sum_dep_weight = 0;
stream->http_flags = NGHTTP2_HTTP_FLAG_NONE; stream->http_flags = NGHTTP2_HTTP_FLAG_NONE;
stream->content_length = -1; stream->content_length = -1;
stream->recv_content_length = 0; stream->recv_content_length = 0;
stream->status_code = -1; stream->status_code = -1;
stream->queued = 0; stream->queued = 0;
stream->descendant_last_cycle = 0;
stream->cycle = 0; stream->cycle = 0;
stream->pending_penalty = 0; stream->pending_penalty = 0;
stream->descendant_next_seq = 0;
stream->seq = 0; stream->seq = 0;
stream->last_writelen = 0; stream->last_writelen = 0;
stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY; stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
} }
void nghttp2_stream_free(nghttp2_stream *stream) { (void)stream; } void nghttp2_stream_free(nghttp2_stream *stream) {
nghttp2_pq_free(&stream->obq);
/* We don't free stream->item. If it is assigned to aob, then
active_outbound_item_reset() will delete it. Otherwise,
nghttp2_stream_close() or session_del() will delete it. */
}
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) { void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
stream->shut_flags = (uint8_t)(stream->shut_flags | flag); stream->shut_flags = (uint8_t)(stream->shut_flags | flag);
} }
void nghttp2_stream_attach_item(nghttp2_stream *stream, /*
nghttp2_outbound_item *item) { * Returns nonzero if |stream| is active. This function does not take
* into account its descendants.
*/
static int stream_active(nghttp2_stream *stream) {
return stream->item &&
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0;
}
/*
* Returns nonzero if |stream| or one of its descendants is active
*/
static int stream_subtree_active(nghttp2_stream *stream) {
return stream_active(stream) || !nghttp2_pq_empty(&stream->obq);
}
/*
* Returns next cycle for |stream|.
*/
static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) {
uint64_t penalty;
penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT +
stream->pending_penalty;
stream->cycle = last_cycle + penalty / (uint32_t)stream->weight;
stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight);
}
static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
int rv;
for (; dep_stream && !stream->queued;
stream = dep_stream, dep_stream = dep_stream->dep_prev) {
stream_next_cycle(stream, dep_stream->descendant_last_cycle);
stream->seq = dep_stream->descendant_next_seq++;
DEBUGF("stream: stream=%d obq push cycle=%lu\n", stream->stream_id,
stream->cycle);
DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id,
dep_stream->stream_id);
rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
if (rv != 0) {
return rv;
}
stream->queued = 1;
}
return 0;
}
/*
* Removes |stream| from parent's obq. If removal of |stream| makes
* parent's obq empty, and parent is not active, then parent is also
* removed. This process is repeated recursively.
*/
static void stream_obq_remove(nghttp2_stream *stream) {
nghttp2_stream *dep_stream;
dep_stream = stream->dep_prev;
if (!stream->queued) {
return;
}
for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id,
dep_stream->stream_id);
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
assert(stream->queued);
stream->queued = 0;
stream->cycle = 0;
stream->pending_penalty = 0;
stream->descendant_last_cycle = 0;
stream->last_writelen = 0;
if (stream_subtree_active(dep_stream)) {
return;
}
}
}
/*
* Moves |stream| from |src|'s obq to |dest|'s obq. Removal from
* |src|'s obq is just done calling nghttp2_pq_remove(), so it does
* not recursively remove |src| and ancestors, like
* stream_obq_remove().
*/
static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src,
nghttp2_stream *stream) {
if (!stream->queued) {
return 0;
}
DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id,
src->stream_id);
nghttp2_pq_remove(&src->obq, &stream->pq_entry);
stream->queued = 0;
return stream_obq_push(dest, stream);
}
void nghttp2_stream_reschedule(nghttp2_stream *stream) {
nghttp2_stream *dep_stream;
assert(stream->queued);
dep_stream = stream->dep_prev;
for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
stream_next_cycle(stream, dep_stream->descendant_last_cycle);
stream->seq = dep_stream->descendant_next_seq++;
nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
stream->cycle);
dep_stream->last_writelen = stream->last_writelen;
}
}
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
nghttp2_stream *dep_stream;
uint64_t last_cycle;
int32_t old_weight;
uint64_t wlen_penalty;
if (stream->weight == weight) {
return;
}
old_weight = stream->weight;
stream->weight = weight;
dep_stream = stream->dep_prev;
if (!dep_stream) {
return;
}
dep_stream->sum_dep_weight += weight - old_weight;
if (!stream->queued) {
return;
}
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
wlen_penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;
/* Compute old stream->pending_penalty we used to calculate
stream->cycle */
stream->pending_penalty =
(uint32_t)((stream->pending_penalty + (uint32_t)old_weight -
(wlen_penalty % (uint32_t)old_weight)) %
(uint32_t)old_weight);
last_cycle = stream->cycle -
(wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight;
/* Now we have old stream->pending_penalty and new stream->weight in
place */
stream_next_cycle(stream, last_cycle);
if (dep_stream->descendant_last_cycle - stream->cycle <=
NGHTTP2_MAX_CYCLE_DISTANCE) {
stream->cycle = dep_stream->descendant_last_cycle;
}
/* Continue to use same stream->seq */
nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
stream->cycle);
}
static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
for (; stream->sib_next; stream = stream->sib_next)
;
return stream;
}
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
int32_t weight) {
weight = stream->weight * weight / stream->sum_dep_weight;
return nghttp2_max_int32(1, weight);
}
#ifdef STREAM_DEP_DEBUG
static void ensure_inactive(nghttp2_stream *stream) {
nghttp2_stream *si;
if (stream->queued) {
fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream,
stream->stream_id);
assert(0);
}
if (stream_active(stream)) {
fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n",
stream, stream->stream_id);
assert(0);
}
if (!nghttp2_pq_empty(&stream->obq)) {
fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream,
stream->stream_id, nghttp2_pq_size(&stream->obq));
assert(0);
}
for (si = stream->dep_next; si; si = si->sib_next) {
ensure_inactive(si);
}
}
static void check_queued(nghttp2_stream *stream) {
nghttp2_stream *si;
int queued;
if (stream->queued) {
if (!stream_subtree_active(stream)) {
fprintf(stderr,
"stream(%p)=%d, stream->queued == 1, but "
"stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n",
stream, stream->stream_id, stream_active(stream),
nghttp2_pq_size(&stream->obq));
assert(0);
}
if (!stream_active(stream)) {
queued = 0;
for (si = stream->dep_next; si; si = si->sib_next) {
if (si->queued) {
++queued;
}
}
if (queued == 0) {
fprintf(stderr,
"stream(%p)=%d, stream->queued == 1, and "
"!stream_active(), but no descendants is queued\n",
stream, stream->stream_id);
assert(0);
}
}
for (si = stream->dep_next; si; si = si->sib_next) {
check_queued(si);
}
} else {
if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) {
fprintf(stderr,
"stream(%p) = %d, stream->queued == 0, but "
"stream_active(stream) == %d and "
"nghttp2_pq_size(&stream->obq) = %zu\n",
stream, stream->stream_id, stream_active(stream),
nghttp2_pq_size(&stream->obq));
assert(0);
}
for (si = stream->dep_next; si; si = si->sib_next) {
ensure_inactive(si);
}
}
}
static void check_sum_dep(nghttp2_stream *stream) {
nghttp2_stream *si;
int32_t n = 0;
for (si = stream->dep_next; si; si = si->sib_next) {
n += si->weight;
}
if (n != stream->sum_dep_weight) {
fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream,
stream->stream_id, n, stream->sum_dep_weight);
assert(0);
}
for (si = stream->dep_next; si; si = si->sib_next) {
check_sum_dep(si);
}
}
static void check_dep_prev(nghttp2_stream *stream) {
nghttp2_stream *si;
for (si = stream->dep_next; si; si = si->sib_next) {
if (si->dep_prev != stream) {
fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream);
assert(0);
}
check_dep_prev(si);
}
}
#endif /* STREAM_DEP_DEBUG */
#ifdef STREAM_DEP_DEBUG
static void validate_tree(nghttp2_stream *stream) {
nghttp2_stream *si;
if (!stream) {
return;
}
for (; stream->dep_prev; stream = stream->dep_prev)
;
assert(stream->stream_id == 0);
assert(!stream->queued);
fprintf(stderr, "checking...\n");
if (nghttp2_pq_empty(&stream->obq)) {
fprintf(stderr, "root obq empty\n");
for (si = stream->dep_next; si; si = si->sib_next) {
ensure_inactive(si);
}
} else {
for (si = stream->dep_next; si; si = si->sib_next) {
check_queued(si);
}
}
check_sum_dep(stream);
check_dep_prev(stream);
}
#else /* !STREAM_DEP_DEBUG */
static void validate_tree(nghttp2_stream *stream) { (void)stream; }
#endif /* !STREAM_DEP_DEBUG*/
static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
int rv;
rv = stream_obq_push(stream->dep_prev, stream);
if (rv != 0) {
return rv;
}
validate_tree(stream);
return 0;
}
static void stream_update_dep_on_detach_item(nghttp2_stream *stream) {
if (nghttp2_pq_empty(&stream->obq)) {
stream_obq_remove(stream);
}
validate_tree(stream);
}
int nghttp2_stream_attach_item(nghttp2_stream *stream,
nghttp2_outbound_item *item) {
int rv;
assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0); assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0);
assert(stream->item == NULL); assert(stream->item == NULL);
DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item); DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item);
stream->item = item; stream->item = item;
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
return 0;
}
rv = stream_update_dep_on_attach_item(stream);
if (rv != 0) {
/* This may relave stream->queued == 1, but stream->item == NULL.
But only consequence of this error is fatal one, and session
destruction. In that execution path, these inconsistency does
not matter. */
stream->item = NULL;
return rv;
}
return 0;
} }
void nghttp2_stream_detach_item(nghttp2_stream *stream) { void nghttp2_stream_detach_item(nghttp2_stream *stream) {
@@ -86,6 +506,12 @@ void nghttp2_stream_detach_item(nghttp2_stream *stream) {
stream->item = NULL; stream->item = NULL;
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL); stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
return;
}
stream_update_dep_on_detach_item(stream);
} }
void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
@@ -95,16 +521,31 @@ void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
stream->item, flags); stream->item, flags);
stream->flags |= flags; stream->flags |= flags;
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
return;
}
stream_update_dep_on_detach_item(stream);
} }
void nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
uint8_t flags) {
assert(stream->item); assert(stream->item);
DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id, DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id,
stream->item, flags); stream->item, flags);
stream->flags = (uint8_t)(stream->flags & ~flags); stream->flags = (uint8_t)(stream->flags & ~flags);
if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
return 0;
}
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
return 0;
}
return stream_update_dep_on_attach_item(stream);
} }
int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) { int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) {
@@ -130,16 +571,16 @@ static int update_initial_window_size(int32_t *window_size_ptr,
} }
int nghttp2_stream_update_remote_initial_window_size( int nghttp2_stream_update_remote_initial_window_size(
nghttp2_stream *stream, int32_t new_initial_window_size, nghttp2_stream *stream, int32_t new_initial_window_size,
int32_t old_initial_window_size) { int32_t old_initial_window_size) {
return update_initial_window_size(&stream->remote_window_size, return update_initial_window_size(&stream->remote_window_size,
new_initial_window_size, new_initial_window_size,
old_initial_window_size); old_initial_window_size);
} }
int nghttp2_stream_update_local_initial_window_size( int nghttp2_stream_update_local_initial_window_size(
nghttp2_stream *stream, int32_t new_initial_window_size, nghttp2_stream *stream, int32_t new_initial_window_size,
int32_t old_initial_window_size) { int32_t old_initial_window_size) {
return update_initial_window_size(&stream->local_window_size, return update_initial_window_size(&stream->local_window_size,
new_initial_window_size, new_initial_window_size,
old_initial_window_size); old_initial_window_size);
@@ -150,11 +591,373 @@ void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) {
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH); stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH);
} }
nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) { int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
if (stream == &nghttp2_stream_root) { nghttp2_stream *target) {
return NGHTTP2_STREAM_STATE_IDLE; for (; stream; stream = stream->dep_prev) {
if (stream == target) {
return 1;
}
}
return 0;
}
int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
nghttp2_stream *stream) {
nghttp2_stream *si;
int rv;
DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
dep_stream->stream_id, stream, stream->stream_id);
stream->sum_dep_weight = dep_stream->sum_dep_weight;
dep_stream->sum_dep_weight = stream->weight;
if (dep_stream->dep_next) {
for (si = dep_stream->dep_next; si; si = si->sib_next) {
si->dep_prev = stream;
if (si->queued) {
rv = stream_obq_move(stream, dep_stream, si);
if (rv != 0) {
return rv;
}
}
}
if (stream_subtree_active(stream)) {
rv = stream_obq_push(dep_stream, stream);
if (rv != 0) {
return rv;
}
}
stream->dep_next = dep_stream->dep_next;
} }
dep_stream->dep_next = stream;
stream->dep_prev = dep_stream;
validate_tree(stream);
return 0;
}
static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) {
for (; stream; stream = stream->sib_next) {
stream->dep_prev = dep;
}
}
static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
dep_stream->dep_next = stream;
if (stream) {
stream->dep_prev = dep_stream;
}
}
static void link_sib(nghttp2_stream *a, nghttp2_stream *b) {
a->sib_next = b;
if (b) {
b->sib_prev = a;
}
}
static void insert_link_dep(nghttp2_stream *dep_stream,
nghttp2_stream *stream) {
nghttp2_stream *sib_next;
assert(stream->sib_prev == NULL);
sib_next = dep_stream->dep_next;
link_sib(stream, sib_next);
link_dep(dep_stream, stream);
}
static void unlink_sib(nghttp2_stream *stream) {
nghttp2_stream *prev, *next, *dep_next;
prev = stream->sib_prev;
dep_next = stream->dep_next;
assert(prev);
if (dep_next) {
/*
* prev--stream(--sib_next--...)
* |
* dep_next
*/
link_sib(prev, dep_next);
set_dep_prev(dep_next, stream->dep_prev);
if (stream->sib_next) {
link_sib(stream_last_sib(dep_next), stream->sib_next);
}
} else {
/*
* prev--stream(--sib_next--...)
*/
next = stream->sib_next;
prev->sib_next = next;
if (next) {
next->sib_prev = prev;
}
}
}
static void unlink_dep(nghttp2_stream *stream) {
nghttp2_stream *prev, *next, *dep_next;
prev = stream->dep_prev;
dep_next = stream->dep_next;
assert(prev);
if (dep_next) {
/*
* prev
* |
* stream(--sib_next--...)
* |
* dep_next
*/
link_dep(prev, dep_next);
set_dep_prev(dep_next, stream->dep_prev);
if (stream->sib_next) {
link_sib(stream_last_sib(dep_next), stream->sib_next);
}
} else if (stream->sib_next) {
/*
* prev
* |
* stream--sib_next
*/
next = stream->sib_next;
next->sib_prev = NULL;
link_dep(prev, next);
} else {
prev->dep_next = NULL;
}
}
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
nghttp2_stream *stream) {
DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
dep_stream->stream_id, stream, stream->stream_id);
dep_stream->sum_dep_weight += stream->weight;
if (dep_stream->dep_next == NULL) {
link_dep(dep_stream, stream);
} else {
insert_link_dep(dep_stream, stream);
}
validate_tree(stream);
}
int nghttp2_stream_dep_remove(nghttp2_stream *stream) {
nghttp2_stream *dep_prev, *si;
int32_t sum_dep_weight_delta;
int rv;
DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id);
/* Distribute weight of |stream| to direct descendants */
sum_dep_weight_delta = -stream->weight;
for (si = stream->dep_next; si; si = si->sib_next) {
si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
sum_dep_weight_delta += si->weight;
if (si->queued) {
rv = stream_obq_move(stream->dep_prev, stream, si);
if (rv != 0) {
return rv;
}
}
}
assert(stream->dep_prev);
dep_prev = stream->dep_prev;
dep_prev->sum_dep_weight += sum_dep_weight_delta;
if (stream->queued) {
stream_obq_remove(stream);
}
if (stream->sib_prev) {
unlink_sib(stream);
} else {
unlink_dep(stream);
}
stream->sum_dep_weight = 0;
stream->dep_prev = NULL;
stream->dep_next = NULL;
stream->sib_prev = NULL;
stream->sib_next = NULL;
validate_tree(dep_prev);
return 0;
}
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream) {
nghttp2_stream *last_sib;
nghttp2_stream *dep_next;
nghttp2_stream *si;
int rv;
DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, stream, stream->stream_id);
stream->sum_dep_weight += dep_stream->sum_dep_weight;
dep_stream->sum_dep_weight = stream->weight;
if (dep_stream->dep_next) {
dep_next = dep_stream->dep_next;
link_dep(dep_stream, stream);
if (stream->dep_next) {
last_sib = stream_last_sib(stream->dep_next);
link_sib(last_sib, dep_next);
} else {
link_dep(stream, dep_next);
}
for (si = dep_next; si; si = si->sib_next) {
si->dep_prev = stream;
if (si->queued) {
rv = stream_obq_move(stream, dep_stream, si);
if (rv != 0) {
return rv;
}
}
}
} else {
link_dep(dep_stream, stream);
}
if (stream_subtree_active(stream)) {
rv = stream_obq_push(dep_stream, stream);
if (rv != 0) {
return rv;
}
}
validate_tree(dep_stream);
return 0;
}
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream) {
int rv;
DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, stream, stream->stream_id);
dep_stream->sum_dep_weight += stream->weight;
if (dep_stream->dep_next) {
insert_link_dep(dep_stream, stream);
} else {
link_dep(dep_stream, stream);
}
if (stream_subtree_active(stream)) {
rv = stream_obq_push(dep_stream, stream);
if (rv != 0) {
return rv;
}
}
validate_tree(dep_stream);
return 0;
}
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
nghttp2_stream *next, *dep_prev;
DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream,
stream->stream_id);
assert(stream->dep_prev);
dep_prev = stream->dep_prev;
if (stream->sib_prev) {
link_sib(stream->sib_prev, stream->sib_next);
} else {
next = stream->sib_next;
link_dep(dep_prev, next);
if (next) {
next->sib_prev = NULL;
}
}
dep_prev->sum_dep_weight -= stream->weight;
if (stream->queued) {
stream_obq_remove(stream);
}
validate_tree(dep_prev);
stream->sib_prev = NULL;
stream->sib_next = NULL;
stream->dep_prev = NULL;
}
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) {
return stream->dep_prev || stream->dep_next || stream->sib_prev ||
stream->sib_next;
}
nghttp2_outbound_item *
nghttp2_stream_next_outbound_item(nghttp2_stream *stream) {
nghttp2_pq_entry *ent;
nghttp2_stream *si;
for (;;) {
if (stream_active(stream)) {
/* Update ascendant's descendant_last_cycle here, so that we can
assure that new stream is scheduled based on it. */
for (si = stream; si->dep_prev; si = si->dep_prev) {
si->dep_prev->descendant_last_cycle = si->cycle;
}
return stream->item;
}
ent = nghttp2_pq_top(&stream->obq);
if (!ent) {
return NULL;
}
stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
}
}
nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) {
if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) { if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) {
return NGHTTP2_STREAM_STATE_CLOSED; return NGHTTP2_STREAM_STATE_CLOSED;
} }
@@ -185,39 +988,27 @@ nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) {
} }
nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) { nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) {
(void)stream; return stream->dep_prev;
return NULL;
} }
nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) { nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) {
(void)stream; return stream->sib_next;
return NULL;
} }
nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) { nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) {
(void)stream; return stream->sib_prev;
return NULL;
} }
nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) { nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) {
(void)stream; return stream->dep_next;
return NULL;
} }
int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) { int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) {
(void)stream; return stream->weight;
return NGHTTP2_DEFAULT_WEIGHT;
} }
int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) { int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) {
(void)stream; return stream->sum_dep_weight;
return 0;
} }
int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) { int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) {

View File

@@ -91,6 +91,9 @@ typedef enum {
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and /* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */ NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c, NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c,
/* Indicates that this stream is not subject to RFC7540
priorities scheme. */
NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10,
/* Ignore client RFC 9218 priority signal. */ /* Ignore client RFC 9218 priority signal. */
NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20, NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20,
/* Indicates that RFC 9113 leading and trailing white spaces /* Indicates that RFC 9113 leading and trailing white spaces
@@ -121,9 +124,10 @@ typedef enum {
NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8, NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9, NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10, NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10,
NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT |
NGHTTP2_HTTP_FLAG_METH_CONNECT | NGHTTP2_HTTP_FLAG_METH_HEAD | NGHTTP2_HTTP_FLAG_METH_HEAD |
NGHTTP2_HTTP_FLAG_METH_OPTIONS | NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND, NGHTTP2_HTTP_FLAG_METH_OPTIONS |
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND,
/* :path category */ /* :path category */
/* path starts with "/" */ /* path starts with "/" */
NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11, NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11,
@@ -143,18 +147,39 @@ typedef enum {
} nghttp2_http_flag; } nghttp2_http_flag;
struct nghttp2_stream { struct nghttp2_stream {
nghttp2_stream_state state; /* Entry for dep_prev->obq */
nghttp2_pq_entry pq_entry; nghttp2_pq_entry pq_entry;
/* Priority Queue storing direct descendant (nghttp2_stream). Only
streams which itself has some data to send, or has a descendant
which has some data to sent. */
nghttp2_pq obq;
/* Content-Length of request/response body. -1 if unknown. */ /* Content-Length of request/response body. -1 if unknown. */
int64_t content_length; int64_t content_length;
/* Received body so far */ /* Received body so far */
int64_t recv_content_length; int64_t recv_content_length;
/* Base last_cycle for direct descendent streams. */
uint64_t descendant_last_cycle;
/* Next scheduled time to sent item */ /* Next scheduled time to sent item */
uint64_t cycle; uint64_t cycle;
/* Next seq used for direct descendant streams */
uint64_t descendant_next_seq;
/* Secondary key for prioritization to break a tie for cycle. This /* Secondary key for prioritization to break a tie for cycle. This
value is monotonically increased for single parent stream. */ value is monotonically increased for single parent stream. */
uint64_t seq; uint64_t seq;
nghttp2_stream *closed_next; /* pointers to form dependency tree. If multiple streams depend on
a stream, only one stream (left most) has non-NULL dep_prev which
points to the stream it depends on. The remaining streams are
linked using sib_prev and sib_next. The stream which has
non-NULL dep_prev always NULL sib_prev. The right most stream
has NULL sib_next. If this stream is a root of dependency tree,
dep_prev and sib_prev are NULL. */
nghttp2_stream *dep_prev, *dep_next;
nghttp2_stream *sib_prev, *sib_next;
/* When stream is kept after closure, it may be kept in doubly
linked list pointed by nghttp2_session closed_stream_head.
closed_next points to the next stream object if it is the element
of the list. */
nghttp2_stream *closed_prev, *closed_next;
/* The arbitrary data provided by user for this stream. */ /* The arbitrary data provided by user for this stream. */
void *stream_user_data; void *stream_user_data;
/* Item to send */ /* Item to send */
@@ -181,8 +206,13 @@ struct nghttp2_stream {
NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by
submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */ submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */
int32_t local_window_size; int32_t local_window_size;
/* weight of this stream */
int32_t weight;
/* This is unpaid penalty (offset) when calculating cycle. */ /* This is unpaid penalty (offset) when calculating cycle. */
uint32_t pending_penalty; uint32_t pending_penalty;
/* sum of weight of direct descendants */
int32_t sum_dep_weight;
nghttp2_stream_state state;
/* status code from remote server */ /* status code from remote server */
int16_t status_code; int16_t status_code;
/* Bitwise OR of zero or more nghttp2_http_flag values */ /* Bitwise OR of zero or more nghttp2_http_flag values */
@@ -210,9 +240,9 @@ struct nghttp2_stream {
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
uint8_t flags, nghttp2_stream_state initial_state, uint8_t flags, nghttp2_stream_state initial_state,
int32_t remote_initial_window_size, int32_t weight, int32_t remote_initial_window_size,
int32_t local_initial_window_size, int32_t local_initial_window_size,
void *stream_user_data); void *stream_user_data, nghttp2_mem *mem);
void nghttp2_stream_free(nghttp2_stream *stream); void nghttp2_stream_free(nghttp2_stream *stream);
@@ -238,8 +268,14 @@ void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are
* cleared if they are set. So even if this function is called, if * cleared if they are set. So even if this function is called, if
* one of flag is still set, data does not become active. * one of flag is still set, data does not become active.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/ */
void nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags); int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags);
/* /*
* Returns nonzero if item is deferred by whatever reason. * Returns nonzero if item is deferred by whatever reason.
@@ -260,8 +296,8 @@ int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream);
* overflow. * overflow.
*/ */
int nghttp2_stream_update_remote_initial_window_size( int nghttp2_stream_update_remote_initial_window_size(
nghttp2_stream *stream, int32_t new_initial_window_size, nghttp2_stream *stream, int32_t new_initial_window_size,
int32_t old_initial_window_size); int32_t old_initial_window_size);
/* /*
* Updates the local window size with the new value * Updates the local window size with the new value
@@ -272,8 +308,8 @@ int nghttp2_stream_update_remote_initial_window_size(
* overflow. * overflow.
*/ */
int nghttp2_stream_update_local_initial_window_size( int nghttp2_stream_update_local_initial_window_size(
nghttp2_stream *stream, int32_t new_initial_window_size, nghttp2_stream *stream, int32_t new_initial_window_size,
int32_t old_initial_window_size); int32_t old_initial_window_size);
/* /*
* Call this function if promised stream |stream| is replied with * Call this function if promised stream |stream| is replied with
@@ -283,10 +319,56 @@ int nghttp2_stream_update_local_initial_window_size(
void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream); void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream);
/* /*
* Attaches |item| to |stream|. * Returns nonzero if |target| is an ancestor of |stream|.
*/ */
void nghttp2_stream_attach_item(nghttp2_stream *stream, int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
nghttp2_outbound_item *item); nghttp2_stream *target);
/*
* Computes distributed weight of a stream of the |weight| under the
* |stream| if |stream| is removed from a dependency tree.
*/
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
int32_t weight);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
* exclusive. All existing direct descendants of |dep_stream| become
* the descendants of the |stream|. This function assumes
* |stream->item| is NULL.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
nghttp2_stream *stream);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
* not exclusive. This function assumes |stream->item| is NULL.
*/
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream);
/*
* Removes the |stream| from the current dependency tree. This
* function assumes |stream->item| is NULL.
*/
int nghttp2_stream_dep_remove(nghttp2_stream *stream);
/*
* Attaches |item| to |stream|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_attach_item(nghttp2_stream *stream,
nghttp2_outbound_item *item);
/* /*
* Detaches |stream->item|. This function does not free * Detaches |stream->item|. This function does not free
@@ -294,4 +376,66 @@ void nghttp2_stream_attach_item(nghttp2_stream *stream,
*/ */
void nghttp2_stream_detach_item(nghttp2_stream *stream); void nghttp2_stream_detach_item(nghttp2_stream *stream);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
* exclusive.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
* not exclusive.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream);
/*
* Removes subtree whose root stream is |stream|. The
* effective_weight of streams in removed subtree is not updated.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
/*
* Returns nonzero if |stream| is in any dependency tree.
*/
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream);
/*
* Schedules transmission of |stream|'s item, assuming stream->item is
* attached, and stream->last_writelen was updated.
*/
void nghttp2_stream_reschedule(nghttp2_stream *stream);
/*
* Changes |stream|'s weight to |weight|. If |stream| is queued, it
* will be rescheduled based on new weight.
*/
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight);
/*
* Returns a stream which has highest priority, updating
* descendant_last_cycle of selected stream's ancestors.
*/
nghttp2_outbound_item *
nghttp2_stream_next_outbound_item(nghttp2_stream *stream);
#endif /* NGHTTP2_STREAM */ #endif /* NGHTTP2_STREAM */

View File

@@ -32,12 +32,42 @@
#include "nghttp2_helper.h" #include "nghttp2_helper.h"
#include "nghttp2_priority_spec.h" #include "nghttp2_priority_spec.h"
/*
* Detects the dependency error, that is stream attempted to depend on
* itself. If |stream_id| is -1, we use session->next_stream_id as
* stream ID.
*
* This function returns 0 if it succeeds, or one of the following
* error codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
* Stream attempted to depend on itself.
*/
static int detect_self_dependency(nghttp2_session *session, int32_t stream_id,
const nghttp2_priority_spec *pri_spec) {
assert(pri_spec);
if (stream_id == -1) {
if ((int32_t)session->next_stream_id == pri_spec->stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
return 0;
}
if (stream_id == pri_spec->stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
return 0;
}
/* This function takes ownership of |nva_copy|. Regardless of the /* This function takes ownership of |nva_copy|. Regardless of the
return value, the caller must not free |nva_copy| after this return value, the caller must not free |nva_copy| after this
function returns. */ function returns. */
static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags, static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
int32_t stream_id, nghttp2_nv *nva_copy, int32_t stream_id,
size_t nvlen, const nghttp2_priority_spec *pri_spec,
nghttp2_nv *nva_copy, size_t nvlen,
const nghttp2_data_provider_wrap *dpw, const nghttp2_data_provider_wrap *dpw,
void *stream_user_data) { void *stream_user_data) {
int rv; int rv;
@@ -64,8 +94,8 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
item->aux_data.headers.stream_user_data = stream_user_data; item->aux_data.headers.stream_user_data = stream_user_data;
flags_copy = flags_copy =
(uint8_t)((flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) | (uint8_t)((flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) |
NGHTTP2_FLAG_END_HEADERS); NGHTTP2_FLAG_END_HEADERS);
if (stream_id == -1) { if (stream_id == -1) {
if (session->next_stream_id > INT32_MAX) { if (session->next_stream_id > INT32_MAX) {
@@ -84,8 +114,8 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
frame = &item->frame; frame = &item->frame;
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat, NULL, nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat,
nva_copy, nvlen); pri_spec, nva_copy, nvlen);
rv = nghttp2_session_add_item(session, item); rv = nghttp2_session_add_item(session, item);
@@ -111,22 +141,31 @@ fail2:
static int32_t submit_headers_shared_nva(nghttp2_session *session, static int32_t submit_headers_shared_nva(nghttp2_session *session,
uint8_t flags, int32_t stream_id, uint8_t flags, int32_t stream_id,
const nghttp2_priority_spec *pri_spec,
const nghttp2_nv *nva, size_t nvlen, const nghttp2_nv *nva, size_t nvlen,
const nghttp2_data_provider_wrap *dpw, const nghttp2_data_provider_wrap *dpw,
void *stream_user_data) { void *stream_user_data) {
int rv; int rv;
nghttp2_nv *nva_copy; nghttp2_nv *nva_copy;
nghttp2_priority_spec copy_pri_spec;
nghttp2_mem *mem; nghttp2_mem *mem;
mem = &session->mem; mem = &session->mem;
if (pri_spec) {
copy_pri_spec = *pri_spec;
nghttp2_priority_spec_normalize_weight(&copy_pri_spec);
} else {
nghttp2_priority_spec_default_init(&copy_pri_spec);
}
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem); rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem);
if (rv < 0) { if (rv < 0) {
return rv; return rv;
} }
return submit_headers_shared(session, flags, stream_id, nva_copy, nvlen, dpw, return submit_headers_shared(session, flags, stream_id, &copy_pri_spec,
stream_user_data); nva_copy, nvlen, dpw, stream_user_data);
} }
int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id, int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id,
@@ -136,7 +175,8 @@ int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id,
} }
return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM, return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM,
stream_id, nva, nvlen, NULL, NULL); stream_id, NULL, nva, nvlen, NULL,
NULL);
} }
int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
@@ -144,7 +184,7 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
const nghttp2_priority_spec *pri_spec, const nghttp2_priority_spec *pri_spec,
const nghttp2_nv *nva, size_t nvlen, const nghttp2_nv *nva, size_t nvlen,
void *stream_user_data) { void *stream_user_data) {
(void)pri_spec; int rv;
if (stream_id == -1) { if (stream_id == -1) {
if (session->server) { if (session->server) {
@@ -156,8 +196,20 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
flags &= NGHTTP2_FLAG_END_STREAM; flags &= NGHTTP2_FLAG_END_STREAM;
return submit_headers_shared_nva(session, flags, stream_id, nva, nvlen, NULL, if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
stream_user_data); session->remote_settings.no_rfc7540_priorities != 1) {
rv = detect_self_dependency(session, stream_id, pri_spec);
if (rv != 0) {
return rv;
}
flags |= NGHTTP2_FLAG_PRIORITY;
} else {
pri_spec = NULL;
}
return submit_headers_shared_nva(session, flags, stream_id, pri_spec, nva,
nvlen, NULL, stream_user_data);
} }
int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
@@ -169,10 +221,51 @@ int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, 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) {
(void)session; int rv;
nghttp2_outbound_item *item;
nghttp2_frame *frame;
nghttp2_priority_spec copy_pri_spec;
nghttp2_mem *mem;
(void)flags; (void)flags;
(void)stream_id;
(void)pri_spec; mem = &session->mem;
if (session->remote_settings.no_rfc7540_priorities == 1) {
return 0;
}
if (stream_id == 0 || pri_spec == NULL) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
if (stream_id == pri_spec->stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
copy_pri_spec = *pri_spec;
nghttp2_priority_spec_normalize_weight(&copy_pri_spec);
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
if (item == NULL) {
return NGHTTP2_ERR_NOMEM;
}
nghttp2_outbound_item_init(item);
frame = &item->frame;
nghttp2_frame_priority_init(&frame->priority, stream_id, &copy_pri_spec);
rv = nghttp2_session_add_item(session, item);
if (rv != 0) {
nghttp2_frame_priority_free(&frame->priority);
nghttp2_mem_free(mem, item);
return rv;
}
return 0; return 0;
} }
@@ -185,8 +278,7 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
return nghttp2_session_add_rst_stream_continue( return nghttp2_session_add_rst_stream(session, stream_id, error_code);
session, stream_id, error_code, /* continue_without_stream = */ 0);
} }
int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags, int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
@@ -297,8 +389,8 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
} }
if (stream_id == 0) { if (stream_id == 0) {
rv = nghttp2_adjust_local_window_size( rv = nghttp2_adjust_local_window_size(
&session->local_window_size, &session->recv_window_size, &session->local_window_size, &session->recv_window_size,
&session->recv_reduction, &window_size_increment); &session->recv_reduction, &window_size_increment);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
} }
@@ -309,8 +401,8 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
} }
rv = nghttp2_adjust_local_window_size( rv = nghttp2_adjust_local_window_size(
&stream->local_window_size, &stream->recv_window_size, &stream->local_window_size, &stream->recv_window_size,
&stream->recv_reduction, &window_size_increment); &stream->recv_reduction, &window_size_increment);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
} }
@@ -319,10 +411,10 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
if (window_size_increment > 0) { if (window_size_increment > 0) {
if (stream_id == 0) { if (stream_id == 0) {
session->consumed_size = session->consumed_size =
nghttp2_max_int32(0, session->consumed_size - window_size_increment); nghttp2_max_int32(0, session->consumed_size - window_size_increment);
} else { } else {
stream->consumed_size = stream->consumed_size =
nghttp2_max_int32(0, stream->consumed_size - window_size_increment); nghttp2_max_int32(0, stream->consumed_size - window_size_increment);
} }
return nghttp2_session_add_window_update(session, 0, stream_id, return nghttp2_session_add_window_update(session, 0, stream_id,
@@ -352,13 +444,13 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
if (window_size_increment < 0) { if (window_size_increment < 0) {
return nghttp2_adjust_local_window_size( return nghttp2_adjust_local_window_size(
&session->local_window_size, &session->recv_window_size, &session->local_window_size, &session->recv_window_size,
&session->recv_reduction, &window_size_increment); &session->recv_reduction, &window_size_increment);
} }
rv = nghttp2_increase_local_window_size( rv = nghttp2_increase_local_window_size(
&session->local_window_size, &session->recv_window_size, &session->local_window_size, &session->recv_window_size,
&session->recv_reduction, &window_size_increment); &session->recv_reduction, &window_size_increment);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
@@ -385,13 +477,13 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
if (window_size_increment < 0) { if (window_size_increment < 0) {
return nghttp2_adjust_local_window_size( return nghttp2_adjust_local_window_size(
&stream->local_window_size, &stream->recv_window_size, &stream->local_window_size, &stream->recv_window_size,
&stream->recv_reduction, &window_size_increment); &stream->recv_reduction, &window_size_increment);
} }
rv = nghttp2_increase_local_window_size( rv = nghttp2_increase_local_window_size(
&stream->local_window_size, &stream->recv_window_size, &stream->local_window_size, &stream->recv_window_size,
&stream->recv_reduction, &window_size_increment); &stream->recv_reduction, &window_size_increment);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
@@ -487,7 +579,7 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
return 0; return 0;
fail_item_malloc: fail_item_malloc:
nghttp2_mem_free(mem, buf); free(buf);
return rv; return rv;
} }
@@ -522,7 +614,7 @@ int nghttp2_submit_origin(nghttp2_session *session, uint8_t flags,
/* The last nov is added for terminal NULL character. */ /* The last nov is added for terminal NULL character. */
ov_copy = ov_copy =
nghttp2_mem_malloc(mem, nov * sizeof(nghttp2_origin_entry) + len + nov); nghttp2_mem_malloc(mem, nov * sizeof(nghttp2_origin_entry) + len + nov);
if (ov_copy == NULL) { if (ov_copy == NULL) {
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }
@@ -570,7 +662,7 @@ int nghttp2_submit_origin(nghttp2_session *session, uint8_t flags,
return 0; return 0;
fail_item_malloc: fail_item_malloc:
nghttp2_mem_free(mem, ov_copy); free(ov_copy);
return rv; return rv;
} }
@@ -642,34 +734,51 @@ int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags,
return 0; return 0;
fail_item_malloc: fail_item_malloc:
nghttp2_mem_free(mem, buf); free(buf);
return rv; return rv;
} }
static uint8_t set_request_flags(const nghttp2_data_provider_wrap *dpw) { static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
const nghttp2_data_provider_wrap *dpw) {
uint8_t flags = NGHTTP2_FLAG_NONE; uint8_t flags = NGHTTP2_FLAG_NONE;
if (dpw == NULL || dpw->data_prd.read_callback == NULL) { if (dpw == NULL || dpw->data_prd.read_callback == NULL) {
flags |= NGHTTP2_FLAG_END_STREAM; flags |= NGHTTP2_FLAG_END_STREAM;
} }
if (pri_spec) {
flags |= NGHTTP2_FLAG_PRIORITY;
}
return flags; return flags;
} }
static int32_t submit_request_shared(nghttp2_session *session, static int32_t submit_request_shared(nghttp2_session *session,
const nghttp2_priority_spec *pri_spec,
const nghttp2_nv *nva, size_t nvlen, const nghttp2_nv *nva, size_t nvlen,
const nghttp2_data_provider_wrap *dpw, const nghttp2_data_provider_wrap *dpw,
void *stream_user_data) { void *stream_user_data) {
uint8_t flags; uint8_t flags;
int rv;
if (session->server) { if (session->server) {
return NGHTTP2_ERR_PROTO; return NGHTTP2_ERR_PROTO;
} }
flags = set_request_flags(dpw); if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
session->remote_settings.no_rfc7540_priorities != 1) {
rv = detect_self_dependency(session, -1, pri_spec);
if (rv != 0) {
return rv;
}
} else {
pri_spec = NULL;
}
return submit_headers_shared_nva(session, flags, -1, nva, nvlen, dpw, flags = set_request_flags(pri_spec, dpw);
stream_user_data);
return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen,
dpw, stream_user_data);
} }
int32_t nghttp2_submit_request(nghttp2_session *session, int32_t nghttp2_submit_request(nghttp2_session *session,
@@ -678,9 +787,8 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
const nghttp2_data_provider *data_prd, const nghttp2_data_provider *data_prd,
void *stream_user_data) { void *stream_user_data) {
nghttp2_data_provider_wrap dpw; nghttp2_data_provider_wrap dpw;
(void)pri_spec;
return submit_request_shared(session, nva, nvlen, return submit_request_shared(session, pri_spec, nva, nvlen,
nghttp2_data_provider_wrap_v1(&dpw, data_prd), nghttp2_data_provider_wrap_v1(&dpw, data_prd),
stream_user_data); stream_user_data);
} }
@@ -691,9 +799,8 @@ int32_t nghttp2_submit_request2(nghttp2_session *session,
const nghttp2_data_provider2 *data_prd, const nghttp2_data_provider2 *data_prd,
void *stream_user_data) { void *stream_user_data) {
nghttp2_data_provider_wrap dpw; nghttp2_data_provider_wrap dpw;
(void)pri_spec;
return submit_request_shared(session, nva, nvlen, return submit_request_shared(session, pri_spec, nva, nvlen,
nghttp2_data_provider_wrap_v2(&dpw, data_prd), nghttp2_data_provider_wrap_v2(&dpw, data_prd),
stream_user_data); stream_user_data);
} }
@@ -720,8 +827,8 @@ static int submit_response_shared(nghttp2_session *session, int32_t stream_id,
} }
flags = set_response_flags(dpw); flags = set_response_flags(dpw);
return submit_headers_shared_nva(session, flags, stream_id, nva, nvlen, dpw, return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen,
NULL); dpw, NULL);
} }
int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
@@ -791,7 +898,7 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
assert(data_prd); assert(data_prd);
return nghttp2_submit_data_shared( return nghttp2_submit_data_shared(
session, flags, stream_id, nghttp2_data_provider_wrap_v1(&dpw, data_prd)); session, flags, stream_id, nghttp2_data_provider_wrap_v1(&dpw, data_prd));
} }
int nghttp2_submit_data2(nghttp2_session *session, uint8_t flags, int nghttp2_submit_data2(nghttp2_session *session, uint8_t flags,
@@ -802,7 +909,7 @@ int nghttp2_submit_data2(nghttp2_session *session, uint8_t flags,
assert(data_prd); assert(data_prd);
return nghttp2_submit_data_shared( return nghttp2_submit_data_shared(
session, flags, stream_id, nghttp2_data_provider_wrap_v2(&dpw, data_prd)); session, flags, stream_id, nghttp2_data_provider_wrap_v2(&dpw, data_prd));
} }
ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen, ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,

View File

@@ -31,7 +31,7 @@
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include "nghttp2_outbound_item.h" typedef struct nghttp2_data_provider_wrap nghttp2_data_provider_wrap;
int nghttp2_submit_data_shared(nghttp2_session *session, uint8_t flags, int nghttp2_submit_data_shared(nghttp2_session *session, uint8_t flags,
int32_t stream_id, int32_t stream_id,

View File

@@ -45,7 +45,7 @@ static uint64_t time_now_sec(void) {
#if defined(HAVE_GETTICKCOUNT64) && !defined(__CYGWIN__) #if defined(HAVE_GETTICKCOUNT64) && !defined(__CYGWIN__)
uint64_t nghttp2_time_now_sec(void) { return GetTickCount64() / 1000; } uint64_t nghttp2_time_now_sec(void) { return GetTickCount64() / 1000; }
#elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_DECL_CLOCK_MONOTONIC) && \ #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_DECL_CLOCK_MONOTONIC) && \
HAVE_DECL_CLOCK_MONOTONIC HAVE_DECL_CLOCK_MONOTONIC
uint64_t nghttp2_time_now_sec(void) { uint64_t nghttp2_time_now_sec(void) {
struct timespec tp; struct timespec tp;
int rv = clock_gettime(CLOCK_MONOTONIC, &tp); int rv = clock_gettime(CLOCK_MONOTONIC, &tp);

File diff suppressed because it is too large Load Diff

View File

@@ -31,90 +31,86 @@
libcurl) */ libcurl) */
#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
# define WIN32 # define WIN32
#endif /* (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) */ #endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* defined(__cplusplus) */ #endif
#if defined(_MSC_VER) && (_MSC_VER < 1800) #if defined(_MSC_VER) && (_MSC_VER < 1800)
/* MSVC < 2013 does not have inttypes.h because it is not C99 /* MSVC < 2013 does not have inttypes.h because it is not C99
compliant. See compiler macros and version number in compliant. See compiler macros and version number in
https://sourceforge.net/p/predef/wiki/Compilers/ */ https://sourceforge.net/p/predef/wiki/Compilers/ */
# include <stdint.h> # include <stdint.h>
#else /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */ #else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
# include <inttypes.h> # include <inttypes.h>
#endif /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */ #endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
#include <sys/types.h> #include <sys/types.h>
#include <stddef.h> #include <stddef.h>
/** /**
* @enum * @enum
* *
* :type:`sfparse_type` defines value type. * :type:`sf_type` defines value type.
*/ */
typedef enum sfparse_type { typedef enum sf_type {
/** /**
* :enum:`SFPARSE_TYPE_BOOLEAN` indicates boolean type. * :enum:`SF_TYPE_BOOLEAN` indicates boolean type.
*/ */
SFPARSE_TYPE_BOOLEAN, SF_TYPE_BOOLEAN,
/** /**
* :enum:`SFPARSE_TYPE_INTEGER` indicates integer type. * :enum:`SF_TYPE_INTEGER` indicates integer type.
*/ */
SFPARSE_TYPE_INTEGER, SF_TYPE_INTEGER,
/** /**
* :enum:`SFPARSE_TYPE_DECIMAL` indicates decimal type. * :enum:`SF_TYPE_DECIMAL` indicates decimal type.
*/ */
SFPARSE_TYPE_DECIMAL, SF_TYPE_DECIMAL,
/** /**
* :enum:`SFPARSE_TYPE_STRING` indicates string type. * :enum:`SF_TYPE_STRING` indicates string type.
*/ */
SFPARSE_TYPE_STRING, SF_TYPE_STRING,
/** /**
* :enum:`SFPARSE_TYPE_TOKEN` indicates token type. * :enum:`SF_TYPE_TOKEN` indicates token type.
*/ */
SFPARSE_TYPE_TOKEN, SF_TYPE_TOKEN,
/** /**
* :enum:`SFPARSE_TYPE_BYTESEQ` indicates byte sequence type. * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type.
*/ */
SFPARSE_TYPE_BYTESEQ, SF_TYPE_BYTESEQ,
/** /**
* :enum:`SFPARSE_TYPE_INNER_LIST` indicates inner list type. * :enum:`SF_TYPE_INNER_LIST` indicates inner list type.
*/ */
SFPARSE_TYPE_INNER_LIST, SF_TYPE_INNER_LIST,
/** /**
* :enum:`SFPARSE_TYPE_DATE` indicates date type. * :enum:`SF_TYPE_DATE` indicates date type.
*/ */
SFPARSE_TYPE_DATE, SF_TYPE_DATE
/** } sf_type;
* :enum:`SFPARSE_TYPE_DISPSTRING` indicates display string type.
*/
SFPARSE_TYPE_DISPSTRING
} sfparse_type;
/** /**
* @macro * @macro
* *
* :macro:`SFPARSE_ERR_PARSE` indicates fatal parse error has * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has
* occurred, and it is not possible to continue the processing. * occurred, and it is not possible to continue the processing.
*/ */
#define SFPARSE_ERR_PARSE -1 #define SF_ERR_PARSE_ERROR -1
/** /**
* @macro * @macro
* *
* :macro:`SFPARSE_ERR_EOF` indicates that there is nothing left to * :macro:`SF_ERR_EOF` indicates that there is nothing left to read.
* read. The context of this error varies depending on the function * The context of this error varies depending on the function that
* that returns this error code. * returns this error code.
*/ */
#define SFPARSE_ERR_EOF -2 #define SF_ERR_EOF -2
/** /**
* @struct * @struct
* *
* :type:`sfparse_vec` stores sequence of bytes. * :type:`sf_vec` stores sequence of bytes.
*/ */
typedef struct sfparse_vec { typedef struct sf_vec {
/** /**
* :member:`base` points to the beginning of the sequence of bytes. * :member:`base` points to the beginning of the sequence of bytes.
*/ */
@@ -123,29 +119,29 @@ typedef struct sfparse_vec {
* :member:`len` is the number of bytes contained in this sequence. * :member:`len` is the number of bytes contained in this sequence.
*/ */
size_t len; size_t len;
} sfparse_vec; } sf_vec;
/** /**
* @macro * @macro
* *
* :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set. * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set.
*/ */
#define SFPARSE_VALUE_FLAG_NONE 0x0u #define SF_VALUE_FLAG_NONE 0x0u
/** /**
* @macro * @macro
* *
* :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` indicates that a string * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string
* contains escaped character(s). * contains escaped character(s).
*/ */
#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1u #define SF_VALUE_FLAG_ESCAPED_STRING 0x1u
/** /**
* @struct * @struct
* *
* :type:`sfparse_decimal` contains decimal value. * :type:`sf_decimal` contains decimal value.
*/ */
typedef struct sfparse_decimal { typedef struct sf_decimal {
/** /**
* :member:`numer` contains numerator of the decimal value. * :member:`numer` contains numerator of the decimal value.
*/ */
@@ -154,289 +150,260 @@ typedef struct sfparse_decimal {
* :member:`denom` contains denominator of the decimal value. * :member:`denom` contains denominator of the decimal value.
*/ */
int64_t denom; int64_t denom;
} sfparse_decimal; } sf_decimal;
/** /**
* @struct * @struct
* *
* :type:`sfparse_value` stores a Structured Field item. For Inner * :type:`sf_value` stores a Structured Field item. For Inner List,
* List, only type is set to * only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order
* :enum:`sfparse_type.SFPARSE_TYPE_INNER_LIST`. In order to read the * to read the items contained in an inner list, call
* items contained in an inner list, call `sfparse_parser_inner_list`. * `sf_parser_inner_list`.
*/ */
typedef struct sfparse_value { typedef struct sf_value {
/** /**
* :member:`type` is the type of the value contained in this * :member:`type` is the type of the value contained in this
* particular object. * particular object.
*/ */
sfparse_type type; sf_type type;
/** /**
* :member:`flags` is bitwise OR of one or more of * :member:`flags` is bitwise OR of one or more of
* :macro:`SFPARSE_VALUE_FLAG_* <SFPARSE_VALUE_FLAG_NONE>`. * :macro:`SF_VALUE_FLAG_* <SF_VALUE_FLAG_NONE>`.
*/ */
uint32_t flags; uint32_t flags;
/** /**
* @anonunion_start * @anonunion_start
* *
* @sfparse_value_value * @sf_value_value
*/ */
union { union {
/** /**
* :member:`boolean` contains boolean value if :member:`type` == * :member:`boolean` contains boolean value if :member:`type` ==
* :enum:`sfparse_type.SFPARSE_TYPE_BOOLEAN`. 1 indicates true, * :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0
* and 0 indicates false. * indicates false.
*/ */
int boolean; int boolean;
/** /**
* :member:`integer` contains integer value if :member:`type` is * :member:`integer` contains integer value if :member:`type` is
* either :enum:`sfparse_type.SFPARSE_TYPE_INTEGER` or * either :enum:`sf_type.SF_TYPE_INTEGER` or
* :enum:`sfparse_type.SFPARSE_TYPE_DATE`. * :enum:`sf_type.SF_TYPE_DATE`.
*/ */
int64_t integer; int64_t integer;
/** /**
* :member:`decimal` contains decimal value if :member:`type` == * :member:`decimal` contains decimal value if :member:`type` ==
* :enum:`sfparse_type.SFPARSE_TYPE_DECIMAL`. * :enum:`sf_type.SF_TYPE_DECIMAL`.
*/ */
sfparse_decimal decimal; sf_decimal decimal;
/** /**
* :member:`vec` contains sequence of bytes if :member:`type` is * :member:`vec` contains sequence of bytes if :member:`type` is
* either :enum:`sfparse_type.SFPARSE_TYPE_STRING`, * either :enum:`sf_type.SF_TYPE_STRING`,
* :enum:`sfparse_type.SFPARSE_TYPE_TOKEN`, * :enum:`sf_type.SF_TYPE_TOKEN`, or
* :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, or * :enum:`sf_type.SF_TYPE_BYTESEQ`.
* :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`.
* *
* For :enum:`sfparse_type.SFPARSE_TYPE_STRING`, this field * For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or
* contains one or more escaped characters if :member:`flags` has * more escaped characters if :member:`flags` has
* :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` set. To unescape * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the
* the string, use `sfparse_unescape`. * string, use `sf_unescape`.
* *
* For :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, this field * For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64
* contains base64 encoded string. To decode this byte string, * encoded string. To decode this byte string, use
* use `sfparse_base64decode`. * `sf_base64decode`.
* *
* For :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`, this field * If :member:`vec.len <sf_vec.len>` == 0, :member:`vec.base
* may contain percent-encoded UTF-8 byte sequences. To decode * <sf_vec.base>` is guaranteed to be NULL.
* it, use `sfparse_pctdecode`.
*
* If :member:`vec.len <sfparse_vec.len>` == 0, :member:`vec.base
* <sfparse_vec.base>` is guaranteed to be NULL.
*/ */
sfparse_vec vec; sf_vec vec;
/** /**
* @anonunion_end * @anonunion_end
*/ */
}; };
} sfparse_value; } sf_value;
/** /**
* @struct * @struct
* *
* :type:`sfparse_parser` is the Structured Field Values parser. Use * :type:`sf_parser` is the Structured Field Values parser. Use
* `sfparse_parser_init` to initialize it. * `sf_parser_init` to initialize it.
*/ */
typedef struct sfparse_parser { typedef struct sf_parser {
/* all fields are private */ /* all fields are private */
const uint8_t *pos; const uint8_t *pos;
const uint8_t *end; const uint8_t *end;
uint32_t state; uint32_t state;
} sfparse_parser; } sf_parser;
/** /**
* @function * @function
* *
* `sfparse_parser_init` initializes |sfp| with the given data encoded * `sf_parser_init` initializes |sfp| with the given buffer pointed by
* in Structured Field Values pointed by |data| of length |datalen|. * |data| of length |datalen|.
*/ */
void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data, void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen);
size_t datalen);
/** /**
* @function * @function
* *
* `sfparse_parser_param` reads a parameter. If this function returns * `sf_parser_param` reads a parameter. If this function returns 0,
* 0, it stores parameter key and value in |dest_key| and |dest_value| * it stores parameter key and value in |dest_key| and |dest_value|
* respectively, if they are not NULL. * respectively, if they are not NULL.
* *
* This function does no effort to find duplicated keys. Same key may * This function does no effort to find duplicated keys. Same key may
* be reported more than once. * be reported more than once.
* *
* Caller should keep calling this function until it returns negative * Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SFPARSE_ERR_EOF`, all parameters * error code. If it returns :macro:`SF_ERR_EOF`, all parameters have
* have read, and caller can continue to read rest of the values. If * read, and caller can continue to read rest of the values. If it
* it returns :macro:`SFPARSE_ERR_PARSE`, it encountered fatal error * returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error
* while parsing field value. * while parsing field value.
*/ */
int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key, int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value);
sfparse_value *dest_value);
/** /**
* @function * @function
* *
* `sfparse_parser_dict` reads the next dictionary key and value pair. * `sf_parser_dict` reads the next dictionary key and value pair. If
* If this function returns 0, it stores the key and value in * this function returns 0, it stores the key and value in |dest_key|
* |dest_key| and |dest_value| respectively, if they are not NULL. * and |dest_value| respectively, if they are not NULL.
* *
* Caller can optionally read parameters attached to the pair by * Caller can optionally read parameters attached to the pair by
* calling `sfparse_parser_param`. * calling `sf_parser_param`.
* *
* This function does no effort to find duplicated keys. Same key may * This function does no effort to find duplicated keys. Same key may
* be reported more than once. * be reported more than once.
* *
* Caller should keep calling this function until it returns negative * Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SFPARSE_ERR_EOF`, all key and * error code. If it returns :macro:`SF_ERR_EOF`, all key and value
* value pairs have been read, and there is nothing left to read. * pairs have been read, and there is nothing left to read.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* :macro:`SFPARSE_ERR_EOF` * :macro:`SF_ERR_EOF`
* All values in the dictionary have read. * All values in the dictionary have read.
* :macro:`SFPARSE_ERR_PARSE` * :macro:`SF_ERR_PARSE_ERROR`
* It encountered fatal error while parsing field value. * It encountered fatal error while parsing field value.
*/ */
int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key, int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value);
sfparse_value *dest_value);
/** /**
* @function * @function
* *
* `sfparse_parser_list` reads the next list item. If this function * `sf_parser_list` reads the next list item. If this function
* returns 0, it stores the item in |dest| if it is not NULL. * returns 0, it stores the item in |dest| if it is not NULL.
* *
* Caller can optionally read parameters attached to the item by * Caller can optionally read parameters attached to the item by
* calling `sfparse_parser_param`. * calling `sf_parser_param`.
* *
* Caller should keep calling this function until it returns negative * Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in * error code. If it returns :macro:`SF_ERR_EOF`, all values in the
* the list have been read, and there is nothing left to read. * list have been read, and there is nothing left to read.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* :macro:`SFPARSE_ERR_EOF` * :macro:`SF_ERR_EOF`
* All values in the list have read. * All values in the list have read.
* :macro:`SFPARSE_ERR_PARSE` * :macro:`SF_ERR_PARSE_ERROR`
* It encountered fatal error while parsing field value. * It encountered fatal error while parsing field value.
*/ */
int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest); int sf_parser_list(sf_parser *sfp, sf_value *dest);
/** /**
* @function * @function
* *
* `sfparse_parser_item` reads a single item. If this function * `sf_parser_item` reads a single item. If this function returns 0,
* returns 0, it stores the item in |dest| if it is not NULL. * it stores the item in |dest| if it is not NULL.
* *
* This function is only used for the field value that consists of a * This function is only used for the field value that consists of a
* single item. * single item.
* *
* Caller can optionally read parameters attached to the item by * Caller can optionally read parameters attached to the item by
* calling `sfparse_parser_param`. * calling `sf_parser_param`.
* *
* Caller should call this function again to make sure that there is * Caller should call this function again to make sure that there is
* nothing left to read. If this 2nd function call returns * nothing left to read. If this 2nd function call returns
* :macro:`SFPARSE_ERR_EOF`, all data have been processed * :macro:`SF_ERR_EOF`, all data have been processed successfully.
* successfully.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* :macro:`SFPARSE_ERR_EOF` * :macro:`SF_ERR_EOF`
* There is nothing left to read. * There is nothing left to read.
* :macro:`SFPARSE_ERR_PARSE` * :macro:`SF_ERR_PARSE_ERROR`
* It encountered fatal error while parsing field value. * It encountered fatal error while parsing field value.
*/ */
int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest); int sf_parser_item(sf_parser *sfp, sf_value *dest);
/** /**
* @function * @function
* *
* `sfparse_parser_inner_list` reads the next inner list item. If * `sf_parser_inner_list` reads the next inner list item. If this
* this function returns 0, it stores the item in |dest| if it is not * function returns 0, it stores the item in |dest| if it is not NULL.
* NULL.
* *
* Caller can optionally read parameters attached to the item by * Caller can optionally read parameters attached to the item by
* calling `sfparse_parser_param`. * calling `sf_parser_param`.
* *
* Caller should keep calling this function until it returns negative * Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in * error code. If it returns :macro:`SF_ERR_EOF`, all values in this
* this inner list have been read, and caller can optionally read * inner list have been read, and caller can optionally read
* parameters attached to this inner list by calling * parameters attached to this inner list by calling
* `sfparse_parser_param`. Then caller can continue to read rest of * `sf_parser_param`. Then caller can continue to read rest of the
* the values. * values.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* :macro:`SFPARSE_ERR_EOF` * :macro:`SF_ERR_EOF`
* All values in the inner list have read. * All values in the inner list have read.
* :macro:`SFPARSE_ERR_PARSE` * :macro:`SF_ERR_PARSE_ERROR`
* It encountered fatal error while parsing field value. * It encountered fatal error while parsing field value.
*/ */
int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest); int sf_parser_inner_list(sf_parser *sfp, sf_value *dest);
/** /**
* @function * @function
* *
* `sfparse_unescape` copies |src| to |dest| by removing escapes * `sf_unescape` copies |src| to |dest| by removing escapes (``\``).
* (``\``). |src| should be the pointer to * |src| should be the pointer to :member:`sf_value.vec` of type
* :member:`sfparse_value.vec` of type * :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`,
* :enum:`sfparse_type.SFPARSE_TYPE_STRING` produced by either * `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or
* `sfparse_parser_dict`, `sfparse_parser_list`, * `sf_parser_param`, otherwise the behavior is undefined.
* `sfparse_parser_inner_list`, `sfparse_parser_item`, or
* `sfparse_parser_param`, otherwise the behavior is undefined.
* *
* :member:`dest->base <sfparse_vec.base>` must point to the buffer * :member:`dest->base <sf_vec.base>` must point to the buffer that
* that has sufficient space to store the unescaped string. The * has sufficient space to store the unescaped string.
* memory areas pointed by :member:`dest->base <sfparse_vec.base>` and *
* :member:`src->base <sfparse_vec.base>` must not overlap. * If there is no escape character in |src|, |*src| is assigned to
* |*dest|. This includes the case that :member:`src->len
* <sf_vec.len>` == 0.
* *
* This function sets the length of unescaped string to * This function sets the length of unescaped string to
* :member:`dest->len <sfparse_vec.len>`. * :member:`dest->len <sf_vec.len>`.
*/ */
void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src); void sf_unescape(sf_vec *dest, const sf_vec *src);
/** /**
* @function * @function
* *
* `sfparse_base64decode` decodes Base64 encoded string |src| and * `sf_base64decode` decodes Base64 encoded string |src| and writes
* writes the result into |dest|. |src| should be the pointer to
* :member:`sfparse_value.vec` of type
* :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ` produced by either
* `sfparse_parser_dict`, `sfparse_parser_list`,
* `sfparse_parser_inner_list`, `sfparse_parser_item`, or
* `sfparse_parser_param`, otherwise the behavior is undefined.
*
* :member:`dest->base <sfparse_vec.base>` must point to the buffer
* that has sufficient space to store the decoded byte string.
*
* This function sets the length of decoded byte string to
* :member:`dest->len <sfparse_vec.len>`.
*/
void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src);
/**
* @function
*
* `sfparse_pctdecode` decodes percent-encoded string |src| and writes
* the result into |dest|. |src| should be the pointer to * the result into |dest|. |src| should be the pointer to
* :member:`sfparse_value.vec` of type * :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ`
* :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING` produced by either * produced by either `sf_parser_dict`, `sf_parser_list`,
* `sfparse_parser_dict`, `sfparse_parser_list`, * `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`,
* `sfparse_parser_inner_list`, `sfparse_parser_item`, or * otherwise the behavior is undefined.
* `sfparse_parser_param`, otherwise the behavior is undefined.
* *
* :member:`dest->base <sfparse_vec.base>` must point to the buffer * :member:`dest->base <sf_vec.base>` must point to the buffer that
* that has sufficient space to store the decoded byte string. The * has sufficient space to store the decoded byte string.
* memory areas pointed by :member:`dest->base <sfparse_vec.base>` and *
* :member:`src->base <sfparse_vec.base>` must not overlap. * If :member:`src->len <sf_vec.len>` == 0, |*src| is assigned to
* |*dest|.
* *
* This function sets the length of decoded byte string to * This function sets the length of decoded byte string to
* :member:`dest->len <sfparse_vec.len>`. * :member:`dest->len <sf_vec.len>`.
*/ */
void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src); void sf_base64decode(sf_vec *dest, const sf_vec *src);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* defined(__cplusplus) */ #endif
#endif /* !defined(SFPARSE_H) */ #endif /* SFPARSE_H */

5
script/CMakeLists.txt Normal file
View File

@@ -0,0 +1,5 @@
# EXTRA_DIST = README.rst
install(
PROGRAMS fetch-ocsp-response
DESTINATION "${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}"
)

25
script/Makefile.am Normal file
View File

@@ -0,0 +1,25 @@
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2015 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
EXTRA_DIST = README.rst CMakeLists.txt
dist_pkgdata_SCRIPTS = fetch-ocsp-response

10
script/README.rst Normal file
View File

@@ -0,0 +1,10 @@
fetch-ocsp-response is a Python script which performs OCSP query and
get response. It uses openssl command under the hood. nghttpx uses
it to enable OCSP stapling feature.
fetch-ocsp-response is a translation from original fetch-ocsp-response
written in Perl and which has been developed as part of h2o project
(https://github.com/h2o/h2o).
fetch-ocsp-response is usually installed under $(pkgdatadir), which is
$(prefix)/share/nghttp2.

253
script/fetch-ocsp-response Executable file
View File

@@ -0,0 +1,253 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2015 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# This program was translated from the program originally developed by
# h2o project (https://github.com/h2o/h2o), written in Perl. It had
# the following copyright notice:
# Copyright (c) 2015 DeNA Co., Ltd.
#
# 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.
from __future__ import unicode_literals
import argparse
import io
import os
import os.path
import re
import shutil
import subprocess
import sys
import tempfile
# make this program work for both Python 3 and Python 2.
try:
from urllib.parse import urlparse
stdout_bwrite = sys.stdout.buffer.write
except ImportError:
from urlparse import urlparse
stdout_bwrite = sys.stdout.write
def die(msg):
sys.stderr.write(msg)
sys.stderr.write('\n')
sys.exit(255)
def tempfail(msg):
sys.stderr.write(msg)
sys.stderr.write('\n')
sys.exit(os.EX_TEMPFAIL)
def run_openssl(args, allow_tempfail=False):
buf = io.BytesIO()
try:
p = subprocess.Popen(args, stdout=subprocess.PIPE)
except Exception as e:
die('failed to invoke {}:{}'.format(args, e))
try:
while True:
data = p.stdout.read()
if len(data) == 0:
break
buf.write(data)
if p.wait() != 0:
raise Exception('nonzero return code {}'.format(p.returncode))
return buf.getvalue()
except Exception as e:
msg = 'OpenSSL exited abnormally: {}:{}'.format(args, e)
tempfail(msg) if allow_tempfail else die(msg)
def read_file(path):
with open(path, 'rb') as f:
return f.read()
def write_file(path, data):
with open(path, 'wb') as f:
f.write(data)
def detect_openssl_version(cmd):
return run_openssl([cmd, 'version']).decode('utf-8').strip()
def extract_ocsp_uri(cmd, cert_fn):
# obtain ocsp uri
ocsp_uri = run_openssl(
[cmd, 'x509', '-in', cert_fn, '-noout',
'-ocsp_uri']).decode('utf-8').strip()
if not re.match(r'^https?://', ocsp_uri):
die('failed to extract ocsp URI from {}'.format(cert_fn))
return ocsp_uri
def save_issuer_certificate(issuer_fn, cert_fn):
# save issuer certificate
chain = read_file(cert_fn).decode('utf-8')
m = re.match(
r'.*?-----END CERTIFICATE-----.*?(-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----)',
chain, re.DOTALL)
if not m:
die('--issuer option was not used, and failed to extract issuer certificate from the certificate')
write_file(issuer_fn, (m.group(1) + '\n').encode('utf-8'))
def send_and_receive_ocsp(respder_fn, cmd, cert_fn, issuer_fn, ocsp_uri,
ocsp_host, openssl_version):
# obtain response (without verification)
sys.stderr.write('sending OCSP request to {}\n'.format(ocsp_uri))
args = [
cmd, 'ocsp', '-issuer', issuer_fn, '-cert', cert_fn, '-url', ocsp_uri,
'-noverify', '-respout', respder_fn
]
ver = openssl_version.lower()
if ver.startswith('openssl 1.0.') or ver.startswith('libressl '):
args.extend(['-header', 'Host', ocsp_host])
resp = run_openssl(args, allow_tempfail=True)
return resp.decode('utf-8')
def verify_response(cmd, tempdir, issuer_fn, respder_fn):
# verify the response
sys.stderr.write('verifying the response signature\n')
verify_fn = os.path.join(tempdir, 'verify.out')
# try from exotic options
allextra = [
# for comodo
['-VAfile', issuer_fn],
# these options are only available in OpenSSL >= 1.0.2
['-partial_chain', '-trusted_first', '-CAfile', issuer_fn],
# for OpenSSL <= 1.0.1
['-CAfile', issuer_fn],
]
for extra in allextra:
with open(verify_fn, 'w+b') as f:
args = [cmd, 'ocsp', '-respin', respder_fn]
args.extend(extra)
p = subprocess.Popen(args, stdout=f, stderr=f)
if p.wait() == 0:
# OpenSSL <= 1.0.1, openssl ocsp still returns exit
# code 0 even if verification was failed. So check
# the error message in stderr output.
f.seek(0)
if f.read().decode('utf-8').find(
'Response Verify Failure') != -1:
continue
sys.stderr.write('verify OK (used: {})\n'.format(extra))
return True
sys.stderr.write(read_file(verify_fn).decode('utf-8'))
return False
def fetch_ocsp_response(cmd, cert_fn, tempdir, issuer_fn=None):
openssl_version = detect_openssl_version(cmd)
sys.stderr.write(
'fetch-ocsp-response (using {})\n'.format(openssl_version))
ocsp_uri = extract_ocsp_uri(cmd, cert_fn)
ocsp_host = urlparse(ocsp_uri).netloc
if not issuer_fn:
issuer_fn = os.path.join(tempdir, 'issuer.crt')
save_issuer_certificate(issuer_fn, cert_fn)
respder_fn = os.path.join(tempdir, 'resp.der')
resp = send_and_receive_ocsp(
respder_fn, cmd, cert_fn, issuer_fn, ocsp_uri, ocsp_host,
openssl_version)
sys.stderr.write('{}\n'.format(resp))
# OpenSSL 1.0.2 still returns exit code 0 even if ocsp responder
# returned error status (e.g., trylater(3))
if resp.find('Responder Error:') != -1:
raise Exception('responder returned error')
if not verify_response(cmd, tempdir, issuer_fn, respder_fn):
tempfail('failed to verify the response')
# success
res = read_file(respder_fn)
stdout_bwrite(res)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description=
'''The command issues an OCSP request for given server certificate, verifies the response and prints the resulting DER.''',
epilog=
'''The command exits 0 if successful, or 75 (EX_TEMPFAIL) on temporary error. Other exit codes may be returned in case of hard errors.''')
parser.add_argument(
'--issuer',
metavar='FILE',
help=
'issuer certificate (if omitted, is extracted from the certificate chain)')
parser.add_argument('--openssl',
metavar='CMD',
help='openssl command to use (default: "openssl")',
default='openssl')
parser.add_argument('certificate',
help='path to certificate file to validate')
args = parser.parse_args()
tempdir = None
try:
# Python3.2 has tempfile.TemporaryDirectory, which has nice
# feature to delete its tree by cleanup() function. We have
# to support Python2.7, so we have to do this manually.
tempdir = tempfile.mkdtemp()
fetch_ocsp_response(args.openssl, args.certificate, tempdir,
args.issuer)
finally:
if tempdir:
shutil.rmtree(tempdir)

View File

@@ -7,7 +7,7 @@ set_source_files_properties(${cxx_sources} PROPERTIES
include_directories( include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/includes" "${CMAKE_CURRENT_SOURCE_DIR}/includes"
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party/urlparse" "${CMAKE_CURRENT_SOURCE_DIR}/../third-party"
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party/llhttp/include" "${CMAKE_CURRENT_SOURCE_DIR}/../third-party/llhttp/include"
${JEMALLOC_INCLUDE_DIRS} ${JEMALLOC_INCLUDE_DIRS}
@@ -16,11 +16,7 @@ include_directories(
${LIBNGHTTP3_INCLUDE_DIRS} ${LIBNGHTTP3_INCLUDE_DIRS}
${LIBNGTCP2_INCLUDE_DIRS} ${LIBNGTCP2_INCLUDE_DIRS}
${LIBNGTCP2_CRYPTO_QUICTLS_INCLUDE_DIRS} ${LIBNGTCP2_CRYPTO_QUICTLS_INCLUDE_DIRS}
${LIBNGTCP2_CRYPTO_LIBRESSL_INCLUDE_DIRS}
${LIBNGTCP2_CRYPTO_WOLFSSL_INCLUDE_DIRS}
${LIBNGTCP2_CRYPTO_OSSL_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS}
${WOLFSSL_INCLUDE_DIRS}
${LIBCARES_INCLUDE_DIRS} ${LIBCARES_INCLUDE_DIRS}
${JANSSON_INCLUDE_DIRS} ${JANSSON_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS}
@@ -38,11 +34,7 @@ link_libraries(
${LIBNGHTTP3_LIBRARIES} ${LIBNGHTTP3_LIBRARIES}
${LIBNGTCP2_LIBRARIES} ${LIBNGTCP2_LIBRARIES}
${LIBNGTCP2_CRYPTO_QUICTLS_LIBRARIES} ${LIBNGTCP2_CRYPTO_QUICTLS_LIBRARIES}
${LIBNGTCP2_CRYPTO_LIBRESSL_LIBRARIES}
${LIBNGTCP2_CRYPTO_WOLFSSL_LIBRARIES}
${LIBNGTCP2_CRYPTO_OSSL_LIBRARIES}
${OPENSSL_LIBRARIES} ${OPENSSL_LIBRARIES}
${WOLFSSL_LIBRARIES}
${LIBCARES_LIBRARIES} ${LIBCARES_LIBRARIES}
${JANSSON_LIBRARIES} ${JANSSON_LIBRARIES}
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
@@ -89,6 +81,7 @@ if(ENABLE_APP)
list(APPEND H2LOAD_SOURCES list(APPEND H2LOAD_SOURCES
h2load_http3_session.cc h2load_http3_session.cc
h2load_quic.cc h2load_quic.cc
quic.cc
) )
endif() endif()
@@ -128,6 +121,7 @@ if(ENABLE_APP)
shrpx_api_downstream_connection.cc shrpx_api_downstream_connection.cc
shrpx_health_monitor_downstream_connection.cc shrpx_health_monitor_downstream_connection.cc
shrpx_null_downstream_connection.cc shrpx_null_downstream_connection.cc
shrpx_exec.cc
shrpx_dns_resolver.cc shrpx_dns_resolver.cc
shrpx_dual_dns_resolver.cc shrpx_dual_dns_resolver.cc
shrpx_dns_tracker.cc shrpx_dns_tracker.cc
@@ -149,7 +143,7 @@ if(ENABLE_APP)
shrpx_quic_connection_handler.cc shrpx_quic_connection_handler.cc
shrpx_http3_upstream.cc shrpx_http3_upstream.cc
http3.cc http3.cc
siphash.cc quic.cc
) )
endif() endif()
add_library(nghttpx_static STATIC ${NGHTTPX_SRCS}) add_library(nghttpx_static STATIC ${NGHTTPX_SRCS})
@@ -173,59 +167,54 @@ if(ENABLE_APP)
target_link_libraries(nghttpx_static neverbleed) target_link_libraries(nghttpx_static neverbleed)
endif() endif()
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) set(NGHTTPX_UNITTEST_SOURCES
set(NGHTTPX_UNITTEST_SOURCES shrpx-unittest.cc
shrpx-unittest.cc shrpx_tls_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 shrpx_http_test.cc
shrpx_http_test.cc shrpx_router_test.cc
shrpx_router_test.cc http2_test.cc
http2_test.cc util_test.cc
util_test.cc nghttp2_gzip_test.c
nghttp2_gzip_test.c nghttp2_gzip.c
nghttp2_gzip.c buffer_test.cc
buffer_test.cc memchunk_test.cc
memchunk_test.cc template_test.cc
template_test.cc base64_test.cc
base64_test.cc ${CMAKE_SOURCE_DIR}/tests/munit/munit.c
${CMAKE_SOURCE_DIR}/tests/munit/munit.c )
add_executable(nghttpx-unittest EXCLUDE_FROM_ALL
${NGHTTPX_UNITTEST_SOURCES}
$<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:url-parser>
) )
if(ENABLE_HTTP3) target_include_directories(nghttpx-unittest PRIVATE
list(APPEND NGHTTPX_UNITTEST_SOURCES siphash_test.cc) ${CMAKE_SOURCE_DIR}/tests/munit
endif() )
add_executable(nghttpx-unittest EXCLUDE_FROM_ALL target_compile_definitions(nghttpx-unittest
${NGHTTPX_UNITTEST_SOURCES} PRIVATE "-DNGHTTP2_SRC_DIR=\"${CMAKE_SOURCE_DIR}/src\""
$<TARGET_OBJECTS:llhttp> )
$<TARGET_OBJECTS:urlparse> target_link_libraries(nghttpx-unittest nghttpx_static)
) if(HAVE_MRUBY)
target_include_directories(nghttpx-unittest PRIVATE target_link_libraries(nghttpx-unittest mruby-lib)
${CMAKE_SOURCE_DIR}/tests/munit endif()
) if(HAVE_NEVERBLEED)
target_compile_definitions(nghttpx-unittest target_link_libraries(nghttpx-unittest neverbleed)
PRIVATE "-DNGHTTP2_SRC_DIR=\"${CMAKE_SOURCE_DIR}/src\""
)
target_link_libraries(nghttpx-unittest nghttpx_static)
if(HAVE_MRUBY)
target_link_libraries(nghttpx-unittest mruby-lib)
endif()
if(HAVE_NEVERBLEED)
target_link_libraries(nghttpx-unittest neverbleed)
endif()
add_test(nghttpx-unittest nghttpx-unittest)
add_dependencies(check nghttpx-unittest)
endif() endif()
add_test(nghttpx-unittest nghttpx-unittest)
add_dependencies(check nghttpx-unittest)
add_executable(nghttp ${NGHTTP_SOURCES} $<TARGET_OBJECTS:llhttp> add_executable(nghttp ${NGHTTP_SOURCES} $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:urlparse> $<TARGET_OBJECTS:url-parser>
) )
add_executable(nghttpd ${NGHTTPD_SOURCES} $<TARGET_OBJECTS:llhttp> add_executable(nghttpd ${NGHTTPD_SOURCES} $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:urlparse> $<TARGET_OBJECTS:url-parser>
) )
add_executable(nghttpx ${NGHTTPX-bin_SOURCES} $<TARGET_OBJECTS:llhttp> add_executable(nghttpx ${NGHTTPX-bin_SOURCES} $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:urlparse> $<TARGET_OBJECTS:url-parser>
) )
target_compile_definitions(nghttpx PRIVATE target_compile_definitions(nghttpx PRIVATE
"-DPKGDATADIR=\"${PKGDATADIR}\"" "-DPKGDATADIR=\"${PKGDATADIR}\""
@@ -233,7 +222,7 @@ if(ENABLE_APP)
) )
target_link_libraries(nghttpx nghttpx_static) target_link_libraries(nghttpx nghttpx_static)
add_executable(h2load ${H2LOAD_SOURCES} $<TARGET_OBJECTS:llhttp> add_executable(h2load ${H2LOAD_SOURCES} $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:urlparse> $<TARGET_OBJECTS:url-parser>
) )
install(TARGETS nghttp nghttpd nghttpx h2load) install(TARGETS nghttp nghttpd nghttpx h2load)

View File

@@ -31,36 +31,38 @@
namespace nghttp2 { namespace nghttp2 {
ParserData::ParserData(const std::string &base_uri) ParserData::ParserData(const std::string &base_uri)
: base_uri(base_uri), inside_head(0) {} : base_uri(base_uri), inside_head(0) {}
HtmlParser::HtmlParser(const std::string &base_uri) HtmlParser::HtmlParser(const std::string &base_uri)
: base_uri_(base_uri), parser_ctx_(nullptr), parser_data_(base_uri) {} : base_uri_(base_uri), parser_ctx_(nullptr), parser_data_(base_uri) {}
HtmlParser::~HtmlParser() { htmlFreeParserCtxt(parser_ctx_); } HtmlParser::~HtmlParser() { htmlFreeParserCtxt(parser_ctx_); }
namespace { namespace {
std::string_view get_attr(const xmlChar **attrs, const std::string_view &name) { StringRef get_attr(const xmlChar **attrs, const StringRef &name) {
if (attrs == nullptr) { if (attrs == nullptr) {
return ""sv; return StringRef{};
} }
for (; *attrs; attrs += 2) { for (; *attrs; attrs += 2) {
if (util::strieq(std::string_view{reinterpret_cast<const char *>(attrs[0])}, if (util::strieq(StringRef{attrs[0], strlen(reinterpret_cast<const char *>(
attrs[0]))},
name)) { name)) {
return std::string_view{reinterpret_cast<const char *>(attrs[1])}; return StringRef{attrs[1],
strlen(reinterpret_cast<const char *>(attrs[1]))};
} }
} }
return ""sv; return StringRef{};
} }
} // namespace } // namespace
namespace { namespace {
ResourceType ResourceType
get_resource_type_for_preload_as(const std::string_view &attribute_value) { get_resource_type_for_preload_as(const StringRef &attribute_value) {
if (util::strieq("image"sv, attribute_value)) { if (util::strieq("image"_sr, attribute_value)) {
return REQ_IMG; return REQ_IMG;
} else if (util::strieq("style"sv, attribute_value)) { } else if (util::strieq("style"_sr, attribute_value)) {
return REQ_CSS; return REQ_CSS;
} else if (util::strieq("script"sv, attribute_value)) { } else if (util::strieq("script"_sr, attribute_value)) {
return REQ_UNBLOCK_JS; return REQ_UNBLOCK_JS;
} else { } else {
return REQ_OTHERS; return REQ_OTHERS;
@@ -69,15 +71,15 @@ get_resource_type_for_preload_as(const std::string_view &attribute_value) {
} // namespace } // namespace
namespace { namespace {
void add_link(ParserData *parser_data, const std::string_view &uri, void add_link(ParserData *parser_data, const StringRef &uri,
ResourceType res_type) { ResourceType res_type) {
auto u = xmlBuildURI( auto u = xmlBuildURI(
reinterpret_cast<const xmlChar *>(uri.data()), reinterpret_cast<const xmlChar *>(uri.data()),
reinterpret_cast<const xmlChar *>(parser_data->base_uri.c_str())); reinterpret_cast<const xmlChar *>(parser_data->base_uri.c_str()));
if (u) { if (u) {
parser_data->links.push_back( parser_data->links.push_back(
std::make_pair(reinterpret_cast<char *>(u), res_type)); std::make_pair(reinterpret_cast<char *>(u), res_type));
xmlFree(u); free(u);
} }
} }
} // namespace } // namespace
@@ -86,36 +88,37 @@ namespace {
void start_element_func(void *user_data, const xmlChar *src_name, void start_element_func(void *user_data, const xmlChar *src_name,
const xmlChar **attrs) { const xmlChar **attrs) {
auto parser_data = static_cast<ParserData *>(user_data); auto parser_data = static_cast<ParserData *>(user_data);
auto name = std::string_view{reinterpret_cast<const char *>(src_name)}; auto name =
if (util::strieq("head"sv, name)) { StringRef{src_name, strlen(reinterpret_cast<const char *>(src_name))};
if (util::strieq("head"_sr, name)) {
++parser_data->inside_head; ++parser_data->inside_head;
} }
if (util::strieq("link"sv, name)) { if (util::strieq("link"_sr, name)) {
auto rel_attr = get_attr(attrs, "rel"sv); auto rel_attr = get_attr(attrs, "rel"_sr);
auto href_attr = get_attr(attrs, "href"sv); auto href_attr = get_attr(attrs, "href"_sr);
if (rel_attr.empty() || href_attr.empty()) { if (rel_attr.empty() || href_attr.empty()) {
return; return;
} }
if (util::strieq("shortcut icon"sv, rel_attr)) { if (util::strieq("shortcut icon"_sr, rel_attr)) {
add_link(parser_data, href_attr, REQ_OTHERS); add_link(parser_data, href_attr, REQ_OTHERS);
} else if (util::strieq("stylesheet"sv, rel_attr)) { } else if (util::strieq("stylesheet"_sr, rel_attr)) {
add_link(parser_data, href_attr, REQ_CSS); add_link(parser_data, href_attr, REQ_CSS);
} else if (util::strieq("preload"sv, rel_attr)) { } else if (util::strieq("preload"_sr, rel_attr)) {
auto as_attr = get_attr(attrs, "as"sv); auto as_attr = get_attr(attrs, "as"_sr);
if (as_attr.empty()) { if (as_attr.empty()) {
return; return;
} }
add_link(parser_data, href_attr, add_link(parser_data, href_attr,
get_resource_type_for_preload_as(as_attr)); get_resource_type_for_preload_as(as_attr));
} }
} else if (util::strieq("img"sv, name)) { } else if (util::strieq("img"_sr, name)) {
auto src_attr = get_attr(attrs, "src"sv); auto src_attr = get_attr(attrs, "src"_sr);
if (src_attr.empty()) { if (src_attr.empty()) {
return; return;
} }
add_link(parser_data, src_attr, REQ_IMG); add_link(parser_data, src_attr, REQ_IMG);
} else if (util::strieq("script"sv, name)) { } else if (util::strieq("script"_sr, name)) {
auto src_attr = get_attr(attrs, "src"sv); auto src_attr = get_attr(attrs, "src"_sr);
if (src_attr.empty()) { if (src_attr.empty()) {
return; return;
} }
@@ -131,8 +134,9 @@ void start_element_func(void *user_data, const xmlChar *src_name,
namespace { namespace {
void end_element_func(void *user_data, const xmlChar *name) { void end_element_func(void *user_data, const xmlChar *name) {
auto parser_data = static_cast<ParserData *>(user_data); auto parser_data = static_cast<ParserData *>(user_data);
if (util::strieq("head"sv, if (util::strieq(
std::string_view{reinterpret_cast<const char *>(name)})) { "head"_sr,
StringRef{name, strlen(reinterpret_cast<const char *>(name))})) {
--parser_data->inside_head; --parser_data->inside_head;
} }
} }
@@ -140,46 +144,46 @@ void end_element_func(void *user_data, const xmlChar *name) {
namespace { namespace {
xmlSAXHandler saxHandler = { xmlSAXHandler saxHandler = {
nullptr, // internalSubsetSAXFunc nullptr, // internalSubsetSAXFunc
nullptr, // isStandaloneSAXFunc nullptr, // isStandaloneSAXFunc
nullptr, // hasInternalSubsetSAXFunc nullptr, // hasInternalSubsetSAXFunc
nullptr, // hasExternalSubsetSAXFunc nullptr, // hasExternalSubsetSAXFunc
nullptr, // resolveEntitySAXFunc nullptr, // resolveEntitySAXFunc
nullptr, // getEntitySAXFunc nullptr, // getEntitySAXFunc
nullptr, // entityDeclSAXFunc nullptr, // entityDeclSAXFunc
nullptr, // notationDeclSAXFunc nullptr, // notationDeclSAXFunc
nullptr, // attributeDeclSAXFunc nullptr, // attributeDeclSAXFunc
nullptr, // elementDeclSAXFunc nullptr, // elementDeclSAXFunc
nullptr, // unparsedEntityDeclSAXFunc nullptr, // unparsedEntityDeclSAXFunc
nullptr, // setDocumentLocatorSAXFunc nullptr, // setDocumentLocatorSAXFunc
nullptr, // startDocumentSAXFunc nullptr, // startDocumentSAXFunc
nullptr, // endDocumentSAXFunc nullptr, // endDocumentSAXFunc
&start_element_func, // startElementSAXFunc &start_element_func, // startElementSAXFunc
&end_element_func, // endElementSAXFunc &end_element_func, // endElementSAXFunc
nullptr, // referenceSAXFunc nullptr, // referenceSAXFunc
nullptr, // charactersSAXFunc nullptr, // charactersSAXFunc
nullptr, // ignorableWhitespaceSAXFunc nullptr, // ignorableWhitespaceSAXFunc
nullptr, // processingInstructionSAXFunc nullptr, // processingInstructionSAXFunc
nullptr, // commentSAXFunc nullptr, // commentSAXFunc
nullptr, // warningSAXFunc nullptr, // warningSAXFunc
nullptr, // errorSAXFunc nullptr, // errorSAXFunc
nullptr, // fatalErrorSAXFunc nullptr, // fatalErrorSAXFunc
nullptr, // getParameterEntitySAXFunc nullptr, // getParameterEntitySAXFunc
nullptr, // cdataBlockSAXFunc nullptr, // cdataBlockSAXFunc
nullptr, // externalSubsetSAXFunc nullptr, // externalSubsetSAXFunc
0, // unsigned int initialized 0, // unsigned int initialized
nullptr, // void * _private nullptr, // void * _private
nullptr, // startElementNsSAX2Func nullptr, // startElementNsSAX2Func
nullptr, // endElementNsSAX2Func nullptr, // endElementNsSAX2Func
nullptr, // xmlStructuredErrorFunc nullptr, // xmlStructuredErrorFunc
}; };
} // namespace } // namespace
int HtmlParser::parse_chunk(const char *chunk, size_t size, int fin) { int HtmlParser::parse_chunk(const char *chunk, size_t size, int fin) {
if (!parser_ctx_) { if (!parser_ctx_) {
parser_ctx_ = htmlCreatePushParserCtxt( parser_ctx_ =
&saxHandler, &parser_data_, chunk, static_cast<int>(size), htmlCreatePushParserCtxt(&saxHandler, &parser_data_, chunk, size,
base_uri_.c_str(), XML_CHAR_ENCODING_NONE); base_uri_.c_str(), XML_CHAR_ENCODING_NONE);
if (!parser_ctx_) { if (!parser_ctx_) {
return -1; return -1;
} else { } else {
@@ -195,7 +199,7 @@ int HtmlParser::parse_chunk(const char *chunk, size_t size, int fin) {
} }
int HtmlParser::parse_chunk_internal(const char *chunk, size_t size, int fin) { int HtmlParser::parse_chunk_internal(const char *chunk, size_t size, int fin) {
int rv = htmlParseChunk(parser_ctx_, chunk, static_cast<int>(size), fin); int rv = htmlParseChunk(parser_ctx_, chunk, size, fin);
if (rv == 0) { if (rv == 0) {
return 0; return 0;
} else { } else {

File diff suppressed because it is too large Load Diff

View File

@@ -34,17 +34,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <unordered_map> #include <map>
#include <memory> #include <memory>
#include "ssl_compat.h" #include <openssl/ssl.h>
#ifdef NGHTTP2_OPENSSL_IS_WOLFSSL
# include <wolfssl/options.h>
# include <wolfssl/openssl/ssl.h>
#else // !NGHTTP2_OPENSSL_IS_WOLFSSL
# include <openssl/ssl.h>
#endif // !NGHTTP2_OPENSSL_IS_WOLFSSL
#include <ev.h> #include <ev.h>
@@ -59,8 +52,8 @@
namespace nghttp2 { namespace nghttp2 {
struct Config { struct Config {
std::unordered_map<std::string, std::vector<std::string>> push; std::map<std::string, std::vector<std::string>> push;
std::unordered_map<std::string, std::string> mime_types; std::map<std::string, std::string> mime_types;
Headers trailer; Headers trailer;
std::string trailer_names; std::string trailer_names;
std::string htdocs; std::string htdocs;
@@ -91,6 +84,7 @@ struct Config {
bool echo_upload; bool echo_upload;
bool no_content_length; bool no_content_length;
bool ktls; bool ktls;
bool no_rfc7540_pri;
Config(); Config();
~Config(); ~Config();
}; };
@@ -102,18 +96,18 @@ struct FileEntry {
const std::string *content_type, const std::string *content_type,
const std::chrono::steady_clock::time_point &last_valid, const std::chrono::steady_clock::time_point &last_valid,
bool stale = false) bool stale = false)
: path(std::move(path)), : path(std::move(path)),
length(length), length(length),
mtime(mtime), mtime(mtime),
last_valid(last_valid), last_valid(last_valid),
content_type(content_type), content_type(content_type),
dlnext(nullptr), dlnext(nullptr),
dlprev(nullptr), dlprev(nullptr),
fd(fd), fd(fd),
usecount(1), usecount(1),
stale(stale) {} stale(stale) {}
std::string path; std::string path;
std::unordered_multimap<std::string, std::unique_ptr<FileEntry>>::iterator it; std::multimap<std::string, std::unique_ptr<FileEntry>>::iterator it;
int64_t length; int64_t length;
int64_t mtime; int64_t mtime;
std::chrono::steady_clock::time_point last_valid; std::chrono::steady_clock::time_point last_valid;
@@ -125,13 +119,13 @@ struct FileEntry {
}; };
struct RequestHeader { struct RequestHeader {
std::string_view method; StringRef method;
std::string_view scheme; StringRef scheme;
std::string_view authority; StringRef authority;
std::string_view host; StringRef host;
std::string_view path; StringRef path;
std::string_view ims; StringRef ims;
std::string_view expect; StringRef expect;
struct { struct {
nghttp2_rcbuf *method; nghttp2_rcbuf *method;
@@ -176,21 +170,21 @@ public:
int connection_made(); int connection_made();
int verify_alpn_result(); int verify_alpn_result();
int submit_file_response(const std::string_view &status, Stream *stream, int submit_file_response(const StringRef &status, Stream *stream,
time_t last_modified, off_t file_length, time_t last_modified, off_t file_length,
const std::string *content_type, const std::string *content_type,
nghttp2_data_provider2 *data_prd); nghttp2_data_provider2 *data_prd);
int submit_response(const std::string_view &status, int32_t stream_id, int submit_response(const StringRef &status, int32_t stream_id,
nghttp2_data_provider2 *data_prd); nghttp2_data_provider2 *data_prd);
int submit_response(const std::string_view &status, int32_t stream_id, int submit_response(const StringRef &status, int32_t stream_id,
const HeaderRefs &headers, const HeaderRefs &headers,
nghttp2_data_provider2 *data_prd); nghttp2_data_provider2 *data_prd);
int submit_non_final_response(const std::string &status, int32_t stream_id); int submit_non_final_response(const std::string &status, int32_t stream_id);
int submit_push_promise(Stream *stream, const std::string_view &push_path); int submit_push_promise(Stream *stream, const StringRef &push_path);
int submit_rst_stream(Stream *stream, uint32_t error_code); int submit_rst_stream(Stream *stream, uint32_t error_code);
@@ -221,7 +215,7 @@ private:
ev_io wev_; ev_io wev_;
ev_io rev_; ev_io rev_;
ev_timer settings_timerev_; ev_timer settings_timerev_;
std::unordered_map<int32_t, std::unique_ptr<Stream>> id2stream_; std::map<int32_t, std::unique_ptr<Stream>> id2stream_;
WriteBuf wb_; WriteBuf wb_;
std::function<int(Http2Handler &)> read_, write_; std::function<int(Http2Handler &)> read_, write_;
int64_t session_id_; int64_t session_id_;

View File

@@ -39,19 +39,15 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/lib/includes \ -I$(top_srcdir)/lib/includes \
-I$(top_builddir)/lib/includes \ -I$(top_builddir)/lib/includes \
-I$(top_srcdir)/lib \ -I$(top_srcdir)/lib \
-I$(top_srcdir)/third-party/urlparse \ -I$(top_srcdir)/third-party \
-I$(top_srcdir)/third-party/llhttp/include \ -I$(top_srcdir)/third-party/llhttp/include \
@JEMALLOC_CFLAGS@ \ @JEMALLOC_CFLAGS@ \
@LIBXML2_CFLAGS@ \ @LIBXML2_CFLAGS@ \
@LIBEV_CFLAGS@ \ @LIBEV_CFLAGS@ \
@LIBNGHTTP3_CFLAGS@ \ @LIBNGHTTP3_CFLAGS@ \
@LIBNGTCP2_CRYPTO_WOLFSSL_CFLAGS@ \
@LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@ \ @LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@ \
@LIBNGTCP2_CRYPTO_LIBRESSL_CFLAGS@ \
@LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS@ \ @LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS@ \
@LIBNGTCP2_CRYPTO_OSSL_CFLAGS@ \
@LIBNGTCP2_CFLAGS@ \ @LIBNGTCP2_CFLAGS@ \
@WOLFSSL_CFLAGS@ \
@OPENSSL_CFLAGS@ \ @OPENSSL_CFLAGS@ \
@LIBCARES_CFLAGS@ \ @LIBCARES_CFLAGS@ \
@JANSSON_CFLAGS@ \ @JANSSON_CFLAGS@ \
@@ -64,19 +60,15 @@ AM_CPPFLAGS = \
AM_LDFLAGS = @LIBTOOL_LDFLAGS@ AM_LDFLAGS = @LIBTOOL_LDFLAGS@
LDADD = $(top_builddir)/lib/libnghttp2.la \ LDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/liburlparse.la \ $(top_builddir)/third-party/liburl-parser.la \
$(top_builddir)/third-party/libllhttp.la \ $(top_builddir)/third-party/libllhttp.la \
@JEMALLOC_LIBS@ \ @JEMALLOC_LIBS@ \
@LIBXML2_LIBS@ \ @LIBXML2_LIBS@ \
@LIBEV_LIBS@ \ @LIBEV_LIBS@ \
@LIBNGHTTP3_LIBS@ \ @LIBNGHTTP3_LIBS@ \
@LIBNGTCP2_CRYPTO_WOLFSSL_LIBS@ \
@LIBNGTCP2_CRYPTO_QUICTLS_LIBS@ \ @LIBNGTCP2_CRYPTO_QUICTLS_LIBS@ \
@LIBNGTCP2_CRYPTO_LIBRESSL_LIBS@ \
@LIBNGTCP2_CRYPTO_BORINGSSL_LIBS@ \ @LIBNGTCP2_CRYPTO_BORINGSSL_LIBS@ \
@LIBNGTCP2_CRYPTO_OSSL_LIBS@ \
@LIBNGTCP2_LIBS@ \ @LIBNGTCP2_LIBS@ \
@WOLFSSL_LIBS@ \
@OPENSSL_LIBS@ \ @OPENSSL_LIBS@ \
@LIBCARES_LIBS@ \ @LIBCARES_LIBS@ \
@SYSTEMD_LIBS@ \ @SYSTEMD_LIBS@ \
@@ -125,7 +117,8 @@ h2load_SOURCES = util.cc util.h \
if ENABLE_HTTP3 if ENABLE_HTTP3
h2load_SOURCES += \ h2load_SOURCES += \
h2load_http3_session.cc h2load_http3_session.h \ h2load_http3_session.cc h2load_http3_session.h \
h2load_quic.cc h2load_quic.h h2load_quic.cc h2load_quic.h \
quic.cc quic.h
endif # ENABLE_HTTP3 endif # ENABLE_HTTP3
NGHTTPX_SRCS = \ NGHTTPX_SRCS = \
@@ -169,6 +162,7 @@ NGHTTPX_SRCS = \
shrpx_health_monitor_downstream_connection.cc \ shrpx_health_monitor_downstream_connection.cc \
shrpx_health_monitor_downstream_connection.h \ shrpx_health_monitor_downstream_connection.h \
shrpx_null_downstream_connection.cc shrpx_null_downstream_connection.h \ shrpx_null_downstream_connection.cc shrpx_null_downstream_connection.h \
shrpx_exec.cc shrpx_exec.h \
shrpx_dns_resolver.cc shrpx_dns_resolver.h \ shrpx_dns_resolver.cc shrpx_dns_resolver.h \
shrpx_dual_dns_resolver.cc shrpx_dual_dns_resolver.h \ shrpx_dual_dns_resolver.cc shrpx_dual_dns_resolver.h \
shrpx_dns_tracker.cc shrpx_dns_tracker.h \ shrpx_dns_tracker.cc shrpx_dns_tracker.h \
@@ -191,7 +185,7 @@ NGHTTPX_SRCS += \
shrpx_quic_connection_handler.cc shrpx_quic_connection_handler.h \ shrpx_quic_connection_handler.cc shrpx_quic_connection_handler.h \
shrpx_http3_upstream.cc shrpx_http3_upstream.h \ shrpx_http3_upstream.cc shrpx_http3_upstream.h \
http3.cc http3.h \ http3.cc http3.h \
siphash.cc siphash.h quic.cc quic.h
endif # ENABLE_HTTP3 endif # ENABLE_HTTP3
noinst_LIBRARIES = libnghttpx.a noinst_LIBRARIES = libnghttpx.a
@@ -231,9 +225,6 @@ nghttpx_unittest_SOURCES = shrpx-unittest.cc \
base64_test.cc base64_test.h \ base64_test.cc base64_test.h \
$(top_srcdir)/tests/munit/munit.c $(top_srcdir)/tests/munit/munit.h \ $(top_srcdir)/tests/munit/munit.c $(top_srcdir)/tests/munit/munit.h \
$(top_srcdir)/tests/munit/munitxx.h $(top_srcdir)/tests/munit/munitxx.h
if ENABLE_HTTP3
nghttpx_unittest_SOURCES += siphash_test.cc siphash_test.h
endif # ENABLE_HTTP3
nghttpx_unittest_CPPFLAGS = ${AM_CPPFLAGS} \ nghttpx_unittest_CPPFLAGS = ${AM_CPPFLAGS} \
-I$(top_srcdir)/tests/munit \ -I$(top_srcdir)/tests/munit \
-DNGHTTP2_SRC_DIR=\"$(top_srcdir)/src\" -DNGHTTP2_SRC_DIR=\"$(top_srcdir)/src\"

View File

@@ -34,7 +34,6 @@
#include <cassert> #include <cassert>
#include <utility> #include <utility>
#include <span> #include <span>
#include <algorithm>
#include "template.h" #include "template.h"
@@ -70,20 +69,20 @@ static_assert(sizeof(ChunkHead) == 16);
// |block_size|. // |block_size|.
struct BlockAllocator { struct BlockAllocator {
BlockAllocator(size_t block_size, size_t isolation_threshold) BlockAllocator(size_t block_size, size_t isolation_threshold)
: retain(nullptr), : retain(nullptr),
head(nullptr), head(nullptr),
block_size(block_size), block_size(block_size),
isolation_threshold(std::min(block_size, isolation_threshold)) { isolation_threshold(std::min(block_size, isolation_threshold)) {
assert(isolation_threshold <= block_size); assert(isolation_threshold <= block_size);
} }
~BlockAllocator() { reset(); } ~BlockAllocator() { reset(); }
BlockAllocator(BlockAllocator &&other) noexcept BlockAllocator(BlockAllocator &&other) noexcept
: retain{std::exchange(other.retain, nullptr)}, : retain{std::exchange(other.retain, nullptr)},
head{std::exchange(other.head, nullptr)}, head{std::exchange(other.head, nullptr)},
block_size(other.block_size), block_size(other.block_size),
isolation_threshold(other.isolation_threshold) {} isolation_threshold(other.isolation_threshold) {}
BlockAllocator &operator=(BlockAllocator &&other) noexcept { BlockAllocator &operator=(BlockAllocator &&other) noexcept {
reset(); reset();
@@ -116,7 +115,7 @@ struct BlockAllocator {
mb->next = retain; mb->next = retain;
mb->begin = mb->last = reinterpret_cast<uint8_t *>( mb->begin = mb->last = reinterpret_cast<uint8_t *>(
(reinterpret_cast<intptr_t>(block + sizeof(MemBlock)) + 0xf) & ~0xf); (reinterpret_cast<intptr_t>(block + sizeof(MemBlock)) + 0xf) & ~0xf);
mb->end = mb->begin + size; mb->end = mb->begin + size;
retain = mb; retain = mb;
return mb; return mb;
@@ -147,7 +146,7 @@ struct BlockAllocator {
ch->size = size; ch->size = size;
head->last = reinterpret_cast<uint8_t *>( head->last = reinterpret_cast<uint8_t *>(
(reinterpret_cast<intptr_t>(res + size) + 0xf) & ~0xf); (reinterpret_cast<intptr_t>(res + size) + 0xf) & ~0xf);
return res; return res;
} }
@@ -157,7 +156,7 @@ struct BlockAllocator {
size_t get_alloc_length(void *ptr) { size_t get_alloc_length(void *ptr) {
return reinterpret_cast<ChunkHead *>(static_cast<uint8_t *>(ptr) - return reinterpret_cast<ChunkHead *>(static_cast<uint8_t *>(ptr) -
sizeof(ChunkHead)) sizeof(ChunkHead))
->size; ->size;
} }
// Allocates memory of at least |size| bytes. If |ptr| is nullptr, // Allocates memory of at least |size| bytes. If |ptr| is nullptr,
@@ -180,7 +179,7 @@ struct BlockAllocator {
auto nalloclen = std::max(size + 1, alloclen * 2); auto nalloclen = std::max(size + 1, alloclen * 2);
auto res = alloc(nalloclen); auto res = alloc(nalloclen);
std::ranges::copy_n(p, as_signed(alloclen), static_cast<uint8_t *>(res)); std::copy_n(p, alloclen, static_cast<uint8_t *>(res));
return res; return res;
} }
@@ -196,37 +195,29 @@ struct BlockAllocator {
size_t isolation_threshold; size_t isolation_threshold;
}; };
// Makes a copy of a range [|first|, |last|). The resulting string // Makes a copy of |src|. The resulting string will be
// will be NULL-terminated.
template <std::input_iterator I>
std::string_view make_string_ref(BlockAllocator &alloc, I first, I last) {
auto dst = static_cast<char *>(
alloc.alloc(static_cast<size_t>(std::ranges::distance(first, last) + 1)));
auto p = std::ranges::copy(first, last, dst).out;
*p = '\0';
return std::string_view{dst, p};
}
// Makes a copy of |r| as std::string_view. The resulting string will be
// NULL-terminated. // NULL-terminated.
template <std::ranges::input_range R> template <typename BlockAllocator>
requires(!std::is_array_v<std::remove_cvref_t<R>>) StringRef make_string_ref(BlockAllocator &alloc, const StringRef &src) {
std::string_view make_string_ref(BlockAllocator &alloc, R &&r) { auto dst = static_cast<uint8_t *>(alloc.alloc(src.size() + 1));
return make_string_ref(alloc, std::ranges::begin(r), std::ranges::end(r)); auto p = dst;
p = std::copy(std::begin(src), std::end(src), p);
*p = '\0';
return StringRef{dst, src.size()};
} }
// private function used in concat_string_ref. this is the base // private function used in concat_string_ref. this is the base
// function of concat_string_ref_count(). // function of concat_string_ref_count().
constexpr size_t concat_string_ref_count(size_t acc) { return acc; } inline constexpr size_t concat_string_ref_count(size_t acc) { return acc; }
// private function used in concat_string_ref. This function counts // private function used in concat_string_ref. This function counts
// the sum of length of given arguments. The calculated length is // the sum of length of given arguments. The calculated length is
// accumulated, and passed to the next function. // accumulated, and passed to the next function.
template <std::ranges::input_range R, std::ranges::input_range... Args> template <typename... Args>
requires(!std::is_array_v<std::remove_cvref_t<R>>) constexpr size_t concat_string_ref_count(size_t acc, const StringRef &value,
constexpr size_t concat_string_ref_count(size_t acc, R &&r, Args &&...args) { Args &&...args) {
return concat_string_ref_count(acc + std::ranges::size(r), args...); return concat_string_ref_count(acc + value.size(),
std::forward<Args>(args)...);
} }
// private function used in concat_string_ref. this is the base // private function used in concat_string_ref. this is the base
@@ -237,23 +228,23 @@ inline uint8_t *concat_string_ref_copy(uint8_t *p) { return p; }
// given strings into |p|. |p| is incremented by the copied length, // given strings into |p|. |p| is incremented by the copied length,
// and returned. In the end, return value points to the location one // and returned. In the end, return value points to the location one
// beyond the last byte written. // beyond the last byte written.
template <std::ranges::input_range R, std::ranges::input_range... Args> template <typename... Args>
requires(!std::is_array_v<std::remove_cvref_t<R>>) uint8_t *concat_string_ref_copy(uint8_t *p, const StringRef &value,
uint8_t *concat_string_ref_copy(uint8_t *p, R &&r, Args &&...args) { Args &&...args) {
return concat_string_ref_copy(std::ranges::copy(std::forward<R>(r), p).out, p = std::copy(std::begin(value), std::end(value), p);
std::forward<Args>(args)...); return concat_string_ref_copy(p, std::forward<Args>(args)...);
} }
// Returns the string which is the concatenation of |args| in the // Returns the string which is the concatenation of |args| in the
// given order. The resulting string will be NULL-terminated. // given order. The resulting string will be NULL-terminated.
template <std::ranges::input_range... Args> template <typename BlockAllocator, typename... Args>
std::string_view concat_string_ref(BlockAllocator &alloc, Args &&...args) { StringRef concat_string_ref(BlockAllocator &alloc, Args &&...args) {
auto len = concat_string_ref_count(0, args...); size_t len = concat_string_ref_count(0, std::forward<Args>(args)...);
auto dst = static_cast<uint8_t *>(alloc.alloc(len + 1)); auto dst = static_cast<uint8_t *>(alloc.alloc(len + 1));
auto p = dst; auto p = dst;
p = concat_string_ref_copy(p, std::forward<Args>(args)...); p = concat_string_ref_copy(p, std::forward<Args>(args)...);
*p = '\0'; *p = '\0';
return as_string_view(dst, p); return StringRef{dst, len};
} }
// Returns the string which is the concatenation of |value| and |args| // Returns the string which is the concatenation of |value| and |args|
@@ -262,27 +253,27 @@ std::string_view concat_string_ref(BlockAllocator &alloc, Args &&...args) {
// obtained from alloc.alloc() or alloc.realloc(), and attempts to use // obtained from alloc.alloc() or alloc.realloc(), and attempts to use
// unused memory region by using alloc.realloc(). If value is empty, // unused memory region by using alloc.realloc(). If value is empty,
// then just call concat_string_ref(). // then just call concat_string_ref().
template <std::ranges::input_range... Args> template <typename BlockAllocator, typename... Args>
std::string_view realloc_concat_string_ref(BlockAllocator &alloc, StringRef realloc_concat_string_ref(BlockAllocator &alloc,
const std::string_view &value, const StringRef &value, Args &&...args) {
Args &&...args) {
if (value.empty()) { if (value.empty()) {
return concat_string_ref(alloc, std::forward<Args>(args)...); return concat_string_ref(alloc, std::forward<Args>(args)...);
} }
auto len = value.size() + concat_string_ref_count(0, args...); auto len =
auto dst = static_cast<uint8_t *>(alloc.realloc( value.size() + concat_string_ref_count(0, std::forward<Args>(args)...);
const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(value.data())), auto dst = static_cast<uint8_t *>(
len + 1)); alloc.realloc(const_cast<uint8_t *>(value.byte()), len + 1));
auto p = dst + value.size(); auto p = dst + value.size();
p = concat_string_ref_copy(p, std::forward<Args>(args)...); p = concat_string_ref_copy(p, std::forward<Args>(args)...);
*p = '\0'; *p = '\0';
return as_string_view(dst, p); return StringRef{dst, len};
} }
// Makes an uninitialized buffer with given size. // Makes an uninitialized buffer with given size.
inline std::span<uint8_t> make_byte_ref(BlockAllocator &alloc, size_t size) { template <typename BlockAllocator>
std::span<uint8_t> make_byte_ref(BlockAllocator &alloc, size_t size) {
return {static_cast<uint8_t *>(alloc.alloc(size)), size}; return {static_cast<uint8_t *>(alloc.alloc(size)), size};
} }

View File

@@ -49,6 +49,7 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <set>
#include <iomanip> #include <iomanip>
#include <fstream> #include <fstream>
@@ -118,7 +119,7 @@ std::string strframetype(uint8_t type) {
s += ')'; s += ')';
return s; return s;
} };
} // namespace } // namespace
namespace { namespace {
@@ -328,20 +329,20 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) {
case NGHTTP2_PING: case NGHTTP2_PING:
print_frame_attr_indent(); print_frame_attr_indent();
fprintf(outfile, "(opaque_data=%s)\n", fprintf(outfile, "(opaque_data=%s)\n",
util::format_hex(std::span{frame->ping.opaque_data}).c_str()); util::format_hex(frame->ping.opaque_data).c_str());
break; break;
case NGHTTP2_GOAWAY: case NGHTTP2_GOAWAY:
print_frame_attr_indent(); print_frame_attr_indent();
fprintf( fprintf(outfile,
outfile, "(last_stream_id=%d, error_code=%s(0x%02x), "
"(last_stream_id=%d, error_code=%s(0x%02x), " "opaque_data(%u)=[%s])\n",
"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, static_cast<unsigned int>(frame->goaway.opaque_data_len),
static_cast<unsigned int>(frame->goaway.opaque_data_len), util::ascii_dump(frame->goaway.opaque_data,
util::ascii_dump(frame->goaway.opaque_data, frame->goaway.opaque_data_len) frame->goaway.opaque_data_len)
.c_str()); .c_str());
break; break;
case NGHTTP2_WINDOW_UPDATE: case NGHTTP2_WINDOW_UPDATE:
print_frame_attr_indent(); print_frame_attr_indent();
@@ -367,7 +368,7 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) {
} }
case NGHTTP2_PRIORITY_UPDATE: { case NGHTTP2_PRIORITY_UPDATE: {
auto priority_update = auto priority_update =
static_cast<nghttp2_ext_priority_update *>(frame->ext.payload); static_cast<nghttp2_ext_priority_update *>(frame->ext.payload);
print_frame_attr_indent(); print_frame_attr_indent();
fprintf(outfile, fprintf(outfile,
"(prioritized_stream_id=%d, priority_field_value=[%.*s])\n", "(prioritized_stream_id=%d, priority_field_value=[%.*s])\n",
@@ -440,7 +441,7 @@ int verbose_on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
size_t len, void *user_data) { size_t len, void *user_data) {
print_timer(); print_timer();
auto srecv = auto srecv =
nghttp2_session_get_stream_effective_recv_data_length(session, stream_id); nghttp2_session_get_stream_effective_recv_data_length(session, stream_id);
auto crecv = nghttp2_session_get_effective_recv_data_length(session); auto crecv = nghttp2_session_get_effective_recv_data_length(session);
fprintf(outfile, fprintf(outfile,

View File

@@ -34,6 +34,7 @@
#endif // HAVE_SYS_TIME_H #endif // HAVE_SYS_TIME_H
#include <poll.h> #include <poll.h>
#include <map>
#include <chrono> #include <chrono>
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>

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