Compare commits

..

99 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
c5e087b103 Update bash_completion 2024-03-01 17:04:52 +09:00
Tatsuhiro Tsujikawa
fb65839653 Update manual pages 2024-03-01 17:04:23 +09:00
Tatsuhiro Tsujikawa
1da27af832 Bump package and library versions 2024-03-01 16:59:34 +09:00
Tatsuhiro Tsujikawa
c29ac85281 Update AUTHORS 2024-03-01 16:57:31 +09:00
Tatsuhiro Tsujikawa
1b5fe4a477 clang-format 2024-02-29 17:59:42 +09:00
Tatsuhiro Tsujikawa
cdf01d1af8 Merge pull request #2086 from barracuda156/darwin
Fix build when `AI_NUMERICSERV` is undefined
2024-02-29 17:58:38 +09:00
Sergey Fedorov
2e54284906 shrpx_tls_test.cc: use AI_NUMERICSERV when defined 2024-02-29 02:29:36 +07:00
Sergey Fedorov
b13c97f04f shrpx_config.cc: if undefined, define AI_NUMERICSERV to 0 2024-02-29 02:26:33 +07:00
Tatsuhiro Tsujikawa
c817b2a3e0 Merge pull request #2085 from nghttp2/nghttpx-remove-default-udp-payload-size
nghttpx: Remove SHRPX_QUIC_MAX_UDP_PAYLOAD_SIZE
2024-02-26 18:04:06 +09:00
Tatsuhiro Tsujikawa
a354577eff nghttpx: Remove SHRPX_QUIC_MAX_UDP_PAYLOAD_SIZE
Remove SHRPX_QUIC_MAX_UDP_PAYLOAD_SIZE and just rely on the ngtcp2
default.
2024-02-26 17:41:54 +09:00
Tatsuhiro Tsujikawa
09a95983b9 Merge pull request #2084 from nghttp2/max-pktcnt-fix
src: Deal with the case that send_quantum < max_udp_payload_size
2024-02-26 17:40:29 +09:00
Tatsuhiro Tsujikawa
25d6df290e src: Deal with the case that send_quantum < max_udp_payload_size 2024-02-26 17:15:29 +09:00
Tatsuhiro Tsujikawa
bd9edc8e76 Merge pull request #2083 from nghttp2/apt-get-update
Run apt-get update before install
2024-02-26 17:12:16 +09:00
Tatsuhiro Tsujikawa
b28998694b Run apt-get update before install 2024-02-26 16:50:09 +09:00
Tatsuhiro Tsujikawa
0b5008eee3 Merge pull request #2082 from nghttp2/reuse-evp-cipher-ctx
nghttpx: Reuse EVP_CIPHER_CTX for QUIC connection ID encryption
2024-02-23 19:46:30 +09:00
Tatsuhiro Tsujikawa
a6d128836d nghttpx: Reuse EVP_CIPHER_CTX for QUIC connection ID encryption 2024-02-23 19:24:42 +09:00
Tatsuhiro Tsujikawa
ea4e5cec19 Merge pull request #2081 from nghttp2/fix-mruby-crash
mruby: Exclude mrdb gem which causes nghttpx to crash
2024-02-22 21:51:08 +09:00
Tatsuhiro Tsujikawa
bfeb1ee182 mruby: Exclude mrdb gem which causes nghttpx to crash 2024-02-22 21:35:25 +09:00
Tatsuhiro Tsujikawa
2b28011c86 Merge pull request #2080 from nghttp2/bpf-pre-expand-aes-key
bpf: Pre-expand aes key
2024-02-22 19:21:20 +09:00
Tatsuhiro Tsujikawa
66c5ea2216 bpf: Pre-expand aes key 2024-02-22 18:56:07 +09:00
Tatsuhiro Tsujikawa
66abd8cbd3 Merge pull request #2079 from nghttp2/neverbleed-gnu-source
neverbleed: Define _GNU_SOURCE for pthread_setaffinity_np
2024-02-18 20:04:28 +09:00
Tatsuhiro Tsujikawa
a142e81994 neverbleed: Define _GNU_SOURCE for pthread_setaffinity_np 2024-02-18 19:30:22 +09:00
Tatsuhiro Tsujikawa
97b7012ccd Merge pull request #2078 from nghttp2/mruby-mrbc-rename
mruby: Adopt deprecation of mrbc_ prefix
2024-02-18 19:16:59 +09:00
Tatsuhiro Tsujikawa
39d293551a mruby: Adopt deprecation of mrbc_ prefix 2024-02-18 18:53:39 +09:00
Tatsuhiro Tsujikawa
fe56b875b4 Merge pull request #2077 from nghttp2/bump-ngtcp2
Bump ngtcp2 dependencies
2024-02-18 18:37:39 +09:00
Tatsuhiro Tsujikawa
d1035d439a Bump ngtcp2 dependencies 2024-02-18 18:17:37 +09:00
Tatsuhiro Tsujikawa
532791209e Merge pull request #2076 from nghttp2/h2load-add-sni
h2load: Add --sni option
2024-02-18 17:47:07 +09:00
Tatsuhiro Tsujikawa
ed0b7864d7 h2load: Add --sni option 2024-02-18 17:26:18 +09:00
Tatsuhiro Tsujikawa
d2ca281ca1 Merge pull request #2075 from nghttp2/bump-llhttp
Bump llhttp to 48588093ca4219b5f689acfc9ebea9e4c8c37663
2024-02-16 18:50:10 +09:00
Tatsuhiro Tsujikawa
3792c573cd Bump llhttp to 48588093ca4219b5f689acfc9ebea9e4c8c37663 2024-02-16 17:58:08 +09:00
Tatsuhiro Tsujikawa
ab8ee3fbce Merge pull request #2074 from nghttp2/bump-mruby
Bump mruby to 3.3.0
2024-02-16 17:57:34 +09:00
Tatsuhiro Tsujikawa
c2cfab6d9c Bump mruby to 3.3.0 2024-02-16 17:30:53 +09:00
Tatsuhiro Tsujikawa
a99667350e Merge pull request #2073 from nghttp2/security-policy
Move security policy to GitHub standard location
2024-02-15 22:39:15 +09:00
Tatsuhiro Tsujikawa
053703eeab Move security policy to GitHub standard location 2024-02-15 22:23:10 +09:00
Tatsuhiro Tsujikawa
3a4e26247b Merge pull request #2072 from nghttp2/security
Use GitHub private vulnerability reporting
2024-02-15 21:52:11 +09:00
Tatsuhiro Tsujikawa
a25f19560c Use GitHub private vulnerability reporting 2024-02-15 21:37:55 +09:00
Tatsuhiro Tsujikawa
2af27bb921 Merge pull request #2071 from nghttp2/reconsider-ssize_t-usage-in-src
Reconsider ssize t usage in src
2024-02-15 21:18:19 +09:00
Tatsuhiro Tsujikawa
731c7c0f92 nghttpx: Reconsider ssize_t usage 2024-02-15 20:59:39 +09:00
Tatsuhiro Tsujikawa
b487cf1d19 nghttp: Use size_t where a negative value is not expected 2024-02-15 20:59:38 +09:00
Tatsuhiro Tsujikawa
41a2f6de00 h2load: Use size_t where a negative value is not expected 2024-02-15 20:59:38 +09:00
Tatsuhiro Tsujikawa
075254e5a0 Merge pull request #2070 from nghttp2/src-remove-unused
src: Remove unused functions
2024-02-15 20:03:32 +09:00
Tatsuhiro Tsujikawa
3daa0de1e6 src: Remove unused functions 2024-02-15 19:44:32 +09:00
Tatsuhiro Tsujikawa
972e372402 Merge pull request #2069 from nghttp2/apps-migrate-nghttp2_ssize
Apps migrate nghttp2 ssize
2024-02-15 19:43:16 +09:00
Tatsuhiro Tsujikawa
65c91ba729 h2load: Migrate to nghttp2_ssize API 2024-02-15 19:29:42 +09:00
Tatsuhiro Tsujikawa
3ffade5f8a nghttpx: Migrate to nghttp2_ssize API 2024-02-15 19:29:42 +09:00
Tatsuhiro Tsujikawa
33ad4cc2b8 deflatehd, inflatehd: Migrate to nghttp2_ssize API 2024-02-15 19:29:42 +09:00
Tatsuhiro Tsujikawa
f029a09cef nghttpd: Migrate to nghttp2_ssize API 2024-02-15 19:29:42 +09:00
Tatsuhiro Tsujikawa
9468b16f1e nghttp: Migrate to nghttp2_ssize API 2024-02-15 19:29:42 +09:00
Tatsuhiro Tsujikawa
d4b19d7a5a Merge pull request #2068 from nghttp2/rfc7540-priorities-api-deprecation-plan
Describe RFC 7540 priorities deprecation plan
2024-02-15 19:08:36 +09:00
Tatsuhiro Tsujikawa
632292731f Describe RFC 7540 priorities deprecation plan 2024-02-15 18:50:32 +09:00
Tatsuhiro Tsujikawa
89500e2ab3 Merge pull request #2067 from nghttp2/deprecated-warning-upfront
Move deprecated warning upfront
2024-02-15 18:50:06 +09:00
Tatsuhiro Tsujikawa
bc1c6c07b3 Move deprecated warning upfront 2024-02-15 18:34:19 +09:00
Tatsuhiro Tsujikawa
2fdb959ea1 Merge pull request #2066 from nghttp2/nghttp2_ssize
Introduce nghttp2_ssize API
2024-02-15 18:32:31 +09:00
Tatsuhiro Tsujikawa
93c4d8bc34 Introduce nghttp2_ssize API
This commit deprecates all APIs, including structs and callback
functions, that use ssize_t.  New APIs that use nghttp2_ssize are
added as a replacement.  The usage of ssize_t is problematic for
several reasons.  Some platforms do not define ssize_t.  The minimum
value of ssize_t that POSIX requires is -1 which makes nghttp2 error
code out of range.  nghttp2_ssize is an alias of ptrdiff_t that is in
C standard and covers our error code range.

New code should use new nghttp2_ssize APIs.  The existing applications
should consider migrating to new APIs.

The deprecated ssize_t APIs continue to work for backward
compatibility.

Here is the summary of the deprecated APIs and their replacements:

Callback functions:

- nghttp2_data_source_read_callback => nghttp2_data_source_read_callback2
- nghttp2_data_source_read_length_callback => nghttp2_data_source_read_length_callback2
- nghttp2_pack_extension_callback => nghttp2_pack_extension_callback2
- nghttp2_recv_callback => nghttp2_recv_callback2
- nghttp2_select_padding_callback => nghttp2_select_padding_callback2
- nghttp2_send_callback => nghttp2_send_callback2

Structs:

- nghttp2_data_provider => nghttp2_data_provider2

Functions:

- nghttp2_hd_deflate_hd => nghttp2_hd_deflate_hd2
- nghttp2_hd_deflate_hd_vec => nghttp2_hd_deflate_hd_vec2
- nghttp2_hd_inflate_hd2 => nghttp2_hd_inflate_hd3
- nghttp2_pack_settings_payload => nghttp2_pack_settings_payload2
- nghttp2_session_callbacks_set_data_source_read_length_callback =>
  nghttp2_session_callbacks_set_data_source_read_length_callback2
- nghttp2_session_callbacks_set_pack_extension_callback =>
  nghttp2_session_callbacks_set_pack_extension_callback2
- nghttp2_session_callbacks_set_recv_callback =>
  nghttp2_session_callbacks_set_recv_callback2
- nghttp2_session_callbacks_set_select_padding_callback =>
  nghttp2_session_callbacks_set_select_padding_callback2
- nghttp2_session_callbacks_set_send_callback =>
  nghttp2_session_callbacks_set_send_callback2
- nghttp2_session_mem_recv => nghttp2_session_mem_recv2
- nghttp2_session_mem_send => nghttp2_session_mem_send2
- nghttp2_submit_data => nghttp2_submit_data2
- nghttp2_submit_request => nghttp2_submit_request2
- nghttp2_submit_response => nghttp2_submit_response2

For those applications that do not want to see ssize_t in nghttp2.h
header file, define NGHTTP2_NO_SSIZE_T macro before including
nghttp2.h.  It hides all ssize_t APIs.
2024-02-15 18:19:11 +09:00
Tatsuhiro Tsujikawa
504633eadd Merge pull request #2064 from nghttp2/munit
Munit
2024-02-14 17:53:19 +09:00
Tatsuhiro Tsujikawa
3884aa166e Remove munit dependency from nghttp2_test_helper.h 2024-02-14 17:39:10 +09:00
Tatsuhiro Tsujikawa
ec7abfeabb Merge pull request #2065 from nghttp2/integration-go-omit-unused-params
integration-tests: Omit unused parameters
2024-02-12 16:04:29 +09:00
Tatsuhiro Tsujikawa
de79d05ad9 integration-tests: Omit unused parameters 2024-02-12 14:02:01 +09:00
Tatsuhiro Tsujikawa
8b4fd9bd13 cmake: Disable -Wunused-macros
Disable -Wunused-macros which makes compiling external code quite
hard.
2024-02-12 14:01:35 +09:00
Tatsuhiro Tsujikawa
be8a327258 Migrate to munit from cunit 2024-02-12 14:01:35 +09:00
Tatsuhiro Tsujikawa
58c1e2bb55 Merge pull request #2062 from nghttp2/dependabot/go_modules/golang.org/x/net-0.21.0
build(deps): bump golang.org/x/net from 0.20.0 to 0.21.0
2024-02-09 21:28:39 +09:00
dependabot[bot]
5d0a2f5fdb build(deps): bump golang.org/x/net from 0.20.0 to 0.21.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.20.0 to 0.21.0.
- [Commits](https://github.com/golang/net/compare/v0.20.0...v0.21.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-09 12:06:05 +00:00
Tatsuhiro Tsujikawa
4f5a769d01 Merge pull request #2061 from nghttp2/dependabot-gomod
Let dependabot manage go modules
2024-02-09 21:05:37 +09:00
Tatsuhiro Tsujikawa
8df2c0090d Merge pull request #2060 from nghttp2/deprecate-rfc7540-priorities
Deprecate RFC 7540 priorities (aka stream dependencies)
2024-02-09 19:43:19 +09:00
Tatsuhiro Tsujikawa
c92aabb6e6 Let dependabot manage go modules 2024-02-09 18:48:24 +09:00
Tatsuhiro Tsujikawa
c00c44abbe Deprecate RFC 7540 priorities (aka stream dependencies)
This commit just adds a warning to the related API documents.  The
actual functionality works just like before.
2024-02-09 18:31:57 +09:00
Tatsuhiro Tsujikawa
92582ce519 Merge pull request #2059 from nghttp2/libbrotli-fixup
Libbrotli fixup
2024-02-08 23:03:56 +09:00
Tatsuhiro Tsujikawa
1291b76986 Use auto 2024-02-08 21:24:20 +09:00
Tatsuhiro Tsujikawa
6d291e98e0 Fix bug that libbrotlienc is not enabled 2024-02-08 21:24:20 +09:00
Tatsuhiro Tsujikawa
68498a307c Fix missing '`' 2024-02-08 21:24:20 +09:00
Tatsuhiro Tsujikawa
a7d73d90db cmake: Add missing definitions 2024-02-08 21:24:20 +09:00
Tatsuhiro Tsujikawa
69fd5b557d Add missing : 2024-02-08 18:04:27 +09:00
Tatsuhiro Tsujikawa
3792abd447 Disable libbrotli by default 2024-02-08 18:04:27 +09:00
Tatsuhiro Tsujikawa
d55323e575 Merge pull request #2058 from nghttp2/switch-to-aws-lc
Switch to aws lc
2024-02-08 18:03:14 +09:00
Tatsuhiro Tsujikawa
96104d0895 README.rst: Switch to aws-lc 2024-02-08 17:49:52 +09:00
Tatsuhiro Tsujikawa
2f7dd5ec65 docker: Switch to aws-lc 2024-02-08 17:49:52 +09:00
Tatsuhiro Tsujikawa
8c0fe8f93f Merge pull request #2057 from nghttp2/fix-missing-newline
Fix missing newline
2024-02-07 19:42:55 +09:00
Tatsuhiro Tsujikawa
85ccbd4f95 Fix missing newline 2024-02-07 19:02:12 +09:00
Tatsuhiro Tsujikawa
f3b142293c Merge pull request #2056 from nghttp2/bssl-cert-compression
src: Certificate Compression with boringssl
2024-02-07 19:00:41 +09:00
Tatsuhiro Tsujikawa
4b34dd1965 src: Certificate Compression with boringssl 2024-02-07 18:41:01 +09:00
Tatsuhiro Tsujikawa
4ae7fe91d6 Merge pull request #2054 from nghttp2/fetch-ocsp-response-python3
Run with python3
2024-02-06 23:35:39 +09:00
Tatsuhiro Tsujikawa
41ac5f7e4e Merge pull request #2055 from nghttp2/bssl-ocsp
nghttpx: Set ocsp response to SSL in case of boringssl
2024-02-06 22:56:24 +09:00
Tatsuhiro Tsujikawa
343dbafe7d nghttpx: Set ocsp response to SSL in case of boringssl 2024-02-06 21:27:43 +09:00
Tatsuhiro Tsujikawa
5003886591 Run with python3 2024-02-06 19:42:03 +09:00
Tatsuhiro Tsujikawa
f7de260969 Merge pull request #2052 from nghttp2/dependabot/github_actions/microsoft/setup-msbuild-2
build(deps): bump microsoft/setup-msbuild from 1 to 2
2024-02-06 00:19:13 +09:00
dependabot[bot]
69daeb040c build(deps): bump microsoft/setup-msbuild from 1 to 2
Bumps [microsoft/setup-msbuild](https://github.com/microsoft/setup-msbuild) from 1 to 2.
- [Release notes](https://github.com/microsoft/setup-msbuild/releases)
- [Changelog](https://github.com/microsoft/setup-msbuild/blob/main/building-release.md)
- [Commits](https://github.com/microsoft/setup-msbuild/compare/v1...v2)

---
updated-dependencies:
- dependency-name: microsoft/setup-msbuild
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-05 14:08:27 +00:00
Tatsuhiro Tsujikawa
fdc53b1a76 Merge pull request #2051 from anthonyalayo/feat/fixingBuildInstallTrees
Fixing the build and install trees
2024-02-05 17:12:51 +09:00
Anthony Alayo
b6247f5391 Setting variables for static and shared libs 2024-02-02 18:45:32 -08:00
Anthony Alayo
40983f461e Update CMakeLists.txt 2024-02-02 18:39:04 -08:00
Anthony Alayo
80ba5ad341 Tweaking export 2024-02-02 13:19:29 -08:00
Anthony Alayo
0f3a369e12 Adding export set 2024-02-02 13:04:12 -08:00
Anthony Alayo
d9edee47aa Fixing the build and install trees 2024-02-02 12:21:13 -08:00
Tatsuhiro Tsujikawa
a65b0acd9e Merge pull request #2046 from nghttp2/dependabot/github_actions/actions/cache-4
build(deps): bump actions/cache from 3 to 4
2024-01-23 00:43:32 +09:00
dependabot[bot]
67c2c481ea build(deps): bump actions/cache from 3 to 4
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-22 14:15:13 +00:00
Tatsuhiro Tsujikawa
57c1db3db4 Merge pull request #2044 from nghttp2/speed-up-git-clone
Speed up git clone
2024-01-22 17:43:45 +09:00
Tatsuhiro Tsujikawa
cc963b4862 Speed up git clone 2024-01-22 17:15:32 +09:00
Tatsuhiro Tsujikawa
2bccc5cf70 Merge pull request #2043 from nghttp2/release-speed-up-git-submodule
makerelease.sh: Speed up git submodule
2024-01-21 21:15:29 +09:00
Tatsuhiro Tsujikawa
93404696ac makerelease.sh: Speed up git submodule 2024-01-21 19:50:01 +09:00
Tatsuhiro Tsujikawa
a0fc33ecd5 Bump package version 2024-01-21 19:45:50 +09:00
171 changed files with 11649 additions and 8990 deletions

View File

@@ -4,3 +4,7 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" interval: "weekly"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -7,11 +7,11 @@ permissions: read-all
env: env:
LIBBPF_VERSION: v1.3.0 LIBBPF_VERSION: v1.3.0
OPENSSL1_VERSION: 1_1_1w+quic OPENSSL1_VERSION: 1_1_1w+quic
OPENSSL3_VERSION: 3.1.4+quic OPENSSL3_VERSION: 3.1.5+quic
BORINGSSL_VERSION: f42be90d665b6a376177648ccbb76fbbd6497c13 BORINGSSL_VERSION: 8e6a26d128484b886e6dcbfa558b993d38950bb5
AWSLC_VERSION: v1.20.0 AWSLC_VERSION: v1.21.0
NGHTTP3_VERSION: v1.1.0 NGHTTP3_VERSION: v1.2.0
NGTCP2_VERSION: v1.2.0 NGTCP2_VERSION: v1.3.0
jobs: jobs:
build-cache: build-cache:
@@ -25,26 +25,26 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Restore libbpf cache - name: Restore libbpf cache
id: cache-libbpf id: cache-libbpf
uses: actions/cache@v3 uses: actions/cache@v4
if: runner.os == 'Linux' if: runner.os == 'Linux'
with: with:
path: libbpf/build path: libbpf/build
key: ${{ runner.os }}-libbpf-${{ env.LIBBPF_VERSION }} key: ${{ runner.os }}-libbpf-${{ env.LIBBPF_VERSION }}
- name: Restore OpenSSL v1.1.1 cache - name: Restore OpenSSL v1.1.1 cache
id: cache-openssl1 id: cache-openssl1
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: openssl1/build path: openssl1/build
key: ${{ runner.os }}-openssl-${{ env.OPENSSL1_VERSION }} key: ${{ runner.os }}-openssl-${{ env.OPENSSL1_VERSION }}
- name: Restore OpenSSL v3.x cache - name: Restore OpenSSL v3.x cache
id: cache-openssl3 id: cache-openssl3
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: openssl3/build path: openssl3/build
key: ${{ runner.os }}-openssl-${{ env.OPENSSL3_VERSION }} key: ${{ runner.os }}-openssl-${{ env.OPENSSL3_VERSION }}
- name: Restore BoringSSL cache - name: Restore BoringSSL cache
id: cache-boringssl id: cache-boringssl
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: | path: |
boringssl/build/crypto/libcrypto.a boringssl/build/crypto/libcrypto.a
@@ -53,7 +53,7 @@ jobs:
key: ${{ runner.os }}-boringssl-${{ env.BORINGSSL_VERSION }} key: ${{ runner.os }}-boringssl-${{ env.BORINGSSL_VERSION }}
- name: Restore aws-lc cache - name: Restore aws-lc cache
id: cache-awslc id: cache-awslc
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: | path: |
aws-lc/build/crypto/libcrypto.a aws-lc/build/crypto/libcrypto.a
@@ -62,19 +62,19 @@ jobs:
key: ${{ runner.os }}-awslc-${{ env.AWSLC_VERSION }} key: ${{ runner.os }}-awslc-${{ env.AWSLC_VERSION }}
- name: Restore nghttp3 cache - name: Restore nghttp3 cache
id: cache-nghttp3 id: cache-nghttp3
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: nghttp3/build path: nghttp3/build
key: ${{ runner.os }}-nghttp3-${{ env.NGHTTP3_VERSION }} key: ${{ runner.os }}-nghttp3-${{ env.NGHTTP3_VERSION }}
- name: Restore ngtcp2 + quictls/openssl v1.1.1 cache - name: Restore ngtcp2 + quictls/openssl v1.1.1 cache
id: cache-ngtcp2-openssl1 id: cache-ngtcp2-openssl1
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: ngtcp2-openssl1/build path: ngtcp2-openssl1/build
key: ${{ runner.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL1_VERSION }} key: ${{ runner.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL1_VERSION }}
- name: Restore ngtcp2 + quictls/openssl v3.x cache - name: Restore ngtcp2 + quictls/openssl v3.x cache
id: cache-ngtcp2-openssl3 id: cache-ngtcp2-openssl3
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: ngtcp2-openssl3/build path: ngtcp2-openssl3/build
key: ${{ runner.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL3_VERSION }} key: ${{ runner.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL3_VERSION }}
@@ -93,6 +93,7 @@ jobs:
- name: Linux setup - name: Linux setup
if: runner.os == 'Linux' && steps.settings.outputs.needs-build == 'true' if: runner.os == 'Linux' && steps.settings.outputs.needs-build == 'true'
run: | run: |
sudo apt-get update
sudo apt-get install \ sudo apt-get install \
g++-12 \ g++-12 \
clang-15 \ clang-15 \
@@ -137,8 +138,11 @@ jobs:
- name: Build BoringSSL - name: Build BoringSSL
if: steps.cache-boringssl.outputs.cache-hit != 'true' if: steps.cache-boringssl.outputs.cache-hit != 'true'
run: | run: |
git clone https://boringssl.googlesource.com/boringssl mkdir boringssl
cd boringssl cd boringssl
git init
git remote add origin https://boringssl.googlesource.com/boringssl
git fetch origin --depth 1 ${{ env.BORINGSSL_VERSION }}
git checkout ${{ env.BORINGSSL_VERSION }} git checkout ${{ env.BORINGSSL_VERSION }}
mkdir build mkdir build
cd build cd build
@@ -156,6 +160,7 @@ jobs:
run: | run: |
git clone --depth 1 -b ${{ env.NGHTTP3_VERSION}} https://github.com/ngtcp2/nghttp3 git clone --depth 1 -b ${{ env.NGHTTP3_VERSION}} https://github.com/ngtcp2/nghttp3
cd nghttp3 cd nghttp3
git submodule update --init --depth 1
autoreconf -i autoreconf -i
./configure --prefix=$PWD/build --enable-lib-only ./configure --prefix=$PWD/build --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
@@ -165,6 +170,7 @@ jobs:
run: | run: |
git clone --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl1 git clone --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl1
cd ngtcp2-openssl1 cd ngtcp2-openssl1
git submodule update --init --depth 1
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" \ PKG_CONFIG_PATH="../openssl1/build/lib/pkgconfig" \
@@ -178,6 +184,7 @@ jobs:
run: | run: |
git clone --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl3 git clone --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl3
cd ngtcp2-openssl3 cd ngtcp2-openssl3
git submodule update --init --depth 1
autoreconf -i autoreconf -i
./configure --prefix=$PWD/build --enable-lib-only \ ./configure --prefix=$PWD/build --enable-lib-only \
PKG_CONFIG_PATH="../openssl3/build/lib/pkgconfig" \ PKG_CONFIG_PATH="../openssl3/build/lib/pkgconfig" \
@@ -228,6 +235,7 @@ jobs:
- name: Linux setup - name: Linux setup
if: runner.os == 'Linux' if: runner.os == 'Linux'
run: | run: |
sudo apt-get update
sudo apt-get install \ sudo apt-get install \
g++-12 \ g++-12 \
clang-15 \ clang-15 \
@@ -237,7 +245,6 @@ jobs:
libtool \ libtool \
pkg-config \ pkg-config \
zlib1g-dev \ zlib1g-dev \
libcunit1-dev \
libssl-dev \ libssl-dev \
libxml2-dev \ libxml2-dev \
libev-dev \ libev-dev \
@@ -246,6 +253,7 @@ jobs:
libjemalloc-dev \ libjemalloc-dev \
libc-ares-dev \ libc-ares-dev \
libelf-dev \ libelf-dev \
libbrotli-dev \
cmake \ cmake \
cmake-data cmake-data
echo 'CPPFLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -g' >> $GITHUB_ENV echo 'CPPFLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -g' >> $GITHUB_ENV
@@ -257,8 +265,8 @@ jobs:
libev \ libev \
libevent \ libevent \
c-ares \ c-ares \
cunit \
libressl \ libressl \
brotli \
autoconf \ autoconf \
automake \ automake \
pkg-config \ pkg-config \
@@ -285,7 +293,7 @@ jobs:
echo 'CC=gcc' >> $GITHUB_ENV echo 'CC=gcc' >> $GITHUB_ENV
echo 'CXX=g++' >> $GITHUB_ENV echo 'CXX=g++' >> $GITHUB_ENV
- name: Restore libbpf cache - name: Restore libbpf cache
uses: actions/cache/restore@v3 uses: actions/cache/restore@v4
if: matrix.http3 == 'http3' && matrix.compiler == 'clang' && runner.os == 'Linux' if: matrix.http3 == 'http3' && matrix.compiler == 'clang' && runner.os == 'Linux'
with: with:
path: libbpf/build path: libbpf/build
@@ -302,21 +310,21 @@ jobs:
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: Restore quictls/openssl v1.1.1 cache - name: Restore quictls/openssl v1.1.1 cache
uses: actions/cache/restore@v3 uses: actions/cache/restore@v4
if: matrix.http3 == 'http3' && matrix.openssl == 'openssl1' if: matrix.http3 == 'http3' && matrix.openssl == 'openssl1'
with: with:
path: openssl1/build path: openssl1/build
key: ${{ runner.os }}-openssl-${{ env.OPENSSL1_VERSION }} key: ${{ runner.os }}-openssl-${{ env.OPENSSL1_VERSION }}
fail-on-cache-miss: true fail-on-cache-miss: true
- name: Restore quictls/openssl v3.x cache - name: Restore quictls/openssl v3.x cache
uses: actions/cache/restore@v3 uses: actions/cache/restore@v4
if: matrix.http3 == 'http3' && matrix.openssl == 'openssl3' if: matrix.http3 == 'http3' && matrix.openssl == 'openssl3'
with: with:
path: openssl3/build path: openssl3/build
key: ${{ runner.os }}-openssl-${{ env.OPENSSL3_VERSION }} key: ${{ runner.os }}-openssl-${{ env.OPENSSL3_VERSION }}
fail-on-cache-miss: true fail-on-cache-miss: true
- name: Restore BoringSSL cache - name: Restore BoringSSL cache
uses: actions/cache/restore@v3 uses: actions/cache/restore@v4
if: matrix.openssl == 'boringssl' if: matrix.openssl == 'boringssl'
with: with:
path: | path: |
@@ -326,7 +334,7 @@ jobs:
key: ${{ runner.os }}-boringssl-${{ env.BORINGSSL_VERSION }} key: ${{ runner.os }}-boringssl-${{ env.BORINGSSL_VERSION }}
fail-on-cache-miss: true fail-on-cache-miss: true
- name: Restore aws-lc cache - name: Restore aws-lc cache
uses: actions/cache/restore@v3 uses: actions/cache/restore@v4
if: matrix.openssl == 'awslc' if: matrix.openssl == 'awslc'
with: with:
path: | path: |
@@ -364,21 +372,21 @@ jobs:
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 nghttp3 cache - name: Restore nghttp3 cache
uses: actions/cache/restore@v3 uses: actions/cache/restore@v4
if: matrix.http3 == 'http3' if: matrix.http3 == 'http3'
with: with:
path: nghttp3/build path: nghttp3/build
key: ${{ runner.os }}-nghttp3-${{ env.NGHTTP3_VERSION }} key: ${{ runner.os }}-nghttp3-${{ env.NGHTTP3_VERSION }}
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@v3 uses: actions/cache/restore@v4
if: matrix.http3 == 'http3' && (matrix.openssl == 'openssl1' || matrix.openssl == 'boringssl') if: matrix.http3 == 'http3' && (matrix.openssl == 'openssl1' || matrix.openssl == 'boringssl')
with: with:
path: ngtcp2-openssl1/build path: ngtcp2-openssl1/build
key: ${{ runner.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL1_VERSION }} key: ${{ runner.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL1_VERSION }}
fail-on-cache-miss: true fail-on-cache-miss: true
- name: Restore ngtcp2 + quictls/openssl v3.x cache + aws-lc - name: Restore ngtcp2 + quictls/openssl v3.x cache + aws-lc
uses: actions/cache/restore@v3 uses: actions/cache/restore@v4
if: matrix.http3 == 'http3' && (matrix.openssl == 'openssl3' || matrix.openssl == 'awslc') if: matrix.http3 == 'http3' && (matrix.openssl == 'openssl3' || matrix.openssl == 'awslc')
with: with:
path: ngtcp2-openssl3/build path: ngtcp2-openssl3/build
@@ -398,7 +406,7 @@ jobs:
echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV
- name: Setup git submodules - name: Setup git submodules
run: | run: |
git submodule update --init git submodule update --init --depth 1
- name: Configure autotools - name: Configure autotools
run: | run: |
autoreconf -i autoreconf -i
@@ -430,12 +438,12 @@ jobs:
if: matrix.buildtool == 'autotools' && runner.os == 'Linux' if: matrix.buildtool == 'autotools' && runner.os == 'Linux'
run: | run: |
make -j"$(nproc)" distcheck \ make -j"$(nproc)" distcheck \
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --with-libev --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\"" DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --with-libev --with-libbrotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
- 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: |
make -j"$(sysctl -n hw.ncpu)" distcheck \ make -j"$(sysctl -n hw.ncpu)" distcheck \
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-libev --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\"" DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-libev --with-libbrotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
- name: Build nghttp2 with cmake - name: Build nghttp2 with cmake
if: matrix.buildtool == 'cmake' if: matrix.buildtool == 'cmake'
run: | run: |
@@ -478,20 +486,12 @@ jobs:
libtool \ libtool \
pkg-config \ pkg-config \
wine wine
- name: Build CUnit
run: |
curl -LO https://jaist.dl.sourceforge.net/project/cunit/CUnit/2.1-3/CUnit-2.1-3.tar.bz2
tar xf CUnit-2.1-3.tar.bz2
cd CUnit-2.1-3
./bootstrap
./configure --disable-shared --host="$HOST" --prefix="$PWD/build"
make -j$(nproc) install
- name: Configure autotools - name: Configure autotools
run: | run: |
git submodule update --init --depth 1
autoreconf -i && \ autoreconf -i && \
./configure --enable-werror --enable-lib-only --with-cunit \ ./configure --enable-werror --enable-lib-only --host="$HOST" \
--host="$HOST" PKG_CONFIG_PATH="$PWD/CUnit-2.1-3/build/lib/pkgconfig" \ CFLAGS="-g -O2 -D_WIN32_WINNT=0x0600" LIBS="-pthread"
CFLAGS="-g -O2 -D_WIN32_WINNT=0x0600"
- name: Build nghttp2 - name: Build nghttp2
run: | run: |
make -j$(nproc) make -j$(nproc)
@@ -499,6 +499,7 @@ jobs:
- name: Run tests - name: Run tests
if: matrix.host == 'x86_64-w64-mingw32' if: matrix.host == 'x86_64-w64-mingw32'
run: | run: |
export WINEPATH=/usr/x86_64-w64-mingw32/lib
cd tests cd tests
wine main.exe wine main.exe
@@ -516,11 +517,10 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: microsoft/setup-msbuild@v1 - uses: microsoft/setup-msbuild@v2
- run: |
vcpkg --triplet=${{ matrix.arch }}-windows install cunit
- name: Configure cmake - name: Configure cmake
run: | run: |
git submodule update --init --depth 1
mkdir build mkdir build
cd build cd build
cmake -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_GENERATOR_PLATFORM=${{ matrix.platform }} -DVCPKG_TARGET_TRIPLET=${{ matrix.arch}}-windows .. cmake -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_GENERATOR_PLATFORM=${{ matrix.platform }} -DVCPKG_TARGET_TRIPLET=${{ matrix.arch}}-windows ..

24
.github/workflows/docker.yaml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: docker-build
on:
push:
paths:
- docker/Dockerfile
branches:
- '**'
permissions: read-all
jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build
uses: docker/build-push-action@v5
with:
context: docker
build-args: NGHTTP2_BRANCH=${{ github.ref_name }}

8
.gitignore vendored
View File

@@ -42,6 +42,7 @@ rules.ninja
lib*.so lib*.so
lib*.so.* lib*.so.*
lib*.a lib*.a
# generated by "make test" with cmake # generated by "make test" with cmake
Testing/ Testing/
@@ -54,3 +55,10 @@ _VC_ROOT/
.depend.MSVC .depend.MSVC
*.pyd *.pyd
*.egg-info/ *.egg-info/
# Build Directories
build/
# IDEs
cmake-*
.idea/

3
.gitmodules vendored
View File

@@ -5,3 +5,6 @@
path = third-party/neverbleed path = third-party/neverbleed
url = https://github.com/tatsuhiro-t/neverbleed.git url = https://github.com/tatsuhiro-t/neverbleed.git
branch = nghttp2 branch = nghttp2
[submodule "tests/munit"]
path = tests/munit
url = https://github.com/ngtcp2/munit

View File

@@ -112,6 +112,7 @@ Rudi Heitbaum
Ryo Ota Ryo Ota
Scott Mitchell Scott Mitchell
Sebastiaan Deckers Sebastiaan Deckers
Sergey Fedorov
Shelley Vohr Shelley Vohr
Simon Frankenberger Simon Frankenberger
Simone Basso Simone Basso

View File

@@ -22,15 +22,15 @@
# 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.
cmake_minimum_required(VERSION 3.5) 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.59.0) project(nghttp2 VERSION 1.60.0)
# 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 40) set(LT_CURRENT 41)
set(LT_REVISION 0) set(LT_REVISION 0)
set(LT_AGE 26) set(LT_AGE 27)
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)
@@ -60,6 +60,8 @@ if(NOT ENABLE_LIB_ONLY)
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)
find_package(Libbrotlienc 1.0.9)
find_package(Libbrotlidec 1.0.9)
endif() endif()
find_package(OpenSSL 1.1.1) find_package(OpenSSL 1.1.1)
@@ -165,12 +167,8 @@ endif()
# XXX shouldn't ${CMAKE_DL_LIBS} be appended to OPENSSL_LIBRARIES instead of # XXX shouldn't ${CMAKE_DL_LIBS} be appended to OPENSSL_LIBRARIES instead of
# APP_LIBRARIES if it is really specific to OpenSSL? # APP_LIBRARIES if it is really specific to OpenSSL?
find_package(CUnit 2.1)
enable_testing() enable_testing()
set(HAVE_CUNIT ${CUNIT_FOUND}) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
if(HAVE_CUNIT)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
endif()
# openssl (for src) # openssl (for src)
include(CheckSymbolExists) include(CheckSymbolExists)
@@ -222,6 +220,13 @@ endif()
# jemalloc # jemalloc
set(HAVE_JEMALLOC ${JEMALLOC_FOUND}) set(HAVE_JEMALLOC ${JEMALLOC_FOUND})
# libbrotli (for src)
set(HAVE_LIBBROTLIENC ${LIBBROTLIENC_FOUND})
set(HAVE_LIBBROTLIDEC ${LIBBROTLIDEC_FOUND})
if(LIBBROTLIENC_FOUND AND LIBBROTLIDEC_FOUND)
set(HAVE_LIBBROTLI 1)
endif()
# libbpf (for bpf) # libbpf (for bpf)
set(HAVE_LIBBPF ${LIBBPF_FOUND}) set(HAVE_LIBBPF ${LIBBPF_FOUND})
if(LIBBPF_FOUND) if(LIBBPF_FOUND)
@@ -458,7 +463,6 @@ message(STATUS "summary of build options:
Python: ${Python3_EXECUTABLE} Python: ${Python3_EXECUTABLE}
Python3_VERSION: ${Python3_VERSION} Python3_VERSION: ${Python3_VERSION}
Test: Test:
CUnit: ${HAVE_CUNIT} (LIBS='${CUNIT_LIBRARIES}')
Failmalloc: ${ENABLE_FAILMALLOC} Failmalloc: ${ENABLE_FAILMALLOC}
Libs: Libs:
OpenSSL: ${HAVE_OPENSSL} (LIBS='${OPENSSL_LIBRARIES}') OpenSSL: ${HAVE_OPENSSL} (LIBS='${OPENSSL_LIBRARIES}')
@@ -474,6 +478,8 @@ message(STATUS "summary of build options:
Jemalloc: ${HAVE_JEMALLOC} (LIBS='${JEMALLOC_LIBRARIES}') Jemalloc: ${HAVE_JEMALLOC} (LIBS='${JEMALLOC_LIBRARIES}')
Zlib: ${HAVE_ZLIB} (LIBS='${ZLIB_LIBRARIES}') Zlib: ${HAVE_ZLIB} (LIBS='${ZLIB_LIBRARIES}')
Systemd: ${HAVE_SYSTEMD} (LIBS='${SYSTEMD_LIBRARIES}') Systemd: ${HAVE_SYSTEMD} (LIBS='${SYSTEMD_LIBRARIES}')
Libbrotlienc: ${HAVE_LIBBROTLIENC} (LIBS='${LIBBROTLIENC_LIBRARIES}')
Libbrotlidec: ${HAVE_LIBBROTLIDEC} (LIBS='${LIBBROTLIDEC_LIBRARIES}')
Third-party: Third-party:
http-parser: ${ENABLE_THIRD_PARTY} http-parser: ${ENABLE_THIRD_PARTY}
MRuby: ${HAVE_MRUBY} MRuby: ${HAVE_MRUBY}

View File

@@ -11,8 +11,8 @@ option(ENABLE_EXAMPLES "Build examples"
${ENABLE_EXAMPLES_DEFAULT}) ${ENABLE_EXAMPLES_DEFAULT})
option(ENABLE_FAILMALLOC "Build failmalloc test program" ON) option(ENABLE_FAILMALLOC "Build failmalloc test program" ON)
option(ENABLE_LIB_ONLY "Build libnghttp2 only. This is a short hand for -DENABLE_APP=0 -DENABLE_EXAMPLES=0 -DENABLE_HPACK_TOOLS=0") option(ENABLE_LIB_ONLY "Build libnghttp2 only. This is a short hand for -DENABLE_APP=0 -DENABLE_EXAMPLES=0 -DENABLE_HPACK_TOOLS=0")
option(ENABLE_STATIC_LIB "Build libnghttp2 in static mode also") option(BUILD_SHARED_LIBS "Build libnghttp2 as a shared library" ON)
option(ENABLE_SHARED_LIB "Build libnghttp2 as a shared library" ON) option(BUILD_STATIC_LIBS "Build libnghttp2 in static mode also" OFF)
option(ENABLE_STATIC_CRT "Build libnghttp2 against the MS LIBCMT[d]") option(ENABLE_STATIC_CRT "Build libnghttp2 against the MS LIBCMT[d]")
option(ENABLE_HTTP3 "Enable HTTP/3 support" OFF) option(ENABLE_HTTP3 "Enable HTTP/3 support" OFF)
option(ENABLE_DOC "Build documentation" ON) option(ENABLE_DOC "Build documentation" ON)

View File

@@ -35,7 +35,6 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-env \
cmake/ExtractValidFlags.cmake \ cmake/ExtractValidFlags.cmake \
cmake/FindJemalloc.cmake \ cmake/FindJemalloc.cmake \
cmake/FindLibev.cmake \ cmake/FindLibev.cmake \
cmake/FindCUnit.cmake \
cmake/Version.cmake \ cmake/Version.cmake \
cmake/FindLibevent.cmake \ cmake/FindLibevent.cmake \
cmake/FindJansson.cmake \ cmake/FindJansson.cmake \
@@ -45,6 +44,8 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-env \
cmake/FindLibnghttp3.cmake \ cmake/FindLibnghttp3.cmake \
cmake/FindLibngtcp2.cmake \ cmake/FindLibngtcp2.cmake \
cmake/FindLibngtcp2_crypto_quictls.cmake \ cmake/FindLibngtcp2_crypto_quictls.cmake \
cmake/FindLibbrotlienc.cmake \
cmake/FindLibbrotlidec.cmake \
cmake/PickyWarningsC.cmake \ cmake/PickyWarningsC.cmake \
cmake/PickyWarningsCXX.cmake cmake/PickyWarningsCXX.cmake

View File

@@ -48,11 +48,6 @@ The following package is required to build the libnghttp2 library:
* pkg-config >= 0.20 * pkg-config >= 0.20
To build and run the unit test programs, the following package is
required:
* cunit >= 2.1
To build the documentation, you need to install: To build the documentation, you need to install:
* sphinx (http://sphinx-doc.org/) * sphinx (http://sphinx-doc.org/)
@@ -100,6 +95,11 @@ To mitigate heap fragmentation in long running server programs
Alpine Linux currently does not support malloc replacement Alpine Linux currently does not support malloc replacement
due to musl limitations. See details in issue `#762 <https://github.com/nghttp2/nghttp2/issues/762>`_. due to musl limitations. See details in issue `#762 <https://github.com/nghttp2/nghttp2/issues/762>`_.
For BoringSSL or aws-lc build, to enable :rfc:`8879` TLS Certificate
Compression in applications, the following library is required:
* libbrotli-dev >= 1.0.9
To enable mruby support for nghttpx, `mruby To enable mruby support for nghttpx, `mruby
<https://github.com/mruby/mruby>`_ is required. We need to build <https://github.com/mruby/mruby>`_ is required. We need to build
mruby with C++ ABI explicitly turned on, and probably need other mruby with C++ ABI explicitly turned on, and probably need other
@@ -127,7 +127,7 @@ following libraries are required:
<https://github.com/quictls/openssl/tree/OpenSSL_1_1_1w+quic>`_; or <https://github.com/quictls/openssl/tree/OpenSSL_1_1_1w+quic>`_; 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
f42be90d665b6a376177648ccbb76fbbd6497c13) 8e6a26d128484b886e6dcbfa558b993d38950bb5)
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 1.0.0 * `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 1.0.0
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 1.1.0 * `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 1.1.0
@@ -205,7 +205,7 @@ required packages:
sudo apt-get install g++ clang make binutils autoconf automake \ sudo apt-get install g++ clang make binutils autoconf automake \
autotools-dev libtool pkg-config \ autotools-dev libtool pkg-config \
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev \ zlib1g-dev libssl-dev libxml2-dev libev-dev \
libevent-dev libjansson-dev \ libevent-dev libjansson-dev \
libc-ares-dev libjemalloc-dev libsystemd-dev \ libc-ares-dev libjemalloc-dev libsystemd-dev \
ruby-dev bison libelf-dev ruby-dev bison libelf-dev
@@ -337,23 +337,24 @@ connections alive during reload.
The detailed steps to build HTTP/3 enabled h2load and nghttpx follow. The detailed steps to build HTTP/3 enabled h2load and nghttpx follow.
Build custom OpenSSL: Build aws-lc:
.. code-block:: text .. code-block:: text
$ git clone --depth 1 -b OpenSSL_1_1_1w+quic https://github.com/quictls/openssl $ git clone --depth 1 -b v1.21.0 https://github.com/aws/aws-lc
$ cd openssl $ cd aws-lc
$ ./config --prefix=$PWD/build --openssldir=/etc/ssl $ cmake -B build -DDISABLE_GO=ON --install-prefix=$PWD/opt
$ make -j$(nproc) $ make -j$(nproc) -C build
$ make install_sw $ cmake --install build
$ cd .. $ cd ..
Build nghttp3: Build nghttp3:
.. code-block:: text .. code-block:: text
$ git clone --depth 1 -b v1.1.0 https://github.com/ngtcp2/nghttp3 $ git clone --depth 1 -b v1.2.0 https://github.com/ngtcp2/nghttp3
$ cd nghttp3 $ cd nghttp3
$ git submodule update --init --depth 1
$ autoreconf -i $ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only $ ./configure --prefix=$PWD/build --enable-lib-only
$ make -j$(nproc) $ make -j$(nproc)
@@ -364,11 +365,13 @@ Build ngtcp2:
.. code-block:: text .. code-block:: text
$ git clone --depth 1 -b v1.2.0 https://github.com/ngtcp2/ngtcp2 $ git clone --depth 1 -b v1.3.0 https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2 $ cd ngtcp2
$ git submodule update --init --depth 1
$ autoreconf -i $ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only \ $ ./configure --prefix=$PWD/build --enable-lib-only --with-boringssl \
PKG_CONFIG_PATH="$PWD/../openssl/build/lib/pkgconfig" BORINGSSL_CFLAGS="-I$PWD/../aws-lc/opt/include" \
BORINGSSL_LIBS="-L$PWD/../aws-lc/opt/lib -lssl -lcrypto"
$ make -j$(nproc) $ make -j$(nproc)
$ make install $ make install
$ cd .. $ cd ..
@@ -391,10 +394,10 @@ Build nghttp2:
$ cd nghttp2 $ cd nghttp2
$ git submodule update --init $ git submodule update --init
$ autoreconf -i $ autoreconf -i
$ ./configure --with-mruby --with-neverbleed --enable-http3 --with-libbpf \ $ ./configure --with-mruby --enable-http3 --with-libbpf \
CC=clang-14 CXX=clang++-14 \ CC=clang-15 CXX=clang++-15 \
PKG_CONFIG_PATH="$PWD/../openssl/build/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/../openssl/build/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)
The eBPF program ``reuseport_kern.o`` should be found under bpf The eBPF program ``reuseport_kern.o`` should be found under bpf
@@ -479,7 +482,7 @@ Previously nghttp2 library did not send client magic, which is first
24 bytes byte string of client connection preface, and client 24 bytes byte string of client connection preface, and client
applications have to send it by themselves. Since v1.0.0, client applications have to send it by themselves. Since v1.0.0, client
magic is sent by library via first call of ``nghttp2_session_send()`` magic is sent by library via first call of ``nghttp2_session_send()``
or ``nghttp2_session_mem_send()``. or ``nghttp2_session_mem_send2()``.
The client applications which send client magic must remove the The client applications which send client magic must remove the
relevant code. relevant code.
@@ -1446,17 +1449,6 @@ See `Contribution Guidelines
<https://nghttp2.org/documentation/contribute.html>`_ for more <https://nghttp2.org/documentation/contribute.html>`_ for more
details. details.
Reporting vulnerability
-----------------------
If you find a vulnerability in our software, please send the email to
"tatsuhiro.t at gmail dot com" about its details instead of submitting
issues on github issue page. It is a standard practice not to
disclose vulnerability information publicly until a fixed version is
released, or mitigation is worked out.
In the future, we may setup a dedicated mail address for this purpose.
Versioning Versioning
---------- ----------

View File

@@ -1,16 +1,15 @@
Security Process # Security Process
================
If you find a vulnerability in our software, please send the email to If you find a vulnerability in our software, please report it via
"tatsuhiro.t at gmail dot com" about its details instead of submitting GitHub "Private vulnerability reporting" feature at
https://github.com/nghttp2/nghttp2/security instead of submitting
issues on github issue page. It is a standard practice not to issues on github issue page. It is a standard practice not to
disclose vulnerability information publicly until a fixed version is disclose vulnerability information publicly until a fixed version is
released, or mitigation is worked out. In the future, we may setup a released, or mitigation is worked out.
dedicated mail address for this purpose.
If we identify that the reported issue is really a vulnerability, we If we identify that the reported issue is really a vulnerability, we
open a new security advisory draft using `GitHub security feature open a new security advisory draft using [GitHub security
<https://github.com/nghttp2/nghttp2/security>`_ and discuss the feature](https://github.com/nghttp2/nghttp2/security) and discuss the
mitigation and bug fixes there. The fixes are committed to the mitigation and bug fixes there. The fixes are committed to the
private repository. private repository.
@@ -21,12 +20,11 @@ We make a new release with the fix at the same time when the
vulnerability is disclosed to public. vulnerability is disclosed to public.
At least 7 days before the public disclosure date, we open a new issue At least 7 days before the public disclosure date, we open a new issue
on `nghttp2 issue tracker on [nghttp2 issue tracker](https://github.com/nghttp2/nghttp2/issues)
<https://github.com/nghttp2/nghttp2/issues>`_ which notifies that the which notifies that the upcoming release will have a security fix.
upcoming release will have a security fix. The ``SECURITY`` label is The `SECURITY` label is attached to this kind of issue. The issue is
attached to this kind of issue. The issue is not opened if a not opened if a vulnerability is already disclosed, and it is publicly
vulnerability is already disclosed, and it is publicly known that known that nghttp2 is affected by that.
nghttp2 is affected by that.
Before few hours of new release, we merge the fixes to the master Before few hours of new release, we merge the fixes to the master
branch (and/or a release branch if necessary) and make a new release. branch (and/or a release branch if necessary) and make a new release.

View File

@@ -42,11 +42,6 @@
License is Public Domain. Commit hash: License is Public Domain. Commit hash:
12e7744b4919e9d55de75b7ab566326a1c8e7a67 */ 12e7744b4919e9d55de75b7ab566326a1c8e7a67 */
#define AES_BLOCKLEN \
16 /* Block length in bytes - AES is 128b block \
only */
#define AES_KEYLEN 16 /* Key length in bytes */
#define AES_keyExpSize 176 #define AES_keyExpSize 176
struct AES_ctx { struct AES_ctx {
@@ -57,7 +52,6 @@ struct AES_ctx {
in AES. Value=4 */ in AES. Value=4 */
#define Nb 4 #define Nb 4
#define Nk 4 /* The number of 32 bit words in a key. */
#define Nr 10 /* The number of rounds in AES Cipher. */ #define Nr 10 /* The number of rounds in AES Cipher. */
/* state - array holding the intermediate results during /* state - array holding the intermediate results during
@@ -68,31 +62,6 @@ typedef __u8 state_t[4][4];
read-only storage instead of RAM The numbers below can be computed read-only storage instead of RAM The numbers below can be computed
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 sbox[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
0xb0, 0x54, 0xbb, 0x16};
static const __u8 rsbox[256] = { static const __u8 rsbox[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
@@ -117,78 +86,6 @@ static const __u8 rsbox[256] = {
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
0x55, 0x21, 0x0c, 0x7d}; 0x55, 0x21, 0x0c, 0x7d};
/* The round constant word array, Rcon[i], contains the values given
by x to the power (i-1) being powers of x (x is denoted as {02}) in
the field GF(2^8) */
static const __u8 Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
0x20, 0x40, 0x80, 0x1b, 0x36};
#define getSBoxValue(num) (sbox[(num)])
/* This function produces Nb(Nr+1) round keys. The round keys are used
in each round to decrypt the states. */
static void KeyExpansion(__u8 *RoundKey, const __u8 *Key) {
unsigned i, j, k;
__u8 tempa[4]; /* Used for the column/row operations */
/* The first round key is the key itself. */
for (i = 0; i < Nk; ++i) {
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
}
/* All other round keys are found from the previous round keys. */
for (i = Nk; i < Nb * (Nr + 1); ++i) {
{
k = (i - 1) * 4;
tempa[0] = RoundKey[k + 0];
tempa[1] = RoundKey[k + 1];
tempa[2] = RoundKey[k + 2];
tempa[3] = RoundKey[k + 3];
}
if (i % Nk == 0) {
/* This function shifts the 4 bytes in a word to the left once.
[a0,a1,a2,a3] becomes [a1,a2,a3,a0] */
/* Function RotWord() */
{
const __u8 u8tmp = tempa[0];
tempa[0] = tempa[1];
tempa[1] = tempa[2];
tempa[2] = tempa[3];
tempa[3] = u8tmp;
}
/* SubWord() is a function that takes a four-byte input word and
applies the S-box to each of the four bytes to produce an
output word. */
/* Function Subword() */
{
tempa[0] = getSBoxValue(tempa[0]);
tempa[1] = getSBoxValue(tempa[1]);
tempa[2] = getSBoxValue(tempa[2]);
tempa[3] = getSBoxValue(tempa[3]);
}
tempa[0] = tempa[0] ^ Rcon[i / Nk];
}
j = i * 4;
k = (i - Nk) * 4;
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
}
}
static void AES_init_ctx(struct AES_ctx *ctx, const __u8 *key) {
KeyExpansion(ctx->RoundKey, key);
}
/* 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. */
static void AddRoundKey(__u8 round, state_t *state, const __u8 *RoundKey) { static void AddRoundKey(__u8 round, state_t *state, const __u8 *RoundKey) {
@@ -439,11 +336,18 @@ struct {
struct { struct {
__uint(type, BPF_MAP_TYPE_ARRAY); __uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 3); __uint(max_entries, 1);
__type(key, __u32); __type(key, __u32);
__type(value, __u64); __type(value, __u64);
} sk_info SEC(".maps"); } sk_info SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__type(key, __u32);
__type(value, struct AES_ctx);
} aes_key SEC(".maps");
typedef struct quic_hd { typedef struct quic_hd {
__u8 *dcid; __u8 *dcid;
__u32 dcidlen; __u32 dcidlen;
@@ -573,13 +477,12 @@ static __u32 sk_index_from_dcid(const quic_hd *qhd,
SEC("sk_reuseport") SEC("sk_reuseport")
int select_reuseport(struct sk_reuseport_md *reuse_md) { int select_reuseport(struct sk_reuseport_md *reuse_md) {
__u32 sk_index, *psk_index; __u32 sk_index, *psk_index;
__u64 *pnum_socks, *pkey; __u64 *pnum_socks;
__u32 zero = 0, key_high_idx = 1, key_low_idx = 2; __u32 zero = 0;
int rv; int rv;
quic_hd qhd; quic_hd qhd;
__u8 qpktbuf[6 + MAX_DCIDLEN]; __u8 qpktbuf[6 + MAX_DCIDLEN];
struct AES_ctx aes_ctx; struct AES_ctx *aes_ctx;
__u8 key[AES_KEYLEN];
__u8 *cid_prefix; __u8 *cid_prefix;
if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr), qpktbuf, if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr), qpktbuf,
@@ -592,33 +495,22 @@ int select_reuseport(struct sk_reuseport_md *reuse_md) {
return SK_DROP; return SK_DROP;
} }
pkey = bpf_map_lookup_elem(&sk_info, &key_high_idx); aes_ctx = bpf_map_lookup_elem(&aes_key, &zero);
if (pkey == NULL) { if (aes_ctx == NULL) {
return SK_DROP; return SK_DROP;
} }
__builtin_memcpy(key, pkey, sizeof(*pkey));
pkey = bpf_map_lookup_elem(&sk_info, &key_low_idx);
if (pkey == NULL) {
return SK_DROP;
}
__builtin_memcpy(key + sizeof(*pkey), pkey, sizeof(*pkey));
rv = parse_quic(&qhd, qpktbuf, qpktbuf + sizeof(qpktbuf)); rv = parse_quic(&qhd, qpktbuf, qpktbuf + sizeof(qpktbuf));
if (rv != 0) { if (rv != 0) {
return SK_DROP; return SK_DROP;
} }
AES_init_ctx(&aes_ctx, key);
switch (qhd.type) { switch (qhd.type) {
case NGTCP2_PKT_INITIAL: case NGTCP2_PKT_INITIAL:
case NGTCP2_PKT_0RTT: case NGTCP2_PKT_0RTT:
if (qhd.dcidlen == SV_DCIDLEN) { if (qhd.dcidlen == SV_DCIDLEN) {
cid_prefix = qhd.dcid + CID_PREFIX_OFFSET; cid_prefix = qhd.dcid + CID_PREFIX_OFFSET;
AES_ECB_decrypt(&aes_ctx, cid_prefix); AES_ECB_decrypt(aes_ctx, cid_prefix);
psk_index = bpf_map_lookup_elem(&cid_prefix_map, cid_prefix); psk_index = bpf_map_lookup_elem(&cid_prefix_map, cid_prefix);
if (psk_index != NULL) { if (psk_index != NULL) {
@@ -638,7 +530,7 @@ int select_reuseport(struct sk_reuseport_md *reuse_md) {
} }
cid_prefix = qhd.dcid + CID_PREFIX_OFFSET; cid_prefix = qhd.dcid + CID_PREFIX_OFFSET;
AES_ECB_decrypt(&aes_ctx, cid_prefix); AES_ECB_decrypt(aes_ctx, cid_prefix);
psk_index = bpf_map_lookup_elem(&cid_prefix_map, cid_prefix); psk_index = bpf_map_lookup_elem(&cid_prefix_map, cid_prefix);
if (psk_index == NULL) { if (psk_index == NULL) {

View File

@@ -1,40 +0,0 @@
# - Try to find cunit
# Once done this will define
# CUNIT_FOUND - System has cunit
# CUNIT_INCLUDE_DIRS - The cunit include directories
# CUNIT_LIBRARIES - The libraries needed to use cunit
find_package(PkgConfig QUIET)
pkg_check_modules(PC_CUNIT QUIET cunit)
find_path(CUNIT_INCLUDE_DIR
NAMES CUnit/CUnit.h
HINTS ${PC_CUNIT_INCLUDE_DIRS}
)
find_library(CUNIT_LIBRARY
NAMES cunit
HINTS ${PC_CUNIT_LIBRARY_DIRS}
)
if(CUNIT_INCLUDE_DIR)
set(_version_regex "^#define[ \t]+CU_VERSION[ \t]+\"([^\"]+)\".*")
file(STRINGS "${CUNIT_INCLUDE_DIR}/CUnit/CUnit.h"
CUNIT_VERSION REGEX "${_version_regex}")
string(REGEX REPLACE "${_version_regex}" "\\1"
CUNIT_VERSION "${CUNIT_VERSION}")
unset(_version_regex)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set CUNIT_FOUND to TRUE
# if all listed variables are TRUE and the requested version matches.
find_package_handle_standard_args(CUnit REQUIRED_VARS
CUNIT_LIBRARY CUNIT_INCLUDE_DIR
VERSION_VAR CUNIT_VERSION)
if(CUNIT_FOUND)
set(CUNIT_LIBRARIES ${CUNIT_LIBRARY})
set(CUNIT_INCLUDE_DIRS ${CUNIT_INCLUDE_DIR})
endif()
mark_as_advanced(CUNIT_INCLUDE_DIR CUNIT_LIBRARY)

View File

@@ -0,0 +1,36 @@
# - Try to find libbrotlidec
# Once done this will define
# LIBBROTLIDEC_FOUND - System has libbrotlidec
# LIBBROTLIDEC_INCLUDE_DIRS - The libbrotlidec include directories
# LIBBROTLIDEC_LIBRARIES - The libraries needed to use libbrotlidec
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBBROTLIDEC QUIET libbrotlidec)
find_path(LIBBROTLIDEC_INCLUDE_DIR
NAMES brotli/decode.h
HINTS ${PC_LIBBROTLIDEC_INCLUDE_DIRS}
)
find_library(LIBBROTLIDEC_LIBRARY
NAMES brotlidec
HINTS ${PC_LIBBROTLIDEC_LIBRARY_DIRS}
)
if(PC_LIBBROTLIDEC_FOUND)
set(LIBBROTLIDEC_VERSION ${PC_LIBBROTLIDEC_VERSION})
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBBROTLIDEC_FOUND
# to TRUE if all listed variables are TRUE and the requested version
# matches.
find_package_handle_standard_args(Libbrotlidec REQUIRED_VARS
LIBBROTLIDEC_LIBRARY LIBBROTLIDEC_INCLUDE_DIR
VERSION_VAR LIBBROTLIDEC_VERSION)
if(LIBBROTLIDEC_FOUND)
set(LIBBROTLIDEC_LIBRARIES ${LIBBROTLIDEC_LIBRARY})
set(LIBBROTLIDEC_INCLUDE_DIRS ${LIBBROTLIDEC_INCLUDE_DIR})
endif()
mark_as_advanced(LIBBROTLIDEC_INCLUDE_DIR LIBBROTLIDEC_LIBRARY)

View File

@@ -0,0 +1,36 @@
# - Try to find libbrotlienc
# Once done this will define
# LIBBROTLIENC_FOUND - System has libbrotlienc
# LIBBROTLIENC_INCLUDE_DIRS - The libbrotlienc include directories
# LIBBROTLIENC_LIBRARIES - The libraries needed to use libbrotlienc
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBBROTLIENC QUIET libbrotlienc)
find_path(LIBBROTLIENC_INCLUDE_DIR
NAMES brotli/encode.h
HINTS ${PC_LIBBROTLIENC_INCLUDE_DIRS}
)
find_library(LIBBROTLIENC_LIBRARY
NAMES brotlienc
HINTS ${PC_LIBBROTLIENC_LIBRARY_DIRS}
)
if(PC_LIBBROTLIENC_FOUND)
set(LIBBROTLIENC_VERSION ${PC_LIBBROTLIENC_VERSION})
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBBROTLIENC_FOUND
# to TRUE if all listed variables are TRUE and the requested version
# matches.
find_package_handle_standard_args(Libbrotlienc REQUIRED_VARS
LIBBROTLIENC_LIBRARY LIBBROTLIENC_INCLUDE_DIR
VERSION_VAR LIBBROTLIENC_VERSION)
if(LIBBROTLIENC_FOUND)
set(LIBBROTLIENC_LIBRARIES ${LIBBROTLIENC_LIBRARY})
set(LIBBROTLIENC_INCLUDE_DIRS ${LIBBROTLIENC_INCLUDE_DIR})
endif()
mark_as_advanced(LIBBROTLIENC_INCLUDE_DIR LIBBROTLIENC_LIBRARY)

View File

@@ -85,7 +85,6 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID MA
-Wstrict-prototypes # clang 1.0 gcc 3.3 -Wstrict-prototypes # clang 1.0 gcc 3.3
# -Wswitch-enum # clang 3.0 gcc 4.1 # Not used because this basically disallows default case # -Wswitch-enum # clang 3.0 gcc 4.1 # Not used because this basically disallows default case
-Wunreachable-code # clang 3.0 gcc 4.1 -Wunreachable-code # clang 3.0 gcc 4.1
-Wunused-macros # clang 3.0 gcc 4.1
-Wunused-parameter # clang 3.0 gcc 4.1 -Wunused-parameter # clang 3.0 gcc 4.1
-Wvla # clang 2.8 gcc 4.3 -Wvla # clang 2.8 gcc 4.3
) )

View File

@@ -99,3 +99,6 @@
/* 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. */
#cmakedefine HAVE_LIBBROTLI 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.59.0], [t-tujikawa@users.sourceforge.net]) AC_INIT([nghttp2], [1.60.0], [t-tujikawa@users.sourceforge.net])
AC_CONFIG_AUX_DIR([.]) AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
@@ -44,9 +44,9 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl See versioning rule: dnl See versioning rule:
dnl 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, 40) AC_SUBST(LT_CURRENT, 41)
AC_SUBST(LT_REVISION, 0) AC_SUBST(LT_REVISION, 0)
AC_SUBST(LT_AGE, 26) AC_SUBST(LT_AGE, 27)
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"`
@@ -137,11 +137,6 @@ AC_ARG_WITH([libev],
[Use libev [default=check]])], [Use libev [default=check]])],
[request_libev=$withval], [request_libev=check]) [request_libev=$withval], [request_libev=check])
AC_ARG_WITH([cunit],
[AS_HELP_STRING([--with-cunit],
[Use cunit [default=check]])],
[request_cunit=$withval], [request_cunit=check])
AC_ARG_WITH([jemalloc], AC_ARG_WITH([jemalloc],
[AS_HELP_STRING([--with-jemalloc], [AS_HELP_STRING([--with-jemalloc],
[Use jemalloc [default=check]])], [Use jemalloc [default=check]])],
@@ -177,6 +172,16 @@ AC_ARG_WITH([libbpf],
[Use libbpf [default=no]])], [Use libbpf [default=no]])],
[request_libbpf=$withval], [request_libbpf=no]) [request_libbpf=$withval], [request_libbpf=no])
AC_ARG_WITH([libbrotlienc],
[AS_HELP_STRING([--with-libbrotlienc],
[Use libbrotlienc [default=no]])],
[request_libbrotlienc=$withval], [request_libbrotlienc=no])
AC_ARG_WITH([libbrotlidec],
[AS_HELP_STRING([--with-libbrotlidec],
[Use libbrotlidec [default=no]])],
[request_libbrotlidec=$withval], [request_libbrotlidec=no])
dnl Define variables dnl Define variables
AC_ARG_VAR([LIBEV_CFLAGS], [C compiler flags for libev, skipping any checks]) AC_ARG_VAR([LIBEV_CFLAGS], [C compiler flags for libev, skipping any checks])
AC_ARG_VAR([LIBEV_LIBS], [linker flags for libev, skipping any checks]) AC_ARG_VAR([LIBEV_LIBS], [linker flags for libev, skipping any checks])
@@ -377,43 +382,6 @@ case "${host_os}" in
;; ;;
esac esac
# cunit
have_cunit=no
if test "x${request_cunit}" != "xno"; then
PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes], [have_cunit=no])
# If pkg-config does not find cunit, check it using AC_CHECK_LIB. We
# do this because Debian (Ubuntu) lacks pkg-config file for cunit.
if test "x${have_cunit}" = "xno"; then
AC_MSG_WARN([${CUNIT_PKG_ERRORS}])
AC_CHECK_LIB([cunit], [CU_initialize_registry],
[have_cunit=yes], [have_cunit=no])
if test "x${have_cunit}" = "xyes"; then
CUNIT_LIBS="-lcunit"
CUNIT_CFLAGS=""
AC_SUBST([CUNIT_LIBS])
AC_SUBST([CUNIT_CFLAGS])
fi
fi
if test "x${have_cunit}" = "xyes"; then
# cunit in Mac OS X requires ncurses. Note that in Mac OS X, test
# program can be built without -lncurses, but it emits runtime
# error.
case "${build}" in
*-apple-darwin*)
CUNIT_LIBS="$CUNIT_LIBS -lncurses"
AC_SUBST([CUNIT_LIBS])
;;
esac
fi
fi
if test "x${request_cunit}" = "xyes" &&
test "x${have_cunit}" != "xyes"; then
AC_MSG_ERROR([cunit was requested (--with-cunit) but not found])
fi
AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ])
# libev (for src) # libev (for src)
have_libev=no have_libev=no
if test "x${request_libev}" != "xno"; then if test "x${request_libev}" != "xno"; then
@@ -626,6 +594,47 @@ fi
AM_CONDITIONAL([HAVE_LIBBPF], [ test "x${have_libbpf}" = "xyes" ]) AM_CONDITIONAL([HAVE_LIBBPF], [ test "x${have_libbpf}" = "xyes" ])
# libbrotlienc (for src)
have_libbrotlienc=no
if test "x${request_libbrotlienc}" != "xno"; then
PKG_CHECK_MODULES([LIBBROTLIENC], [libbrotlienc >= 1.0.9],
[have_libbrotlienc=yes],
[have_libbrotlienc=no])
if test "x${have_libbrotlienc}" = "xno"; then
AC_MSG_NOTICE($LIBBROTLIENC_PKG_ERRORS)
fi
fi
if test "x${request_libbrotlienc}" = "xyes" &&
test "x${have_libbrotlienc}" != "xyes"; then
AC_MSG_ERROR([libbrotlienc was requested (--with-libbrotlienc) but not found])
fi
# libbrotlidec (for src)
have_libbrotlidec=no
if test "x${request_libbrotlidec}" != "xno"; then
PKG_CHECK_MODULES([LIBBROTLIDEC], [libbrotlidec >= 1.0.9],
[have_libbrotlidec=yes],
[have_libbrotlidec=no])
if test "x${have_libbrotlidec}" = "xno"; then
AC_MSG_NOTICE($LIBBROTLIDEC_PKG_ERRORS)
fi
fi
if test "x${request_libbrotlidec}" = "xyes" &&
test "x${have_libbrotlidec}" != "xyes"; then
AC_MSG_ERROR([libbrotlidec was requested (--with-libbrotlidec) but not found])
fi
have_libbrotli=no
if test "x${have_libbrotlienc}" = "xyes" &&
test "x${have_libbrotlidec}" = "xyes"; then
have_libbrotli=yes
AC_DEFINE([HAVE_LIBBROTLI], [1],
[Define to 1 if you have `libbrotlienc` and `libbrotlidec` libraries.])
fi
# libevent_openssl (for examples) # libevent_openssl (for examples)
# 2.0.8 is required because we use evconnlistener_set_error_cb() # 2.0.8 is required because we use evconnlistener_set_error_cb()
have_libevent_openssl=no have_libevent_openssl=no
@@ -1155,7 +1164,6 @@ AC_MSG_NOTICE([summary of build options:
Python: ${PYTHON} Python: ${PYTHON}
PYTHON_VERSION: ${PYTHON_VERSION} PYTHON_VERSION: ${PYTHON_VERSION}
Test: Test:
CUnit: ${have_cunit} (CFLAGS='${CUNIT_CFLAGS}' LIBS='${CUNIT_LIBS}')
Failmalloc: ${enable_failmalloc} Failmalloc: ${enable_failmalloc}
Libs: Libs:
OpenSSL: ${have_openssl} (CFLAGS='${OPENSSL_CFLAGS}' LIBS='${OPENSSL_LIBS}') OpenSSL: ${have_openssl} (CFLAGS='${OPENSSL_CFLAGS}' LIBS='${OPENSSL_LIBS}')
@@ -1172,6 +1180,8 @@ AC_MSG_NOTICE([summary of build options:
Jemalloc: ${have_jemalloc} (CFLAGS='${JEMALLOC_CFLAGS}' LIBS='${JEMALLOC_LIBS}') Jemalloc: ${have_jemalloc} (CFLAGS='${JEMALLOC_CFLAGS}' LIBS='${JEMALLOC_LIBS}')
Zlib: ${have_zlib} (CFLAGS='${ZLIB_CFLAGS}' LIBS='${ZLIB_LIBS}') Zlib: ${have_zlib} (CFLAGS='${ZLIB_CFLAGS}' LIBS='${ZLIB_LIBS}')
Systemd: ${have_libsystemd} (CFLAGS='${SYSTEMD_CFLAGS}' LIBS='${SYSTEMD_LIBS}') Systemd: ${have_libsystemd} (CFLAGS='${SYSTEMD_CFLAGS}' LIBS='${SYSTEMD_LIBS}')
Libbrotlienc: ${have_libbrotlienc} (CFLAGS="${LIBBROTLIENC_CFLAGS}' LIBS='${LIBBROTLIENC_LIBS}')
Libbrotlidec: ${have_libbrotlidec} (CFLAGS="${LIBBROTLIDEC_CFLAGS}' LIBS='${LIBBROTLIDEC_LIBS}')
Third-party: Third-party:
http-parser: ${enable_third_party} http-parser: ${enable_third_party}
MRuby: ${have_mruby} (CFLAGS='${LIBMRUBY_CFLAGS}' LIBS='${LIBMRUBY_LIBS}') MRuby: ${have_mruby} (CFLAGS='${LIBMRUBY_CFLAGS}' LIBS='${LIBMRUBY_LIBS}')

View File

@@ -42,7 +42,9 @@ APIDOCS= \
nghttp2_hd_deflate_get_num_table_entries.rst \ nghttp2_hd_deflate_get_num_table_entries.rst \
nghttp2_hd_deflate_get_table_entry.rst \ nghttp2_hd_deflate_get_table_entry.rst \
nghttp2_hd_deflate_hd.rst \ nghttp2_hd_deflate_hd.rst \
nghttp2_hd_deflate_hd2.rst \
nghttp2_hd_deflate_hd_vec.rst \ nghttp2_hd_deflate_hd_vec.rst \
nghttp2_hd_deflate_hd_vec2.rst \
nghttp2_hd_deflate_new.rst \ nghttp2_hd_deflate_new.rst \
nghttp2_hd_deflate_new2.rst \ nghttp2_hd_deflate_new2.rst \
nghttp2_hd_inflate_change_table_size.rst \ nghttp2_hd_inflate_change_table_size.rst \
@@ -54,6 +56,7 @@ APIDOCS= \
nghttp2_hd_inflate_get_table_entry.rst \ nghttp2_hd_inflate_get_table_entry.rst \
nghttp2_hd_inflate_hd.rst \ nghttp2_hd_inflate_hd.rst \
nghttp2_hd_inflate_hd2.rst \ nghttp2_hd_inflate_hd2.rst \
nghttp2_hd_inflate_hd3.rst \
nghttp2_hd_inflate_new.rst \ nghttp2_hd_inflate_new.rst \
nghttp2_hd_inflate_new2.rst \ nghttp2_hd_inflate_new2.rst \
nghttp2_http2_strerror.rst \ nghttp2_http2_strerror.rst \
@@ -78,6 +81,7 @@ APIDOCS= \
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_pack_settings_payload.rst \ nghttp2_pack_settings_payload.rst \
nghttp2_pack_settings_payload2.rst \
nghttp2_priority_spec_check_default.rst \ nghttp2_priority_spec_check_default.rst \
nghttp2_priority_spec_default_init.rst \ nghttp2_priority_spec_default_init.rst \
nghttp2_priority_spec_init.rst \ nghttp2_priority_spec_init.rst \
@@ -91,6 +95,7 @@ APIDOCS= \
nghttp2_session_callbacks_new.rst \ nghttp2_session_callbacks_new.rst \
nghttp2_session_callbacks_set_before_frame_send_callback.rst \ nghttp2_session_callbacks_set_before_frame_send_callback.rst \
nghttp2_session_callbacks_set_data_source_read_length_callback.rst \ nghttp2_session_callbacks_set_data_source_read_length_callback.rst \
nghttp2_session_callbacks_set_data_source_read_length_callback2.rst \
nghttp2_session_callbacks_set_error_callback.rst \ nghttp2_session_callbacks_set_error_callback.rst \
nghttp2_session_callbacks_set_error_callback2.rst \ nghttp2_session_callbacks_set_error_callback2.rst \
nghttp2_session_callbacks_set_on_begin_frame_callback.rst \ nghttp2_session_callbacks_set_on_begin_frame_callback.rst \
@@ -107,9 +112,13 @@ APIDOCS= \
nghttp2_session_callbacks_set_on_invalid_header_callback2.rst \ nghttp2_session_callbacks_set_on_invalid_header_callback2.rst \
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_recv_callback.rst \ nghttp2_session_callbacks_set_recv_callback.rst \
nghttp2_session_callbacks_set_recv_callback2.rst \
nghttp2_session_callbacks_set_select_padding_callback.rst \ nghttp2_session_callbacks_set_select_padding_callback.rst \
nghttp2_session_callbacks_set_select_padding_callback2.rst \
nghttp2_session_callbacks_set_send_callback.rst \ nghttp2_session_callbacks_set_send_callback.rst \
nghttp2_session_callbacks_set_send_callback2.rst \
nghttp2_session_callbacks_set_send_data_callback.rst \ nghttp2_session_callbacks_set_send_data_callback.rst \
nghttp2_session_callbacks_set_unpack_extension_callback.rst \ nghttp2_session_callbacks_set_unpack_extension_callback.rst \
nghttp2_session_change_extpri_stream_priority.rst \ nghttp2_session_change_extpri_stream_priority.rst \
@@ -146,7 +155,9 @@ APIDOCS= \
nghttp2_session_get_stream_remote_window_size.rst \ nghttp2_session_get_stream_remote_window_size.rst \
nghttp2_session_get_stream_user_data.rst \ nghttp2_session_get_stream_user_data.rst \
nghttp2_session_mem_recv.rst \ nghttp2_session_mem_recv.rst \
nghttp2_session_mem_recv2.rst \
nghttp2_session_mem_send.rst \ nghttp2_session_mem_send.rst \
nghttp2_session_mem_send2.rst \
nghttp2_session_recv.rst \ nghttp2_session_recv.rst \
nghttp2_session_resume_data.rst \ nghttp2_session_resume_data.rst \
nghttp2_session_send.rst \ nghttp2_session_send.rst \
@@ -174,6 +185,7 @@ APIDOCS= \
nghttp2_strerror.rst \ nghttp2_strerror.rst \
nghttp2_submit_altsvc.rst \ nghttp2_submit_altsvc.rst \
nghttp2_submit_data.rst \ nghttp2_submit_data.rst \
nghttp2_submit_data2.rst \
nghttp2_submit_extension.rst \ nghttp2_submit_extension.rst \
nghttp2_submit_goaway.rst \ nghttp2_submit_goaway.rst \
nghttp2_submit_headers.rst \ nghttp2_submit_headers.rst \
@@ -183,7 +195,9 @@ APIDOCS= \
nghttp2_submit_priority_update.rst \ nghttp2_submit_priority_update.rst \
nghttp2_submit_push_promise.rst \ nghttp2_submit_push_promise.rst \
nghttp2_submit_request.rst \ nghttp2_submit_request.rst \
nghttp2_submit_request2.rst \
nghttp2_submit_response.rst \ nghttp2_submit_response.rst \
nghttp2_submit_response2.rst \
nghttp2_submit_rst_stream.rst \ nghttp2_submit_rst_stream.rst \
nghttp2_submit_settings.rst \ nghttp2_submit_settings.rst \
nghttp2_submit_shutdown_notice.rst \ nghttp2_submit_shutdown_notice.rst \
@@ -212,7 +226,6 @@ EXTRA_DIST = \
sources/h2load-howto.rst \ sources/h2load-howto.rst \
sources/building-android-binary.rst \ sources/building-android-binary.rst \
sources/contribute.rst \ sources/contribute.rst \
sources/security.rst \
_exts/rubydomain/LICENSE.rubydomain \ _exts/rubydomain/LICENSE.rubydomain \
_exts/rubydomain/__init__.py \ _exts/rubydomain/__init__.py \
_exts/rubydomain/rubydomain.py \ _exts/rubydomain/rubydomain.py \

View File

@@ -68,7 +68,7 @@ The example follows::
* Callback function invoked when |session| wants to send data to * Callback function invoked when |session| wants to send data to
* remote peer. * remote peer.
*/ */
typedef ssize_t (*nghttp2_send_callback) typedef nghttp2_ssize (*nghttp2_send_callback2)
(nghttp2_session *session, (nghttp2_session *session,
const uint8_t *data, size_t length, int flags, void *user_data); const uint8_t *data, size_t length, int flags, void *user_data);

View File

@@ -8,7 +8,7 @@ _h2load()
_get_comp_words_by_ref cur prev _get_comp_words_by_ref cur prev
case $cur in case $cur in
-*) -*)
COMPREPLY=( $( compgen -W '--requests --clients --threads --input-file --max-concurrent-streams --max-frame-size --window-bits --connection-window-bits --header --ciphers --tls13-ciphers --no-tls-proto --data --rate --rate-period --duration --warm-up-time --connection-active-timeout --connection-inactivity-timeout --timing-script-file --base-uri --alpn-list --h1 --header-table-size --encoder-header-table-size --log-file --qlog-file-base --connect-to --rps --groups --no-udp-gso --max-udp-payload-size --ktls --verbose --version --help ' -- "$cur" ) ) COMPREPLY=( $( compgen -W '--requests --clients --threads --input-file --max-concurrent-streams --max-frame-size --window-bits --connection-window-bits --header --ciphers --tls13-ciphers --no-tls-proto --data --rate --rate-period --duration --warm-up-time --connection-active-timeout --connection-inactivity-timeout --timing-script-file --base-uri --alpn-list --h1 --header-table-size --encoder-header-table-size --log-file --qlog-file-base --connect-to --rps --groups --no-udp-gso --max-udp-payload-size --ktls --sni --verbose --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" "Jan 21, 2024" "1.59.0" "nghttp2" .TH "H2LOAD" "1" "Mar 01, 2024" "1.60.0" "nghttp2"
.SH NAME .SH NAME
h2load \- HTTP/2 benchmarking tool h2load \- HTTP/2 benchmarking tool
.SH SYNOPSIS .SH SYNOPSIS
@@ -344,6 +344,12 @@ Enable ktls.
.UNINDENT .UNINDENT
.INDENT 0.0 .INDENT 0.0
.TP .TP
.B \-\-sni=<DNSNAME>
Send <DNSNAME> in TLS SNI, overriding the host name
specified in URI.
.UNINDENT
.INDENT 0.0
.TP
.B \-v, \-\-verbose .B \-v, \-\-verbose
Output debug information. Output debug information.
.UNINDENT .UNINDENT

View File

@@ -290,6 +290,11 @@ OPTIONS
Enable ktls. Enable ktls.
.. option:: --sni=<DNSNAME>
Send <DNSNAME> in TLS SNI, overriding the host name
specified in URI.
.. option:: -v, --verbose .. option:: -v, --verbose
Output debug information. Output debug information.

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" "Jan 21, 2024" "1.59.0" "nghttp2" .TH "NGHTTP" "1" "Mar 01, 2024" "1.60.0" "nghttp2"
.SH NAME .SH NAME
nghttp \- HTTP/2 client nghttp \- HTTP/2 client
.SH SYNOPSIS .SH SYNOPSIS

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" "Jan 21, 2024" "1.59.0" "nghttp2" .TH "NGHTTPD" "1" "Mar 01, 2024" "1.60.0" "nghttp2"
.SH NAME .SH NAME
nghttpd \- HTTP/2 server nghttpd \- HTTP/2 server
.SH SYNOPSIS .SH SYNOPSIS

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" "Jan 21, 2024" "1.59.0" "nghttp2" .TH "NGHTTPX" "1" "Mar 01, 2024" "1.60.0" "nghttp2"
.SH NAME .SH NAME
nghttpx \- HTTP/2 proxy nghttpx \- HTTP/2 proxy
.SH SYNOPSIS .SH SYNOPSIS

View File

@@ -40,28 +40,28 @@ most event-based architecture applications use is single thread per
core, and handling one connection I/O is done by single thread. core, and handling one connection I/O is done by single thread.
To feed input to :type:`nghttp2_session` object, one can use To feed input to :type:`nghttp2_session` object, one can use
`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` functions. `nghttp2_session_recv()` or `nghttp2_session_mem_recv2()` functions.
They behave similarly, and the difference is that They behave similarly, and the difference is that
`nghttp2_session_recv()` will use :type:`nghttp2_read_callback` to get `nghttp2_session_recv()` will use :type:`nghttp2_read_callback` to get
input. On the other hand, `nghttp2_session_mem_recv()` will take input. On the other hand, `nghttp2_session_mem_recv2()` will take
input as its parameter. If in doubt, use `nghttp2_session_mem_recv()` input as its parameter. If in doubt, use
since it is simpler, and could be faster since it avoids calling `nghttp2_session_mem_recv2()` since it is simpler, and could be faster
callback function. since it avoids calling callback function.
To get output from :type:`nghttp2_session` object, one can use To get output from :type:`nghttp2_session` object, one can use
`nghttp2_session_send()` or `nghttp2_session_mem_send()`. The `nghttp2_session_send()` or `nghttp2_session_mem_send2()`. The
difference between them is that the former uses difference between them is that the former uses
:type:`nghttp2_send_callback` to pass output to an application. On :type:`nghttp2_send_callback` to pass output to an application. On
the other hand, the latter returns the output to the caller. If in the other hand, the latter returns the output to the caller. If in
doubt, use `nghttp2_session_mem_send()` since it is simpler. But doubt, use `nghttp2_session_mem_send2()` since it is simpler. But
`nghttp2_session_send()` might be easier to use if the output buffer `nghttp2_session_send()` might be easier to use if the output buffer
an application has is fixed sized. an application has is fixed sized.
In general, an application should call `nghttp2_session_mem_send()` In general, an application should call `nghttp2_session_mem_send2()`
when it gets input from underlying connection. Since there is great when it gets input from underlying connection. Since there is great
chance to get something pushed into transmission queue while the call chance to get something pushed into transmission queue while the call
of `nghttp2_session_mem_send()`, it is recommended to call of `nghttp2_session_mem_send2()`, it is recommended to call
`nghttp2_session_mem_recv()` after `nghttp2_session_mem_send()`. `nghttp2_session_mem_recv2()` after `nghttp2_session_mem_send2()`.
There is a question when we are safe to close HTTP/2 session without There is a question when we are safe to close HTTP/2 session without
waiting for the closure of underlying connection. We offer 2 API waiting for the closure of underlying connection. We offer 2 API
@@ -70,7 +70,7 @@ calls for this: `nghttp2_session_want_read()` and
can destroy :type:`nghttp2_session`, and then close the underlying can destroy :type:`nghttp2_session`, and then close the underlying
connection. But make sure that the buffered output has been connection. But make sure that the buffered output has been
transmitted to the peer before closing the connection when transmitted to the peer before closing the connection when
`nghttp2_session_mem_send()` is used, since `nghttp2_session_mem_send2()` is used, since
`nghttp2_session_want_write()` does not take into account the `nghttp2_session_want_write()` does not take into account the
transmission of the buffered data outside of :type:`nghttp2_session`. transmission of the buffered data outside of :type:`nghttp2_session`.
@@ -87,18 +87,18 @@ The header files are also available online: :doc:`nghttp2.h` and
Remarks Remarks
------- -------
Do not call `nghttp2_session_send()`, `nghttp2_session_mem_send()`, Do not call `nghttp2_session_send()`, `nghttp2_session_mem_send2()`,
`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` from the `nghttp2_session_recv()` or `nghttp2_session_mem_recv2()` from the
nghttp2 callback functions directly or indirectly. It will lead to the nghttp2 callback functions directly or indirectly. It will lead to the
crash. You can submit requests or frames in the callbacks then call crash. You can submit requests or frames in the callbacks then call
these functions outside the callbacks. these functions outside the callbacks.
`nghttp2_session_send()` and `nghttp2_session_mem_send()` send first `nghttp2_session_send()` and `nghttp2_session_mem_send2()` send first
24 bytes of client magic string (MAGIC) 24 bytes of client magic string (MAGIC)
(:macro:`NGHTTP2_CLIENT_MAGIC`) on client configuration. The (:macro:`NGHTTP2_CLIENT_MAGIC`) on client configuration. The
applications are responsible to send SETTINGS frame as part of applications are responsible to send SETTINGS frame as part of
connection preface using `nghttp2_submit_settings()`. Similarly, connection preface using `nghttp2_submit_settings()`. Similarly,
`nghttp2_session_recv()` and `nghttp2_session_mem_recv()` consume `nghttp2_session_recv()` and `nghttp2_session_mem_recv2()` consume
MAGIC on server configuration unless MAGIC on server configuration unless
`nghttp2_option_set_no_recv_client_magic()` is used with nonzero `nghttp2_option_set_no_recv_client_magic()` is used with nonzero
option value. option value.
@@ -222,7 +222,7 @@ above, the following code does not work:
.. code-block:: c .. code-block:: c
nghttp2_submit_response(...) nghttp2_submit_response2(...)
nghttp2_submit_rst_stream(...) nghttp2_submit_rst_stream(...)
RST_STREAM cancels HEADERS (and DATA), and just RST_STREAM is sent. RST_STREAM cancels HEADERS (and DATA), and just RST_STREAM is sent.
@@ -258,9 +258,9 @@ For example, we will illustrate how to send `ALTSVC
const char *field; const char *field;
} alt_svc; } alt_svc;
ssize_t pack_extension_callback(nghttp2_session *session, uint8_t *buf, nghttp2_ssize pack_extension_callback(nghttp2_session *session, uint8_t *buf,
size_t len, const nghttp2_frame *frame, size_t len, const nghttp2_frame *frame,
void *user_data) { void *user_data) {
const alt_svc *altsvc = (const alt_svc *)frame->ext.payload; const alt_svc *altsvc = (const alt_svc *)frame->ext.payload;
size_t originlen = strlen(altsvc->origin); size_t originlen = strlen(altsvc->origin);
size_t fieldlen = strlen(altsvc->field); size_t fieldlen = strlen(altsvc->field);
@@ -497,8 +497,8 @@ order to receive and process PRIORITY_UPDATE frame, server has to call
NGHTTP2_PRIORITY_UPDATE)`` (see the above section), and pass the NGHTTP2_PRIORITY_UPDATE)`` (see the above section), and pass the
option to `nghttp2_session_server_new2()` or 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_request()`. It can can send Priority header field via `nghttp2_submit_request2()`. It
also send PRIORITY_UPDATE frame via can also send PRIORITY_UPDATE frame via
`nghttp2_submit_priority_update()`. Server processes Priority header `nghttp2_submit_priority_update()`. Server processes Priority header
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

View File

@@ -1 +0,0 @@
.. include:: ../doc/sources/security.rst

View File

@@ -18,7 +18,6 @@ Contents:
package_README package_README
contribute contribute
security
building-android-binary building-android-binary
tutorial-client tutorial-client
tutorial-server tutorial-server

View File

@@ -171,7 +171,7 @@ session object and several callbacks::
nghttp2_session_callbacks_new(&callbacks); nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); nghttp2_session_callbacks_set_send_callback2(callbacks, send_callback);
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);
@@ -246,8 +246,8 @@ HTTP request in the ``submit_request()`` function::
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_request(session_data->session, NULL, hdrs, stream_id = nghttp2_submit_request2(session_data->session, NULL, hdrs,
ARRLEN(hdrs), NULL, stream_data); ARRLEN(hdrs), NULL, stream_data);
if (stream_id < 0) { if (stream_id < 0) {
errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id)); errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id));
} }
@@ -258,11 +258,11 @@ HTTP request in the ``submit_request()`` function::
We build the HTTP request header fields in ``hdrs``, which is an array We build the HTTP request header fields in ``hdrs``, which is an array
of :type:`nghttp2_nv`. There are four header fields to be sent: of :type:`nghttp2_nv`. There are four header fields to be sent:
``:method``, ``:scheme``, ``:authority``, and ``:path``. To queue the ``:method``, ``:scheme``, ``:authority``, and ``:path``. To queue the
HTTP request, we call `nghttp2_submit_request()`. The ``stream_data`` HTTP request, we call `nghttp2_submit_request2()`. The ``stream_data``
is passed via the *stream_user_data* parameter, which is helpfully is passed via the *stream_user_data* parameter, which is helpfully
later passed back to callback functions. later passed back to callback functions.
`nghttp2_submit_request()` returns the newly assigned stream ID for `nghttp2_submit_request2()` returns the newly assigned stream ID for
the request. the request.
The next bufferevent callback is ``readcb()``, which is invoked when The next bufferevent callback is ``readcb()``, which is invoked when
@@ -270,12 +270,12 @@ data is available to read from the bufferevent input buffer::
static void readcb(struct bufferevent *bev, void *ptr) { static void readcb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr; http2_session_data *session_data = (http2_session_data *)ptr;
ssize_t readlen; nghttp2_ssize readlen;
struct evbuffer *input = bufferevent_get_input(bev); struct evbuffer *input = bufferevent_get_input(bev);
size_t datalen = evbuffer_get_length(input); size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1); unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen); readlen = nghttp2_session_mem_recv2(session_data->session, data, datalen);
if (readlen < 0) { if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen)); warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
delete_http2_session_data(session_data); delete_http2_session_data(session_data);
@@ -293,8 +293,8 @@ data is available to read from the bufferevent input buffer::
} }
In this function we feed all unprocessed, received data to the nghttp2 In this function we feed all unprocessed, received data to the nghttp2
session object using the `nghttp2_session_mem_recv()` function. session object using the `nghttp2_session_mem_recv2()` function.
`nghttp2_session_mem_recv()` processes the received data and may `nghttp2_session_mem_recv2()` processes the received data and may
invoke nghttp2 callbacks and queue frames for transmission. Since invoke nghttp2 callbacks and queue frames for transmission. Since
there may be pending frames for transmission, we call immediately there may be pending frames for transmission, we call immediately
``session_send()`` to send them. ``session_send()`` is defined as ``session_send()`` to send them. ``session_send()`` is defined as
@@ -313,15 +313,16 @@ follows::
The `nghttp2_session_send()` function serializes pending frames into The `nghttp2_session_send()` function serializes pending frames into
wire format and calls the ``send_callback()`` function to send them. wire format and calls the ``send_callback()`` function to send them.
``send_callback()`` has type :type:`nghttp2_send_callback` and is ``send_callback()`` has type :type:`nghttp2_send_callback2` and is
defined as:: defined as::
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data, static nghttp2_ssize send_callback(nghttp2_session *session _U_,
size_t length, int flags _U_, void *user_data) { const uint8_t *data, size_t length,
int flags _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data; http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev; struct bufferevent *bev = session_data->bev;
bufferevent_write(bev, data, length); bufferevent_write(bev, data, length);
return (ssize_t)length; return (nghttp2_ssize)length;
} }
Since we use bufferevent to abstract network I/O, we just write the Since we use bufferevent to abstract network I/O, we just write the

View File

@@ -24,11 +24,11 @@ deflater object for the dynamic header table. If in doubt, just
specify 4096 here, which is the default upper bound of dynamic header specify 4096 here, which is the default upper bound of dynamic header
table buffer size. table buffer size.
To encode header fields, use the `nghttp2_hd_deflate_hd()` function:: To encode header fields, use the `nghttp2_hd_deflate_hd2()` function::
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, nghttp2_ssize nghttp2_hd_deflate_hd2(nghttp2_hd_deflater *deflater,
uint8_t *buf, size_t buflen, uint8_t *buf, size_t buflen,
const nghttp2_nv *nva, size_t nvlen); const nghttp2_nv *nva, size_t nvlen);
The *deflater* is the deflater object initialized by The *deflater* is the deflater object initialized by
`nghttp2_hd_deflate_new()` described above. The encoded byte string is `nghttp2_hd_deflate_new()` described above. The encoded byte string is
@@ -44,7 +44,7 @@ cookies), set the :macro:`NGHTTP2_NV_FLAG_NO_INDEX` flag in
sensitive header fields by compression based attacks: This is achieved sensitive header fields by compression based attacks: This is achieved
by not inserting the header field into the dynamic header table. by not inserting the header field into the dynamic header table.
`nghttp2_hd_deflate_hd()` processes all headers given in *nva*. The `nghttp2_hd_deflate_hd2()` processes all headers given in *nva*. The
*nva* must include all request or response header fields to be sent in *nva* must include all request or response header fields to be sent in
one HEADERS (or optionally following (multiple) CONTINUATION one HEADERS (or optionally following (multiple) CONTINUATION
frame(s)). The *buf* must have enough space to store the encoded frame(s)). The *buf* must have enough space to store the encoded
@@ -55,13 +55,13 @@ of the encoded result length, use `nghttp2_hd_deflate_bound()`::
const nghttp2_nv *nva, size_t nvlen); const nghttp2_nv *nva, size_t nvlen);
Pass this function the same parameters (*deflater*, *nva*, and Pass this function the same parameters (*deflater*, *nva*, and
*nvlen*) which will be passed to `nghttp2_hd_deflate_hd()`. *nvlen*) which will be passed to `nghttp2_hd_deflate_hd2()`.
Subsequent calls to `nghttp2_hd_deflate_hd()` will use the current Subsequent calls to `nghttp2_hd_deflate_hd2()` will use the current
encoder state and perform differential encoding, which yields HPAC's encoder state and perform differential encoding, which yields HPAC's
fundamental compression gain. fundamental compression gain.
If `nghttp2_hd_deflate_hd()` fails, the failure is fatal and any If `nghttp2_hd_deflate_hd2()` fails, the failure is fatal and any
further calls with the same deflater object will fail. Thus it's very further calls with the same deflater object will fail. Thus it's very
important to use `nghttp2_hd_deflate_bound()` to determine the important to use `nghttp2_hd_deflate_bound()` to determine the
required size of the output buffer. required size of the output buffer.
@@ -78,14 +78,14 @@ header data. To initialize the object, use
int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr); int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
To inflate header data, use `nghttp2_hd_inflate_hd2()`:: To inflate header data, use `nghttp2_hd_inflate_hd3()`::
ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, nghttp2_ssize nghttp2_hd_inflate_hd3(nghttp2_hd_inflater *inflater,
nghttp2_nv *nv_out, int *inflate_flags, nghttp2_nv *nv_out, int *inflate_flags,
const uint8_t *in, size_t inlen, const uint8_t *in, size_t inlen,
int in_final); int in_final);
`nghttp2_hd_inflate_hd2()` reads a stream of bytes and outputs a `nghttp2_hd_inflate_hd3()` reads a stream of bytes and outputs a
single header field at a time. Multiple calls are normally required to single header field at a time. Multiple calls are normally required to
read a full stream of bytes and output all of the header fields. read a full stream of bytes and output all of the header fields.
@@ -119,7 +119,7 @@ If *in_final* is zero and the :macro:`NGHTTP2_HD_INFLATE_EMIT` flag is
not set, it indicates that all given data was processed. The caller not set, it indicates that all given data was processed. The caller
is required to pass additional data. is required to pass additional data.
Example usage of `nghttp2_hd_inflate_hd2()` is shown in the Example usage of `nghttp2_hd_inflate_hd3()` is shown in the
`inflate_header_block()` function in `deflate.c`_. `inflate_header_block()` function in `deflate.c`_.
Finally, to delete a :type:`nghttp2_hd_inflater` object, use Finally, to delete a :type:`nghttp2_hd_inflater` object, use

View File

@@ -220,7 +220,7 @@ session object and several callbacks::
nghttp2_session_callbacks_new(&callbacks); nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); nghttp2_session_callbacks_set_send_callback2(callbacks, send_callback);
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);
@@ -275,12 +275,12 @@ this pending data. To process the received data, we call the
``session_recv()`` function:: ``session_recv()`` function::
static int session_recv(http2_session_data *session_data) { static int session_recv(http2_session_data *session_data) {
ssize_t readlen; nghttp2_ssize readlen;
struct evbuffer *input = bufferevent_get_input(session_data->bev); struct evbuffer *input = bufferevent_get_input(session_data->bev);
size_t datalen = evbuffer_get_length(input); size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1); unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen); readlen = nghttp2_session_mem_recv2(session_data->session, data, datalen);
if (readlen < 0) { if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen)); warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
return -1; return -1;
@@ -296,9 +296,9 @@ this pending data. To process the received data, we call the
} }
In this function, we feed all unprocessed but already received data to In this function, we feed all unprocessed but already received data to
the nghttp2 session object using the `nghttp2_session_mem_recv()` the nghttp2 session object using the `nghttp2_session_mem_recv2()`
function. The `nghttp2_session_mem_recv()` function processes the data function. The `nghttp2_session_mem_recv2()` function processes the
and may both invoke the previously setup callbacks and also queue data and may both invoke the previously setup callbacks and also queue
outgoing frames. To send any pending outgoing frames, we immediately outgoing frames. To send any pending outgoing frames, we immediately
call ``session_send()``. call ``session_send()``.
@@ -316,11 +316,12 @@ The ``session_send()`` function is defined as follows::
The `nghttp2_session_send()` function serializes the frame into wire The `nghttp2_session_send()` function serializes the frame into wire
format and calls the ``send_callback()``, which is of type format and calls the ``send_callback()``, which is of type
:type:`nghttp2_send_callback`. The ``send_callback()`` is defined as :type:`nghttp2_send_callback2`. The ``send_callback()`` is defined as
follows:: follows::
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data, static nghttp2_ssize send_callback(nghttp2_session *session _U_,
size_t length, int flags _U_, void *user_data) { const uint8_t *data, size_t length,
int flags _U_, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data; http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev; struct bufferevent *bev = session_data->bev;
/* Avoid excessive buffering in server side. */ /* Avoid excessive buffering in server side. */
@@ -329,7 +330,7 @@ follows::
return NGHTTP2_ERR_WOULDBLOCK; return NGHTTP2_ERR_WOULDBLOCK;
} }
bufferevent_write(bev, data, length); bufferevent_write(bev, data, length);
return (ssize_t)length; return (nghttp2_ssize)length;
} }
Since we use bufferevent to abstract network I/O, we just write the Since we use bufferevent to abstract network I/O, we just write the
@@ -509,11 +510,11 @@ Sending the file content is performed by the ``send_response()`` function::
static int send_response(nghttp2_session *session, int32_t stream_id, static int send_response(nghttp2_session *session, int32_t stream_id,
nghttp2_nv *nva, size_t nvlen, int fd) { nghttp2_nv *nva, size_t nvlen, int fd) {
int rv; int rv;
nghttp2_data_provider data_prd; nghttp2_data_provider2 data_prd;
data_prd.source.fd = fd; data_prd.source.fd = fd;
data_prd.read_callback = file_read_callback; data_prd.read_callback = file_read_callback;
rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd); rv = nghttp2_submit_response2(session, stream_id, nva, nvlen, &data_prd);
if (rv != 0) { if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv)); warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1; return -1;
@@ -521,7 +522,7 @@ Sending the file content is performed by the ``send_response()`` function::
return 0; return 0;
} }
nghttp2 uses the :type:`nghttp2_data_provider` structure to send the nghttp2 uses the :type:`nghttp2_data_provider2` structure to send the
entity body to the remote peer. The ``source`` member of this entity body to the remote peer. The ``source`` member of this
structure is a union, which can be either a void pointer or an int structure is a union, which can be either a void pointer or an int
(which is intended to be used as file descriptor). In this example (which is intended to be used as file descriptor). In this example
@@ -529,11 +530,11 @@ server, we use it as a file descriptor. We also set the
``file_read_callback()`` callback function to read the contents of the ``file_read_callback()`` callback function to read the contents of the
file:: file::
static ssize_t file_read_callback(nghttp2_session *session _U_, static nghttp2_ssize file_read_callback(nghttp2_session *session _U_,
int32_t stream_id _U_, uint8_t *buf, int32_t stream_id _U_, uint8_t *buf,
size_t length, uint32_t *data_flags, size_t length, uint32_t *data_flags,
nghttp2_data_source *source, nghttp2_data_source *source,
void *user_data _U_) { void *user_data _U_) {
int fd = source->fd; int fd = source->fd;
ssize_t r; ssize_t r;
while ((r = read(fd, buf, length)) == -1 && errno == EINTR) while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
@@ -544,7 +545,7 @@ file::
if (r == 0) { if (r == 0) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF; *data_flags |= NGHTTP2_DATA_FLAG_EOF;
} }
return r; return (nghttp2_ssize)r;
} }
If an error occurs while reading the file, we return If an error occurs while reading the file, we return
@@ -553,8 +554,8 @@ library to send RST_STREAM to the stream. When all data has been
read, the :macro:`NGHTTP2_DATA_FLAG_EOF` flag is set to signal nghttp2 read, the :macro:`NGHTTP2_DATA_FLAG_EOF` flag is set to signal nghttp2
that we have finished reading the file. that we have finished reading the file.
The `nghttp2_submit_response()` function is used to send the response to the The `nghttp2_submit_response2()` function is used to send the response
remote peer. to the remote peer.
The ``on_stream_close_callback()`` function is invoked when the stream The ``on_stream_close_callback()`` function is invoked when the stream
is about to close:: is about to close::

View File

@@ -1,22 +1,25 @@
FROM debian:12 as build FROM debian:12 as build
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 make binutils autoconf automake autotools-dev libtool \ git clang make binutils autoconf automake autotools-dev libtool \
pkg-config \ 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 libelf-dev libbrotli-dev
RUN git clone --depth 1 -b OpenSSL_1_1_1w+quic https://github.com/quictls/openssl && \ RUN git clone --depth 1 -b v1.21.0 https://github.com/aws/aws-lc && \
cd openssl && \ cd aws-lc && \
./config --openssldir=/etc/ssl && \ cmake -B build -DDISABLE_GO=ON && \
make -j$(nproc) && \ make -j$(nproc) -C build && \
make install_sw && \ cmake --install build && \
cd .. && \ cd .. && \
rm -rf openssl rm -rf aws-lc
RUN git clone --depth 1 -b v1.1.0 https://github.com/ngtcp2/nghttp3 && \ RUN git clone --depth 1 -b v1.2.0 https://github.com/ngtcp2/nghttp3 && \
cd nghttp3 && \ cd nghttp3 && \
git submodule update --init --depth 1 && \
autoreconf -i && \ autoreconf -i && \
./configure --enable-lib-only && \ ./configure --enable-lib-only && \
make -j$(nproc) && \ make -j$(nproc) && \
@@ -24,12 +27,13 @@ RUN git clone --depth 1 -b v1.1.0 https://github.com/ngtcp2/nghttp3 && \
cd .. && \ cd .. && \
rm -rf nghttp3 rm -rf nghttp3
RUN git clone --depth 1 -b v1.2.0 https://github.com/ngtcp2/ngtcp2 && \ RUN git clone --depth 1 -b v1.3.0 https://github.com/ngtcp2/ngtcp2 && \
cd ngtcp2 && \ cd ngtcp2 && \
git submodule update --init --depth 1 && \
autoreconf -i && \ autoreconf -i && \
./configure --enable-lib-only \ ./configure --enable-lib-only --with-boringssl \
LIBTOOL_LDFLAGS="-static-libtool-libs" \ LIBTOOL_LDFLAGS="-static-libtool-libs" \
OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a -ldl -lpthread" \ BORINGSSL_LIBS="-l:libssl.a -l:libcrypto.a" \
PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \ PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \
make -j$(nproc) && \ make -j$(nproc) && \
make install-strip && \ make install-strip && \
@@ -42,21 +46,24 @@ RUN git clone --depth 1 -b v1.3.0 https://github.com/libbpf/libbpf && \
cd .. && \ cd .. && \
rm -rf libbpf rm -rf libbpf
RUN git clone --depth 1 https://github.com/nghttp2/nghttp2.git && \ RUN git clone --depth 1 -b $NGHTTP2_BRANCH https://github.com/nghttp2/nghttp2 && \
cd nghttp2 && \ cd nghttp2 && \
git submodule update --init && \ git submodule update --init --depth 1 && \
autoreconf -i && \ autoreconf -i && \
./configure --disable-examples --disable-hpack-tools \ ./configure --disable-examples --disable-hpack-tools \
--with-mruby --with-neverbleed \ --with-mruby \
--enable-http3 --with-libbpf \ --enable-http3 --with-libbpf \
--with-libbrotlienc --with-libbrotlidec \
CC=clang CXX=clang++ \ CC=clang CXX=clang++ \
LIBTOOL_LDFLAGS="-static-libtool-libs" \ LIBTOOL_LDFLAGS="-static-libtool-libs" \
OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a -ldl -pthread" \ OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a" \
LIBEV_LIBS="-l:libev.a" \ LIBEV_LIBS="-l:libev.a" \
JEMALLOC_LIBS="-l:libjemalloc.a" \ JEMALLOC_LIBS="-l:libjemalloc.a" \
LIBCARES_LIBS="-l:libcares.a" \ LIBCARES_LIBS="-l:libcares.a" \
ZLIB_LIBS="-l:libz.a" \ ZLIB_LIBS="-l:libz.a" \
LIBBPF_LIBS="-L/usr/local/lib64 -l:libbpf.a -l:libelf.a" \ LIBBPF_LIBS="-L/usr/local/lib64 -l:libbpf.a -l:libelf.a" \
LIBBROTLIENC_LIBS="-l:libbrotlienc.a -l:libbrotlicommon.a" \
LIBBROTLIDEC_LIBS="-l:libbrotlidec.a -l:libbrotlicommon.a" \
LDFLAGS="-static-libgcc -static-libstdc++" \ LDFLAGS="-static-libgcc -static-libstdc++" \
PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \ PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \
make -j$(nproc) install-strip && \ make -j$(nproc) install-strip && \

View File

@@ -56,6 +56,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
@@ -154,13 +155,14 @@ static void diec(const char *func, int error_code) {
} }
/* /*
* The implementation of nghttp2_send_callback type. Here we write * The implementation of nghttp2_send_callback2 type. Here we write
* |data| with size |length| to the network and return the number of * |data| with size |length| to the network and return the number of
* bytes actually written. See the documentation of * bytes actually written. See the documentation of
* nghttp2_send_callback for the details. * nghttp2_send_callback for the details.
*/ */
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data, static nghttp2_ssize send_callback(nghttp2_session *session,
size_t length, int flags, void *user_data) { const uint8_t *data, size_t length,
int flags, void *user_data) {
struct Connection *connection; struct Connection *connection;
int rv; int rv;
(void)session; (void)session;
@@ -184,13 +186,14 @@ static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
} }
/* /*
* The implementation of nghttp2_recv_callback type. Here we read data * The implementation of nghttp2_recv_callback2 type. Here we read
* from the network and write them in |buf|. The capacity of |buf| is * data from the network and write them in |buf|. The capacity of
* |length| bytes. Returns the number of bytes stored in |buf|. See * |buf| is |length| bytes. Returns the number of bytes stored in
* the documentation of nghttp2_recv_callback for the details. * |buf|. See the documentation of nghttp2_recv_callback for the
* details.
*/ */
static ssize_t recv_callback(nghttp2_session *session, uint8_t *buf, static nghttp2_ssize recv_callback(nghttp2_session *session, uint8_t *buf,
size_t length, int flags, void *user_data) { size_t length, int flags, void *user_data) {
struct Connection *connection; struct Connection *connection;
int rv; int rv;
(void)session; (void)session;
@@ -328,9 +331,9 @@ static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
* recv_callback is also required. * recv_callback is also required.
*/ */
static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) { static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); nghttp2_session_callbacks_set_send_callback2(callbacks, send_callback);
nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback); nghttp2_session_callbacks_set_recv_callback2(callbacks, recv_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);
@@ -458,8 +461,8 @@ static void submit_request(struct Connection *connection, struct Request *req) {
MAKE_NV("accept", "*/*"), MAKE_NV("accept", "*/*"),
MAKE_NV("user-agent", "nghttp2/" NGHTTP2_VERSION)}; MAKE_NV("user-agent", "nghttp2/" NGHTTP2_VERSION)};
stream_id = nghttp2_submit_request(connection->session, NULL, nva, stream_id = nghttp2_submit_request2(connection->session, NULL, nva,
sizeof(nva) / sizeof(nva[0]), NULL, req); sizeof(nva) / sizeof(nva[0]), NULL, req);
if (stream_id < 0) { if (stream_id < 0) {
diec("nghttp2_submit_request", stream_id); diec("nghttp2_submit_request", stream_id);

View File

@@ -29,6 +29,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#define MAKE_NV(K, V) \ #define MAKE_NV(K, V) \
@@ -93,7 +94,7 @@ int main(void) {
static void deflate(nghttp2_hd_deflater *deflater, static void deflate(nghttp2_hd_deflater *deflater,
nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva, nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva,
size_t nvlen) { size_t nvlen) {
ssize_t rv; nghttp2_ssize rv;
uint8_t *buf; uint8_t *buf;
size_t buflen; size_t buflen;
size_t outlen; size_t outlen;
@@ -118,10 +119,10 @@ static void deflate(nghttp2_hd_deflater *deflater,
buflen = nghttp2_hd_deflate_bound(deflater, nva, nvlen); buflen = nghttp2_hd_deflate_bound(deflater, nva, nvlen);
buf = malloc(buflen); buf = malloc(buflen);
rv = nghttp2_hd_deflate_hd(deflater, buf, buflen, nva, nvlen); rv = nghttp2_hd_deflate_hd2(deflater, buf, buflen, nva, nvlen);
if (rv < 0) { if (rv < 0) {
fprintf(stderr, "nghttp2_hd_deflate_hd() failed with error: %s\n", fprintf(stderr, "nghttp2_hd_deflate_hd2() failed with error: %s\n",
nghttp2_strerror((int)rv)); nghttp2_strerror((int)rv));
free(buf); free(buf);
@@ -166,17 +167,18 @@ static void deflate(nghttp2_hd_deflater *deflater,
int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in, int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
size_t inlen, int final) { size_t inlen, int final) {
ssize_t rv; nghttp2_ssize rv;
for (;;) { for (;;) {
nghttp2_nv nv; nghttp2_nv nv;
int inflate_flags = 0; int inflate_flags = 0;
size_t proclen; size_t proclen;
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, in, inlen, final); rv =
nghttp2_hd_inflate_hd3(inflater, &nv, &inflate_flags, in, inlen, final);
if (rv < 0) { if (rv < 0) {
fprintf(stderr, "inflate failed with error code %zd", rv); fprintf(stderr, "inflate failed with error code %td", rv);
return -1; return -1;
} }

View File

@@ -63,6 +63,7 @@ char *strndup(const char *s, size_t size);
#include <event2/bufferevent_ssl.h> #include <event2/bufferevent_ssl.h>
#include <event2/dns.h> #include <event2/dns.h>
#define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include "url-parser/url_parser.h" #include "url-parser/url_parser.h"
@@ -196,18 +197,19 @@ static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen) {
fprintf(f, "\n"); fprintf(f, "\n");
} }
/* nghttp2_send_callback. Here we transmit the |data|, |length| bytes, /* nghttp2_send_callback2. Here we transmit the |data|, |length|
to the network. Because we are using libevent bufferevent, we just bytes, to the network. Because we are using libevent bufferevent,
write those bytes into bufferevent buffer. */ we just write those bytes into bufferevent buffer. */
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data, static nghttp2_ssize send_callback(nghttp2_session *session,
size_t length, int flags, void *user_data) { const uint8_t *data, size_t length,
int flags, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data; http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev; struct bufferevent *bev = session_data->bev;
(void)session; (void)session;
(void)flags; (void)flags;
bufferevent_write(bev, data, length); bufferevent_write(bev, data, length);
return (ssize_t)length; return (nghttp2_ssize)length;
} }
/* nghttp2_on_header_callback: Called when nghttp2 library emits /* nghttp2_on_header_callback: Called when nghttp2 library emits
@@ -342,7 +344,7 @@ static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_session_callbacks_new(&callbacks); nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); nghttp2_session_callbacks_set_send_callback2(callbacks, send_callback);
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);
@@ -403,8 +405,8 @@ static void submit_request(http2_session_data *session_data) {
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_request(session_data->session, NULL, hdrs, stream_id = nghttp2_submit_request2(session_data->session, NULL, hdrs,
ARRLEN(hdrs), NULL, stream_data); ARRLEN(hdrs), NULL, stream_data);
if (stream_id < 0) { if (stream_id < 0) {
errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id)); errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id));
} }
@@ -431,12 +433,12 @@ static int session_send(http2_session_data *session_data) {
context. To send them, we call session_send() in the end. */ context. To send them, we call session_send() in the end. */
static void readcb(struct bufferevent *bev, void *ptr) { static void readcb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr; http2_session_data *session_data = (http2_session_data *)ptr;
ssize_t readlen; nghttp2_ssize readlen;
struct evbuffer *input = bufferevent_get_input(bev); struct evbuffer *input = bufferevent_get_input(bev);
size_t datalen = evbuffer_get_length(input); size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1); unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen); readlen = nghttp2_session_mem_recv2(session_data->session, data, datalen);
if (readlen < 0) { if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen)); warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
delete_http2_session_data(session_data); delete_http2_session_data(session_data);

View File

@@ -71,6 +71,7 @@
#include <event2/bufferevent_ssl.h> #include <event2/bufferevent_ssl.h>
#include <event2/listener.h> #include <event2/listener.h>
#define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#define OUTPUT_WOULDBLOCK_THRESHOLD (1 << 16) #define OUTPUT_WOULDBLOCK_THRESHOLD (1 << 16)
@@ -277,16 +278,16 @@ static int session_send(http2_session_data *session_data) {
} }
/* Read the data in the bufferevent and feed them into nghttp2 library /* Read the data in the bufferevent and feed them into nghttp2 library
function. Invocation of nghttp2_session_mem_recv() may make function. Invocation of nghttp2_session_mem_recv2() may make
additional pending frames, so call session_send() at the end of the additional pending frames, so call session_send() at the end of the
function. */ function. */
static int session_recv(http2_session_data *session_data) { static int session_recv(http2_session_data *session_data) {
ssize_t readlen; nghttp2_ssize readlen;
struct evbuffer *input = bufferevent_get_input(session_data->bev); struct evbuffer *input = bufferevent_get_input(session_data->bev);
size_t datalen = evbuffer_get_length(input); size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1); unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen); readlen = nghttp2_session_mem_recv2(session_data->session, data, datalen);
if (readlen < 0) { if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen)); warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
return -1; return -1;
@@ -301,8 +302,9 @@ static int session_recv(http2_session_data *session_data) {
return 0; return 0;
} }
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data, static nghttp2_ssize send_callback(nghttp2_session *session,
size_t length, int flags, void *user_data) { const uint8_t *data, size_t length,
int flags, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data; http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev; struct bufferevent *bev = session_data->bev;
(void)session; (void)session;
@@ -314,7 +316,7 @@ static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
return NGHTTP2_ERR_WOULDBLOCK; return NGHTTP2_ERR_WOULDBLOCK;
} }
bufferevent_write(bev, data, length); bufferevent_write(bev, data, length);
return (ssize_t)length; return (nghttp2_ssize)length;
} }
/* Returns nonzero if the string |s| ends with the substring |sub| */ /* Returns nonzero if the string |s| ends with the substring |sub| */
@@ -370,11 +372,11 @@ static char *percent_decode(const uint8_t *value, size_t valuelen) {
return res; return res;
} }
static ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, static nghttp2_ssize file_read_callback(nghttp2_session *session,
uint8_t *buf, size_t length, int32_t stream_id, uint8_t *buf,
uint32_t *data_flags, size_t length, uint32_t *data_flags,
nghttp2_data_source *source, nghttp2_data_source *source,
void *user_data) { void *user_data) {
int fd = source->fd; int fd = source->fd;
ssize_t r; ssize_t r;
(void)session; (void)session;
@@ -389,17 +391,17 @@ static ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
if (r == 0) { if (r == 0) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF; *data_flags |= NGHTTP2_DATA_FLAG_EOF;
} }
return r; return (nghttp2_ssize)r;
} }
static int send_response(nghttp2_session *session, int32_t stream_id, static int send_response(nghttp2_session *session, int32_t stream_id,
nghttp2_nv *nva, size_t nvlen, int fd) { nghttp2_nv *nva, size_t nvlen, int fd) {
int rv; int rv;
nghttp2_data_provider data_prd; nghttp2_data_provider2 data_prd;
data_prd.source.fd = fd; data_prd.source.fd = fd;
data_prd.read_callback = file_read_callback; data_prd.read_callback = file_read_callback;
rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd); rv = nghttp2_submit_response2(session, stream_id, nva, nvlen, &data_prd);
if (rv != 0) { if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv)); warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1; return -1;
@@ -590,7 +592,7 @@ static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_session_callbacks_new(&callbacks); nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); nghttp2_session_callbacks_set_send_callback2(callbacks, send_callback);
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);

View File

@@ -40,7 +40,7 @@ namespace {
void send_pending(nghttp2_session *session) { void send_pending(nghttp2_session *session) {
for (;;) { for (;;) {
const uint8_t *data; const uint8_t *data;
auto n = nghttp2_session_mem_send(session, &data); auto n = nghttp2_session_mem_send2(session, &data);
if (n == 0) { if (n == 0) {
return; return;
} }
@@ -70,7 +70,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
nghttp2_settings_entry iv{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}; nghttp2_settings_entry iv{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100};
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1); nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1);
send_pending(session); send_pending(session);
nghttp2_session_mem_recv(session, data, size); nghttp2_session_mem_recv2(session, data, size);
send_pending(session); send_pending(session);
nghttp2_session_del(session); nghttp2_session_del(session);

View File

@@ -44,7 +44,7 @@ namespace {
void send_pending(nghttp2_session *session) { void send_pending(nghttp2_session *session) {
for (;;) { for (;;) {
const uint8_t *data; const uint8_t *data;
auto n = nghttp2_session_mem_send(session, &data); auto n = nghttp2_session_mem_send2(session, &data);
if (n == 0) { if (n == 0) {
return; return;
} }
@@ -87,7 +87,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
send_pending(session); send_pending(session);
std::vector<uint8_t> d = data_provider.ConsumeRemainingBytes<uint8_t>(); std::vector<uint8_t> d = data_provider.ConsumeRemainingBytes<uint8_t>();
nghttp2_session_mem_recv(session, d.data(), d.size()); nghttp2_session_mem_recv2(session, d.data(), d.size());
send_pending(session); send_pending(session);

6
go.mod
View File

@@ -6,7 +6,7 @@ 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.41.0 github.com/quic-go/quic-go v0.41.0
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.20.0 golang.org/x/net v0.21.0
) )
require ( require (
@@ -15,10 +15,10 @@ require (
github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect
github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect
go.uber.org/mock v0.3.0 // indirect go.uber.org/mock v0.3.0 // indirect
golang.org/x/crypto v0.18.0 // indirect golang.org/x/crypto v0.19.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/mod v0.11.0 // indirect golang.org/x/mod v0.11.0 // indirect
golang.org/x/sys v0.16.0 // indirect golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.9.1 // indirect golang.org/x/tools v0.9.1 // indirect
) )

12
go.sum
View File

@@ -34,17 +34,17 @@ github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20240121064059-46ccb0a462a8 h1:zKJxuRe+
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.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=

View File

@@ -58,7 +58,7 @@ func TestH1H1PlainGETClose(t *testing.T) {
// 501 status code // 501 status code
func TestH1H1InvalidMethod(t *testing.T) { func TestH1H1InvalidMethod(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
@@ -82,7 +82,7 @@ func TestH1H1InvalidMethod(t *testing.T) {
// contains multiple Content-Length header fields. // contains multiple Content-Length header fields.
func TestH1H1MultipleRequestCL(t *testing.T) { func TestH1H1MultipleRequestCL(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }
@@ -255,7 +255,7 @@ func TestH1H1HostRewrite(t *testing.T) {
// characters in host header field. // characters in host header field.
func TestH1H1BadHost(t *testing.T) { func TestH1H1BadHost(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
@@ -281,7 +281,7 @@ func TestH1H1BadHost(t *testing.T) {
// bad characters in authority component of requset URI. // bad characters in authority component of requset URI.
func TestH1H1BadAuthority(t *testing.T) { func TestH1H1BadAuthority(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
@@ -307,7 +307,7 @@ func TestH1H1BadAuthority(t *testing.T) {
// bad characters in scheme component of requset URI. // bad characters in scheme component of requset URI.
func TestH1H1BadScheme(t *testing.T) { func TestH1H1BadScheme(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
@@ -394,7 +394,7 @@ func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
// backend. // backend.
func TestH1H1RequestTrailer(t *testing.T) { func TestH1H1RequestTrailer(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
buf := make([]byte, 4096) buf := make([]byte, 4096)
for { for {
_, err := r.Body.Read(buf) _, err := r.Body.Read(buf)
@@ -436,7 +436,7 @@ func TestH1H1HeaderFieldBufferPath(t *testing.T) {
// limit. // limit.
opts := options{ opts := options{
args: []string{"--request-header-field-buffer=100"}, args: []string{"--request-header-field-buffer=100"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatal("execution path should not be here") t.Fatal("execution path should not be here")
}, },
} }
@@ -460,7 +460,7 @@ func TestH1H1HeaderFieldBufferPath(t *testing.T) {
func TestH1H1HeaderFieldBuffer(t *testing.T) { func TestH1H1HeaderFieldBuffer(t *testing.T) {
opts := options{ opts := options{
args: []string{"--request-header-field-buffer=10"}, args: []string{"--request-header-field-buffer=10"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatal("execution path should not be here") t.Fatal("execution path should not be here")
}, },
} }
@@ -483,7 +483,7 @@ func TestH1H1HeaderFieldBuffer(t *testing.T) {
func TestH1H1HeaderFields(t *testing.T) { func TestH1H1HeaderFields(t *testing.T) {
opts := options{ opts := options{
args: []string{"--max-request-header-fields=1"}, args: []string{"--max-request-header-fields=1"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatal("execution path should not be here") t.Fatal("execution path should not be here")
}, },
} }
@@ -533,7 +533,7 @@ func TestH1H1Websocket(t *testing.T) {
func TestH1H1ReqPhaseSetHeader(t *testing.T) { func TestH1H1ReqPhaseSetHeader(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/req-set-header.rb"}, args: []string{"--mruby-file=" + testDir + "/req-set-header.rb"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("User-Agent"), "mruby"; got != want { if got, want := r.Header.Get("User-Agent"), "mruby"; got != want {
t.Errorf("User-Agent = %v; want %v", got, want) t.Errorf("User-Agent = %v; want %v", got, want)
} }
@@ -559,7 +559,7 @@ func TestH1H1ReqPhaseSetHeader(t *testing.T) {
func TestH1H1ReqPhaseReturn(t *testing.T) { func TestH1H1ReqPhaseReturn(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/req-return.rb"}, args: []string{"--mruby-file=" + testDir + "/req-return.rb"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
} }
@@ -599,7 +599,7 @@ func TestH1H1ReqPhaseReturn(t *testing.T) {
func TestH1H1ReqPhaseReturnCONNECTMethod(t *testing.T) { func TestH1H1ReqPhaseReturnCONNECTMethod(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/req-return.rb"}, args: []string{"--mruby-file=" + testDir + "/req-return.rb"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
} }
@@ -884,7 +884,7 @@ func TestH1H1CONNECTMethodFailure(t *testing.T) {
func TestH1H2NoHost(t *testing.T) { func TestH1H2NoHost(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge"}, args: []string{"--http2-bridge"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }
@@ -978,7 +978,7 @@ func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
func TestH1H2CrumbleCookie(t *testing.T) { func TestH1H2CrumbleCookie(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge"}, args: []string{"--http2-bridge"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want { if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
t.Errorf("Cookie: %v; want %v", got, want) t.Errorf("Cookie: %v; want %v", got, want)
} }
@@ -1006,7 +1006,7 @@ func TestH1H2CrumbleCookie(t *testing.T) {
func TestH1H2GenerateVia(t *testing.T) { func TestH1H2GenerateVia(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge"}, args: []string{"--http2-bridge"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want { if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want) t.Errorf("Via: %v; want %v", got, want)
} }
@@ -1092,7 +1092,7 @@ func TestH1H2ReqPhaseReturn(t *testing.T) {
"--http2-bridge", "--http2-bridge",
"--mruby-file=" + testDir + "/req-return.rb", "--mruby-file=" + testDir + "/req-return.rb",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
} }
@@ -1172,7 +1172,7 @@ func TestH1H2RespPhaseReturn(t *testing.T) {
func TestH1H2TE(t *testing.T) { func TestH1H2TE(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge"}, args: []string{"--http2-bridge"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("te"), "trailers"; got != want { if got, want := r.Header.Get("te"), "trailers"; got != want {
t.Errorf("te: %v; want %v", got, want) t.Errorf("te: %v; want %v", got, want)
} }
@@ -1200,7 +1200,7 @@ func TestH1H2TE(t *testing.T) {
func TestH1APIBackendconfig(t *testing.T) { func TestH1APIBackendconfig(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -1242,7 +1242,7 @@ backend=127.0.0.1,3011
func TestH1APIBackendconfigQuery(t *testing.T) { func TestH1APIBackendconfigQuery(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -1284,7 +1284,7 @@ backend=127.0.0.1,3011
func TestH1APIBackendconfigBadMethod(t *testing.T) { func TestH1APIBackendconfigBadMethod(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -1325,7 +1325,7 @@ backend=127.0.0.1,3011
func TestH1APIConfigrevision(t *testing.T) { func TestH1APIConfigrevision(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -1368,7 +1368,7 @@ func TestH1APIConfigrevision(t *testing.T) {
func TestH1APINotFound(t *testing.T) { func TestH1APINotFound(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -1409,7 +1409,7 @@ backend=127.0.0.1,3011
func TestH1Healthmon(t *testing.T) { func TestH1Healthmon(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3011;healthmon;no-tls"}, args: []string{"-f127.0.0.1,3011;healthmon;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3011, connectPort: 3011,
@@ -1434,7 +1434,7 @@ func TestH1Healthmon(t *testing.T) {
func TestH1ResponseBeforeRequestEnd(t *testing.T) { func TestH1ResponseBeforeRequestEnd(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/req-return.rb"}, args: []string{"--mruby-file=" + testDir + "/req-return.rb"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatal("request should not be forwarded") t.Fatal("request should not be forwarded")
}, },
} }
@@ -1462,7 +1462,7 @@ func TestH1ResponseBeforeRequestEnd(t *testing.T) {
// if the backend chunked encoded response ends prematurely. // if the backend chunked encoded response ends prematurely.
func TestH1H1ChunkedEndsPrematurely(t *testing.T) { func TestH1H1ChunkedEndsPrematurely(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
hj, ok := w.(http.Hijacker) hj, ok := w.(http.Hijacker)
if !ok { if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
@@ -1495,7 +1495,7 @@ func TestH1H1ChunkedEndsPrematurely(t *testing.T) {
// request which contains malformed transfer-encoding. // request which contains malformed transfer-encoding.
func TestH1H1RequestMalformedTransferEncoding(t *testing.T) { func TestH1H1RequestMalformedTransferEncoding(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }
@@ -1523,7 +1523,7 @@ func TestH1H1RequestMalformedTransferEncoding(t *testing.T) {
// its response contains malformed transfer-encoding. // its response contains malformed transfer-encoding.
func TestH1H1ResponseMalformedTransferEncoding(t *testing.T) { func TestH1H1ResponseMalformedTransferEncoding(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
hj, ok := w.(http.Hijacker) hj, ok := w.(http.Hijacker)
if !ok { if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
@@ -1559,7 +1559,7 @@ func TestH1H1ResponseMalformedTransferEncoding(t *testing.T) {
// its response contains unknown transfer-encoding. // its response contains unknown transfer-encoding.
func TestH1H1ResponseUnknownTransferEncoding(t *testing.T) { func TestH1H1ResponseUnknownTransferEncoding(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
hj, ok := w.(http.Hijacker) hj, ok := w.(http.Hijacker)
if !ok { if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
@@ -1607,7 +1607,7 @@ func TestH1H1ResponseUnknownTransferEncoding(t *testing.T) {
// HTTP/1.0 request which contains transfer-encoding. // HTTP/1.0 request which contains transfer-encoding.
func TestH1H1RequestHTTP10TransferEncoding(t *testing.T) { func TestH1H1RequestHTTP10TransferEncoding(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }

View File

@@ -40,7 +40,7 @@ func TestH2H1PlainGET(t *testing.T) {
func TestH2H1AddXfp(t *testing.T) { func TestH2H1AddXfp(t *testing.T) {
opts := options{ opts := options{
args: []string{"--no-strip-incoming-x-forwarded-proto"}, args: []string{"--no-strip-incoming-x-forwarded-proto"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xfp := r.Header.Get("X-Forwarded-Proto") xfp := r.Header.Get("X-Forwarded-Proto")
if got, want := xfp, "foo, http"; got != want { if got, want := xfp, "foo, http"; got != want {
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
@@ -72,7 +72,7 @@ func TestH2H1NoAddXfp(t *testing.T) {
"--no-add-x-forwarded-proto", "--no-add-x-forwarded-proto",
"--no-strip-incoming-x-forwarded-proto", "--no-strip-incoming-x-forwarded-proto",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xfp := r.Header.Get("X-Forwarded-Proto") xfp := r.Header.Get("X-Forwarded-Proto")
if got, want := xfp, "foo"; got != want { if got, want := xfp, "foo"; got != want {
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
@@ -100,7 +100,7 @@ func TestH2H1NoAddXfp(t *testing.T) {
// x-forwarded-proto header field. // x-forwarded-proto header field.
func TestH2H1StripXfp(t *testing.T) { func TestH2H1StripXfp(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xfp := r.Header.Get("X-Forwarded-Proto") xfp := r.Header.Get("X-Forwarded-Proto")
if got, want := xfp, "http"; got != want { if got, want := xfp, "http"; got != want {
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
@@ -129,7 +129,7 @@ func TestH2H1StripXfp(t *testing.T) {
func TestH2H1StripNoAddXfp(t *testing.T) { func TestH2H1StripNoAddXfp(t *testing.T) {
opts := options{ opts := options{
args: []string{"--no-add-x-forwarded-proto"}, args: []string{"--no-add-x-forwarded-proto"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, found := r.Header["X-Forwarded-Proto"]; found { if got, found := r.Header["X-Forwarded-Proto"]; found {
t.Errorf("X-Forwarded-Proto = %q; want nothing", got) t.Errorf("X-Forwarded-Proto = %q; want nothing", got)
} }
@@ -157,7 +157,7 @@ func TestH2H1StripNoAddXfp(t *testing.T) {
func TestH2H1AddXff(t *testing.T) { func TestH2H1AddXff(t *testing.T) {
opts := options{ opts := options{
args: []string{"--add-x-forwarded-for"}, args: []string{"--add-x-forwarded-for"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For") xff := r.Header.Get("X-Forwarded-For")
want := "127.0.0.1" want := "127.0.0.1"
if xff != want { if xff != want {
@@ -184,7 +184,7 @@ func TestH2H1AddXff(t *testing.T) {
func TestH2H1AddXff2(t *testing.T) { func TestH2H1AddXff2(t *testing.T) {
opts := options{ opts := options{
args: []string{"--add-x-forwarded-for"}, args: []string{"--add-x-forwarded-for"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For") xff := r.Header.Get("X-Forwarded-For")
want := "host, 127.0.0.1" want := "host, 127.0.0.1"
if xff != want { if xff != want {
@@ -214,7 +214,7 @@ func TestH2H1AddXff2(t *testing.T) {
func TestH2H1StripXff(t *testing.T) { func TestH2H1StripXff(t *testing.T) {
opts := options{ opts := options{
args: []string{"--strip-incoming-x-forwarded-for"}, args: []string{"--strip-incoming-x-forwarded-for"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if xff, found := r.Header["X-Forwarded-For"]; found { if xff, found := r.Header["X-Forwarded-For"]; found {
t.Errorf("X-Forwarded-For = %v; want nothing", xff) t.Errorf("X-Forwarded-For = %v; want nothing", xff)
} }
@@ -245,7 +245,7 @@ func TestH2H1StripAddXff(t *testing.T) {
"--strip-incoming-x-forwarded-for", "--strip-incoming-x-forwarded-for",
"--add-x-forwarded-for", "--add-x-forwarded-for",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For") xff := r.Header.Get("X-Forwarded-For")
want := "127.0.0.1" want := "127.0.0.1"
if xff != want { if xff != want {
@@ -275,7 +275,7 @@ func TestH2H1StripAddXff(t *testing.T) {
func TestH2H1AddForwardedObfuscated(t *testing.T) { func TestH2H1AddForwardedObfuscated(t *testing.T) {
opts := options{ opts := options{
args: []string{"--add-forwarded=by,for,host,proto"}, args: []string{"--add-forwarded=by,for,host,proto"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
pattern := fmt.Sprintf(`by=_[^;]+;for=_[^;]+;host="127\.0\.0\.1:%v";proto=http`, serverPort) pattern := fmt.Sprintf(`by=_[^;]+;for=_[^;]+;host="127\.0\.0\.1:%v";proto=http`, serverPort)
validFwd := regexp.MustCompile(pattern) validFwd := regexp.MustCompile(pattern)
got := r.Header.Get("Forwarded") got := r.Header.Get("Forwarded")
@@ -304,7 +304,7 @@ func TestH2H1AddForwardedObfuscated(t *testing.T) {
func TestH2H1AddForwardedByIP(t *testing.T) { func TestH2H1AddForwardedByIP(t *testing.T) {
opts := options{ opts := options{
args: []string{"--add-forwarded=by,for", "--forwarded-by=ip"}, args: []string{"--add-forwarded=by,for", "--forwarded-by=ip"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
pattern := fmt.Sprintf(`by="127\.0\.0\.1:%v";for=_[^;]+`, serverPort) pattern := fmt.Sprintf(`by="127\.0\.0\.1:%v";for=_[^;]+`, serverPort)
validFwd := regexp.MustCompile(pattern) validFwd := regexp.MustCompile(pattern)
if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) { if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
@@ -335,7 +335,7 @@ func TestH2H1AddForwardedForIP(t *testing.T) {
"--forwarded-by=_alpha", "--forwarded-by=_alpha",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
want := fmt.Sprintf(`by=_alpha;for=127.0.0.1;host="127.0.0.1:%v";proto=http`, serverPort) want := fmt.Sprintf(`by=_alpha;for=127.0.0.1;host="127.0.0.1:%v";proto=http`, serverPort)
if got := r.Header.Get("Forwarded"); got != want { if got := r.Header.Get("Forwarded"); got != want {
t.Errorf("Forwarded = %v; want %v", got, want) t.Errorf("Forwarded = %v; want %v", got, want)
@@ -362,7 +362,7 @@ func TestH2H1AddForwardedForIP(t *testing.T) {
func TestH2H1AddForwardedMerge(t *testing.T) { func TestH2H1AddForwardedMerge(t *testing.T) {
opts := options{ opts := options{
args: []string{"--add-forwarded=proto"}, args: []string{"--add-forwarded=proto"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Forwarded"), `host=foo, proto=http`; got != want { if got, want := r.Header.Get("Forwarded"), `host=foo, proto=http`; got != want {
t.Errorf("Forwarded = %v; want %v", got, want) t.Errorf("Forwarded = %v; want %v", got, want)
} }
@@ -394,7 +394,7 @@ func TestH2H1AddForwardedStrip(t *testing.T) {
"--strip-incoming-forwarded", "--strip-incoming-forwarded",
"--add-forwarded=proto", "--add-forwarded=proto",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Forwarded"), `proto=http`; got != want { if got, want := r.Header.Get("Forwarded"), `proto=http`; got != want {
t.Errorf("Forwarded = %v; want %v", got, want) t.Errorf("Forwarded = %v; want %v", got, want)
} }
@@ -422,7 +422,7 @@ func TestH2H1AddForwardedStrip(t *testing.T) {
func TestH2H1StripForwarded(t *testing.T) { func TestH2H1StripForwarded(t *testing.T) {
opts := options{ opts := options{
args: []string{"--strip-incoming-forwarded"}, args: []string{"--strip-incoming-forwarded"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, found := r.Header["Forwarded"]; found { if got, found := r.Header["Forwarded"]; found {
t.Errorf("Forwarded = %v; want nothing", got) t.Errorf("Forwarded = %v; want nothing", got)
} }
@@ -454,7 +454,7 @@ func TestH2H1AddForwardedStatic(t *testing.T) {
"--add-forwarded=by,for", "--add-forwarded=by,for",
"--forwarded-by=_alpha", "--forwarded-by=_alpha",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
pattern := `by=_alpha;for=_[^;]+` pattern := `by=_alpha;for=_[^;]+`
validFwd := regexp.MustCompile(pattern) validFwd := regexp.MustCompile(pattern)
if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) { if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
@@ -480,7 +480,7 @@ func TestH2H1AddForwardedStatic(t *testing.T) {
// from backend server. // from backend server.
func TestH2H1GenerateVia(t *testing.T) { func TestH2H1GenerateVia(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "2 nghttpx"; got != want { if got, want := r.Header.Get("Via"), "2 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want) t.Errorf("Via: %v; want %v", got, want)
} }
@@ -639,7 +639,7 @@ func TestH2H1BadRequestCL(t *testing.T) {
// response body size. // response body size.
func TestH2H1BadResponseCL(t *testing.T) { func TestH2H1BadResponseCL(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
// we set content-length: 1024, but only send 3 bytes. // we set content-length: 1024, but only send 3 bytes.
w.Header().Add("Content-Length", "1024") w.Header().Add("Content-Length", "1024")
if _, err := w.Write([]byte("foo")); err != nil { if _, err := w.Write([]byte("foo")); err != nil {
@@ -667,7 +667,7 @@ func TestH2H1BadResponseCL(t *testing.T) {
// works. // works.
func TestH2H1LocationRewrite(t *testing.T) { func TestH2H1LocationRewrite(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
// TODO we cannot get st.ts's port number // TODO we cannot get st.ts's port number
// here.. 8443 is just a place holder. We // here.. 8443 is just a place holder. We
// ignore it on rewrite. // ignore it on rewrite.
@@ -693,7 +693,7 @@ func TestH2H1LocationRewrite(t *testing.T) {
// TestH2H1ChunkedRequestBody tests that chunked request body works. // TestH2H1ChunkedRequestBody tests that chunked request body works.
func TestH2H1ChunkedRequestBody(t *testing.T) { func TestH2H1ChunkedRequestBody(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
want := "[chunked]" want := "[chunked]"
if got := fmt.Sprint(r.TransferEncoding); got != want { if got := fmt.Sprint(r.TransferEncoding); got != want {
t.Errorf("Transfer-Encoding: %v; want %v", got, want) t.Errorf("Transfer-Encoding: %v; want %v", got, want)
@@ -728,7 +728,7 @@ func TestH2H1ChunkedRequestBody(t *testing.T) {
// multiple Content-Length request header fields. // multiple Content-Length request header fields.
func TestH2H1MultipleRequestCL(t *testing.T) { func TestH2H1MultipleRequestCL(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }
@@ -754,7 +754,7 @@ func TestH2H1MultipleRequestCL(t *testing.T) {
// Content-Length which cannot be parsed as a number. // Content-Length which cannot be parsed as a number.
func TestH2H1InvalidRequestCL(t *testing.T) { func TestH2H1InvalidRequestCL(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward bad request") t.Errorf("server should not forward bad request")
}, },
} }
@@ -800,7 +800,7 @@ func TestH2H1InvalidRequestCL(t *testing.T) {
// 501. // 501.
func TestH2H1InvalidMethod(t *testing.T) { func TestH2H1InvalidMethod(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
@@ -823,7 +823,7 @@ func TestH2H1InvalidMethod(t *testing.T) {
// bad characters in :authority header field. // bad characters in :authority header field.
func TestH2H1BadAuthority(t *testing.T) { func TestH2H1BadAuthority(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
@@ -846,7 +846,7 @@ func TestH2H1BadAuthority(t *testing.T) {
// bad characters in :scheme header field. // bad characters in :scheme header field.
func TestH2H1BadScheme(t *testing.T) { func TestH2H1BadScheme(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
@@ -869,7 +869,7 @@ func TestH2H1BadScheme(t *testing.T) {
// request is assembled into 1 when forwarding to HTTP/1 backend link. // request is assembled into 1 when forwarding to HTTP/1 backend link.
func TestH2H1AssembleCookies(t *testing.T) { func TestH2H1AssembleCookies(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want { if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
t.Errorf("Cookie: %v; want %v", got, want) t.Errorf("Cookie: %v; want %v", got, want)
} }
@@ -918,7 +918,7 @@ func TestH2H1TETrailers(t *testing.T) {
// field contains gzip. // field contains gzip.
func TestH2H1TEGzip(t *testing.T) { func TestH2H1TEGzip(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Error("server should not forward bad request") t.Error("server should not forward bad request")
}, },
} }
@@ -967,7 +967,7 @@ func TestH2H1SNI(t *testing.T) {
// connection is encrypted. // connection is encrypted.
func TestH2H1TLSXfp(t *testing.T) { func TestH2H1TLSXfp(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want { if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
t.Errorf("x-forwarded-proto: want %v; got %v", want, got) t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
} }
@@ -1028,7 +1028,7 @@ func TestH2H1ServerPush(t *testing.T) {
// backend. // backend.
func TestH2H1RequestTrailer(t *testing.T) { func TestH2H1RequestTrailer(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
buf := make([]byte, 4096) buf := make([]byte, 4096)
for { for {
_, err := r.Body.Read(buf) _, err := r.Body.Read(buf)
@@ -1067,7 +1067,7 @@ func TestH2H1RequestTrailer(t *testing.T) {
func TestH2H1HeaderFieldBuffer(t *testing.T) { func TestH2H1HeaderFieldBuffer(t *testing.T) {
opts := options{ opts := options{
args: []string{"--request-header-field-buffer=10"}, args: []string{"--request-header-field-buffer=10"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatal("execution path should not be here") t.Fatal("execution path should not be here")
}, },
} }
@@ -1090,7 +1090,7 @@ func TestH2H1HeaderFieldBuffer(t *testing.T) {
func TestH2H1HeaderFields(t *testing.T) { func TestH2H1HeaderFields(t *testing.T) {
opts := options{ opts := options{
args: []string{"--max-request-header-fields=1"}, args: []string{"--max-request-header-fields=1"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatal("execution path should not be here") t.Fatal("execution path should not be here")
}, },
} }
@@ -1115,7 +1115,7 @@ func TestH2H1HeaderFields(t *testing.T) {
func TestH2H1ReqPhaseSetHeader(t *testing.T) { func TestH2H1ReqPhaseSetHeader(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/req-set-header.rb"}, args: []string{"--mruby-file=" + testDir + "/req-set-header.rb"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("User-Agent"), "mruby"; got != want { if got, want := r.Header.Get("User-Agent"), "mruby"; got != want {
t.Errorf("User-Agent = %v; want %v", got, want) t.Errorf("User-Agent = %v; want %v", got, want)
} }
@@ -1141,7 +1141,7 @@ func TestH2H1ReqPhaseSetHeader(t *testing.T) {
func TestH2H1ReqPhaseReturn(t *testing.T) { func TestH2H1ReqPhaseReturn(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/req-return.rb"}, args: []string{"--mruby-file=" + testDir + "/req-return.rb"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
} }
@@ -1284,7 +1284,7 @@ func TestH2H1ProxyProtocolV1ForwardedForObfuscated(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=obfuscated", "--forwarded-for=obfuscated",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) { if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
t.Errorf("Forwarded: %v; want pattern %v", got, pattern) t.Errorf("Forwarded: %v; want pattern %v", got, pattern)
} }
@@ -1321,7 +1321,7 @@ func TestH2H1ProxyProtocolV1TCP4(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -1361,7 +1361,7 @@ func TestH2H1ProxyProtocolV1TCP6(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -1401,7 +1401,7 @@ func TestH2H1ProxyProtocolV1TCP4TLS(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -1439,7 +1439,7 @@ func TestH2H1ProxyProtocolV1TCP6TLS(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -1476,7 +1476,7 @@ func TestH2H1ProxyProtocolV1Unknown(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, notWant := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got == notWant { if got, notWant := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got == notWant {
t.Errorf("X-Forwarded-For: %v; want something else", got) t.Errorf("X-Forwarded-For: %v; want something else", got)
} }
@@ -1881,7 +1881,7 @@ func TestH2H1ProxyProtocolV2TCP4(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -1937,7 +1937,7 @@ func TestH2H1ProxyProtocolV2TCP6(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "2001:db8:85a3::8a2e:370:7334"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "2001:db8:85a3::8a2e:370:7334"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -2009,7 +2009,7 @@ func TestH2H1ProxyProtocolV2TCP4TLS(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -2063,7 +2063,7 @@ func TestH2H1ProxyProtocolV2TCP6TLS(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "2001:db8:85a3::8a2e:370:7334"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "2001:db8:85a3::8a2e:370:7334"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -2100,7 +2100,7 @@ func TestH2H1ProxyProtocolV2Local(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -2193,7 +2193,7 @@ func TestH2H1ProxyProtocolV2Unix(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -2248,7 +2248,7 @@ func TestH2H1ProxyProtocolV2Unspec(t *testing.T) {
"--add-forwarded=for", "--add-forwarded=for",
"--forwarded-for=ip", "--forwarded-for=ip",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want { if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
t.Errorf("X-Forwarded-For: %v; want %v", got, want) t.Errorf("X-Forwarded-For: %v; want %v", got, want)
} }
@@ -2383,7 +2383,7 @@ func TestH2H1HTTPSRedirectPort(t *testing.T) {
// transfer-encoding is valid. // transfer-encoding is valid.
func TestH2H1Code204(t *testing.T) { func TestH2H1Code204(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
}, },
} }
@@ -2406,7 +2406,7 @@ func TestH2H1Code204(t *testing.T) {
// is allowed. // is allowed.
func TestH2H1Code204CL0(t *testing.T) { func TestH2H1Code204CL0(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
hj, ok := w.(http.Hijacker) hj, ok := w.(http.Hijacker)
if !ok { if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
@@ -2447,7 +2447,7 @@ func TestH2H1Code204CL0(t *testing.T) {
// content-length is not allowed. // content-length is not allowed.
func TestH2H1Code204CLNonzero(t *testing.T) { func TestH2H1Code204CLNonzero(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
hj, ok := w.(http.Hijacker) hj, ok := w.(http.Hijacker)
if !ok { if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
@@ -2484,7 +2484,7 @@ func TestH2H1Code204CLNonzero(t *testing.T) {
// not allowed. // not allowed.
func TestH2H1Code204TE(t *testing.T) { func TestH2H1Code204TE(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
hj, ok := w.(http.Hijacker) hj, ok := w.(http.Hijacker)
if !ok { if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
@@ -2659,7 +2659,7 @@ func TestH2H1GracefulShutdown(t *testing.T) {
func TestH2H2MultipleResponseCL(t *testing.T) { func TestH2H2MultipleResponseCL(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge"}, args: []string{"--http2-bridge"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
w.Header().Add("content-length", "1") w.Header().Add("content-length", "1")
w.Header().Add("content-length", "1") w.Header().Add("content-length", "1")
}, },
@@ -2684,7 +2684,7 @@ func TestH2H2MultipleResponseCL(t *testing.T) {
func TestH2H2InvalidResponseCL(t *testing.T) { func TestH2H2InvalidResponseCL(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge"}, args: []string{"--http2-bridge"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
w.Header().Add("content-length", "") w.Header().Add("content-length", "")
}, },
} }
@@ -2783,7 +2783,7 @@ func TestH2H2NoHostRewrite(t *testing.T) {
func TestH2H2TLSXfp(t *testing.T) { func TestH2H2TLSXfp(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge"}, args: []string{"--http2-bridge"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want { if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
t.Errorf("x-forwarded-proto: want %v; got %v", want, got) t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
} }
@@ -2812,7 +2812,7 @@ func TestH2H2AddXfp(t *testing.T) {
"--http2-bridge", "--http2-bridge",
"--no-strip-incoming-x-forwarded-proto", "--no-strip-incoming-x-forwarded-proto",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xfp := r.Header.Get("X-Forwarded-Proto") xfp := r.Header.Get("X-Forwarded-Proto")
if got, want := xfp, "foo, http"; got != want { if got, want := xfp, "foo, http"; got != want {
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
@@ -2846,7 +2846,7 @@ func TestH2H2NoAddXfp(t *testing.T) {
"--no-add-x-forwarded-proto", "--no-add-x-forwarded-proto",
"--no-strip-incoming-x-forwarded-proto", "--no-strip-incoming-x-forwarded-proto",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xfp := r.Header.Get("X-Forwarded-Proto") xfp := r.Header.Get("X-Forwarded-Proto")
if got, want := xfp, "foo"; got != want { if got, want := xfp, "foo"; got != want {
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
@@ -2876,7 +2876,7 @@ func TestH2H2NoAddXfp(t *testing.T) {
func TestH2H2StripXfp(t *testing.T) { func TestH2H2StripXfp(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge"}, args: []string{"--http2-bridge"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xfp := r.Header.Get("X-Forwarded-Proto") xfp := r.Header.Get("X-Forwarded-Proto")
if got, want := xfp, "http"; got != want { if got, want := xfp, "http"; got != want {
t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
@@ -2906,7 +2906,7 @@ func TestH2H2StripXfp(t *testing.T) {
func TestH2H2StripNoAddXfp(t *testing.T) { func TestH2H2StripNoAddXfp(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge", "--no-add-x-forwarded-proto"}, args: []string{"--http2-bridge", "--no-add-x-forwarded-proto"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, found := r.Header["X-Forwarded-Proto"]; found { if got, found := r.Header["X-Forwarded-Proto"]; found {
t.Errorf("X-Forwarded-Proto = %q; want nothing", got) t.Errorf("X-Forwarded-Proto = %q; want nothing", got)
} }
@@ -2935,7 +2935,7 @@ func TestH2H2StripNoAddXfp(t *testing.T) {
func TestH2H2AddXff(t *testing.T) { func TestH2H2AddXff(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge", "--add-x-forwarded-for"}, args: []string{"--http2-bridge", "--add-x-forwarded-for"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For") xff := r.Header.Get("X-Forwarded-For")
want := "127.0.0.1" want := "127.0.0.1"
if xff != want { if xff != want {
@@ -2963,7 +2963,7 @@ func TestH2H2AddXff(t *testing.T) {
func TestH2H2AddXff2(t *testing.T) { func TestH2H2AddXff2(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge", "--add-x-forwarded-for"}, args: []string{"--http2-bridge", "--add-x-forwarded-for"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For") xff := r.Header.Get("X-Forwarded-For")
want := "host, 127.0.0.1" want := "host, 127.0.0.1"
if xff != want { if xff != want {
@@ -2997,7 +2997,7 @@ func TestH2H2StripXff(t *testing.T) {
"--http2-bridge", "--http2-bridge",
"--strip-incoming-x-forwarded-for", "--strip-incoming-x-forwarded-for",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if xff, found := r.Header["X-Forwarded-For"]; found { if xff, found := r.Header["X-Forwarded-For"]; found {
t.Errorf("X-Forwarded-For = %v; want nothing", xff) t.Errorf("X-Forwarded-For = %v; want nothing", xff)
} }
@@ -3030,7 +3030,7 @@ func TestH2H2StripAddXff(t *testing.T) {
"--strip-incoming-x-forwarded-for", "--strip-incoming-x-forwarded-for",
"--add-x-forwarded-for", "--add-x-forwarded-for",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
xff := r.Header.Get("X-Forwarded-For") xff := r.Header.Get("X-Forwarded-For")
want := "127.0.0.1" want := "127.0.0.1"
if xff != want { if xff != want {
@@ -3065,7 +3065,7 @@ func TestH2H2AddForwarded(t *testing.T) {
"--add-forwarded=by,for,host,proto", "--add-forwarded=by,for,host,proto",
"--forwarded-by=_alpha", "--forwarded-by=_alpha",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
pattern := fmt.Sprintf(`by=_alpha;for=_[^;]+;host="127\.0\.0\.1:%v";proto=https`, serverPort) pattern := fmt.Sprintf(`by=_alpha;for=_[^;]+;host="127\.0\.0\.1:%v";proto=https`, serverPort)
validFwd := regexp.MustCompile(pattern) validFwd := regexp.MustCompile(pattern)
if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) { if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
@@ -3099,7 +3099,7 @@ func TestH2H2AddForwardedMerge(t *testing.T) {
"--add-forwarded=by,host,proto", "--add-forwarded=by,host,proto",
"--forwarded-by=_alpha", "--forwarded-by=_alpha",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
want := fmt.Sprintf(`host=foo, by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort) want := fmt.Sprintf(`host=foo, by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort)
if got := r.Header.Get("Forwarded"); got != want { if got := r.Header.Get("Forwarded"); got != want {
t.Errorf("Forwarded = %v; want %v", got, want) t.Errorf("Forwarded = %v; want %v", got, want)
@@ -3136,7 +3136,7 @@ func TestH2H2AddForwardedStrip(t *testing.T) {
"--add-forwarded=by,host,proto", "--add-forwarded=by,host,proto",
"--forwarded-by=_alpha", "--forwarded-by=_alpha",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
want := fmt.Sprintf(`by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort) want := fmt.Sprintf(`by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort)
if got := r.Header.Get("Forwarded"); got != want { if got := r.Header.Get("Forwarded"); got != want {
t.Errorf("Forwarded = %v; want %v", got, want) t.Errorf("Forwarded = %v; want %v", got, want)
@@ -3167,7 +3167,7 @@ func TestH2H2AddForwardedStrip(t *testing.T) {
func TestH2H2StripForwarded(t *testing.T) { func TestH2H2StripForwarded(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge", "--strip-incoming-forwarded"}, args: []string{"--http2-bridge", "--strip-incoming-forwarded"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, found := r.Header["Forwarded"]; found { if got, found := r.Header["Forwarded"]; found {
t.Errorf("Forwarded = %v; want nothing", got) t.Errorf("Forwarded = %v; want nothing", got)
} }
@@ -3200,7 +3200,7 @@ func TestH2H2ReqPhaseReturn(t *testing.T) {
"--http2-bridge", "--http2-bridge",
"--mruby-file=" + testDir + "/req-return.rb", "--mruby-file=" + testDir + "/req-return.rb",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
} }
@@ -3322,7 +3322,7 @@ func TestH2H2DNS(t *testing.T) {
func TestH2H2Code204(t *testing.T) { func TestH2H2Code204(t *testing.T) {
opts := options{ opts := options{
args: []string{"--http2-bridge"}, args: []string{"--http2-bridge"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
}, },
} }
@@ -3346,7 +3346,7 @@ func TestH2H2Code204(t *testing.T) {
func TestH2APIBackendconfig(t *testing.T) { func TestH2APIBackendconfig(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -3388,7 +3388,7 @@ backend=127.0.0.1,3011
func TestH2APIBackendconfigQuery(t *testing.T) { func TestH2APIBackendconfigQuery(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -3430,7 +3430,7 @@ backend=127.0.0.1,3011
func TestH2APIBackendconfigBadMethod(t *testing.T) { func TestH2APIBackendconfigBadMethod(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -3471,7 +3471,7 @@ backend=127.0.0.1,3011
func TestH2APIConfigrevision(t *testing.T) { func TestH2APIConfigrevision(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -3514,7 +3514,7 @@ func TestH2APIConfigrevision(t *testing.T) {
func TestH2APINotFound(t *testing.T) { func TestH2APINotFound(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3010;api;no-tls"}, args: []string{"-f127.0.0.1,3010;api;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3010, connectPort: 3010,
@@ -3555,7 +3555,7 @@ backend=127.0.0.1,3011
func TestH2Healthmon(t *testing.T) { func TestH2Healthmon(t *testing.T) {
opts := options{ opts := options{
args: []string{"-f127.0.0.1,3011;healthmon;no-tls"}, args: []string{"-f127.0.0.1,3011;healthmon;no-tls"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
connectPort: 3011, connectPort: 3011,
@@ -3580,7 +3580,7 @@ func TestH2Healthmon(t *testing.T) {
func TestH2ResponseBeforeRequestEnd(t *testing.T) { func TestH2ResponseBeforeRequestEnd(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/req-return.rb"}, args: []string{"--mruby-file=" + testDir + "/req-return.rb"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatal("request should not be forwarded") t.Fatal("request should not be forwarded")
}, },
} }
@@ -3603,7 +3603,7 @@ func TestH2ResponseBeforeRequestEnd(t *testing.T) {
// backend chunked encoded response ends prematurely. // backend chunked encoded response ends prematurely.
func TestH2H1ChunkedEndsPrematurely(t *testing.T) { func TestH2H1ChunkedEndsPrematurely(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
hj, ok := w.(http.Hijacker) hj, ok := w.(http.Hijacker)
if !ok { if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
@@ -3641,7 +3641,7 @@ func TestH2H1ChunkedEndsPrematurely(t *testing.T) {
func TestH2H1RequireHTTPSchemeHTTPSWithoutEncryption(t *testing.T) { func TestH2H1RequireHTTPSchemeHTTPSWithoutEncryption(t *testing.T) {
opts := options{ opts := options{
args: []string{"--require-http-scheme"}, args: []string{"--require-http-scheme"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
@@ -3666,7 +3666,7 @@ func TestH2H1RequireHTTPSchemeHTTPSWithoutEncryption(t *testing.T) {
func TestH2H1RequireHTTPSchemeHTTPWithEncryption(t *testing.T) { func TestH2H1RequireHTTPSchemeHTTPWithEncryption(t *testing.T) {
opts := options{ opts := options{
args: []string{"--require-http-scheme"}, args: []string{"--require-http-scheme"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
tls: true, tls: true,
@@ -3693,7 +3693,7 @@ func TestH2H1RequireHTTPSchemeHTTPWithEncryption(t *testing.T) {
func TestH2H1RequireHTTPSchemeUnknownSchemeWithoutEncryption(t *testing.T) { func TestH2H1RequireHTTPSchemeUnknownSchemeWithoutEncryption(t *testing.T) {
opts := options{ opts := options{
args: []string{"--require-http-scheme"}, args: []string{"--require-http-scheme"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
} }
@@ -3718,7 +3718,7 @@ func TestH2H1RequireHTTPSchemeUnknownSchemeWithoutEncryption(t *testing.T) {
func TestH2H1RequireHTTPSchemeUnknownSchemeWithEncryption(t *testing.T) { func TestH2H1RequireHTTPSchemeUnknownSchemeWithEncryption(t *testing.T) {
opts := options{ opts := options{
args: []string{"--require-http-scheme"}, args: []string{"--require-http-scheme"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Errorf("server should not forward this request") t.Errorf("server should not forward this request")
}, },
tls: true, tls: true,

View File

@@ -41,7 +41,7 @@ func TestH3H1RequestBody(t *testing.T) {
} }
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
buf := make([]byte, 4096) buf := make([]byte, 4096)
buflen := 0 buflen := 0
p := buf p := buf
@@ -92,7 +92,7 @@ func TestH3H1RequestBody(t *testing.T) {
// and from backend server. // and from backend server.
func TestH3H1GenerateVia(t *testing.T) { func TestH3H1GenerateVia(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(_ http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("Via"), "3 nghttpx"; got != want { if got, want := r.Header.Get("Via"), "3 nghttpx"; got != want {
t.Errorf("Via: %v; want %v", got, want) t.Errorf("Via: %v; want %v", got, want)
} }
@@ -177,7 +177,7 @@ func TestH3H1NoVia(t *testing.T) {
// response body size. // response body size.
func TestH3H1BadResponseCL(t *testing.T) { func TestH3H1BadResponseCL(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
// we set content-length: 1024, but only send 3 bytes. // we set content-length: 1024, but only send 3 bytes.
w.Header().Add("Content-Length", "1024") w.Header().Add("Content-Length", "1024")
if _, err := w.Write([]byte("foo")); err != nil { if _, err := w.Write([]byte("foo")); err != nil {
@@ -256,7 +256,7 @@ func TestH3H2ReqPhaseReturn(t *testing.T) {
"--http2-bridge", "--http2-bridge",
"--mruby-file=" + testDir + "/req-return.rb", "--mruby-file=" + testDir + "/req-return.rb",
}, },
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatalf("request should not be forwarded") t.Fatalf("request should not be forwarded")
}, },
quic: true, quic: true,
@@ -338,7 +338,7 @@ func TestH3H2RespPhaseReturn(t *testing.T) {
func TestH3ResponseBeforeRequestEnd(t *testing.T) { func TestH3ResponseBeforeRequestEnd(t *testing.T) {
opts := options{ opts := options{
args: []string{"--mruby-file=" + testDir + "/req-return.rb"}, args: []string{"--mruby-file=" + testDir + "/req-return.rb"},
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(http.ResponseWriter, *http.Request) {
t.Fatal("request should not be forwarded") t.Fatal("request should not be forwarded")
}, },
quic: true, quic: true,
@@ -362,7 +362,7 @@ func TestH3ResponseBeforeRequestEnd(t *testing.T) {
// backend chunked encoded response ends prematurely. // backend chunked encoded response ends prematurely.
func TestH3H1ChunkedEndsPrematurely(t *testing.T) { func TestH3H1ChunkedEndsPrematurely(t *testing.T) {
opts := options{ opts := options{
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, _ *http.Request) {
hj, ok := w.(http.Hijacker) hj, ok := w.(http.Hijacker)
if !ok { if !ok {
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)

View File

@@ -31,6 +31,8 @@ set(NGHTTP2_SOURCES
) )
set(NGHTTP2_RES "") set(NGHTTP2_RES "")
set(STATIC_LIB "nghttp2_static")
set(SHARED_LIB "nghttp2")
if(WIN32) if(WIN32)
configure_file( configure_file(
@@ -41,40 +43,61 @@ if(WIN32)
set(NGHTTP2_RES ${CMAKE_CURRENT_BINARY_DIR}/version.rc) set(NGHTTP2_RES ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif() endif()
set(EXPORT_SET "${PROJECT_NAME}-targets")
# Public shared library # Public shared library
if(ENABLE_SHARED_LIB) if(BUILD_SHARED_LIBS)
add_library(nghttp2 SHARED ${NGHTTP2_SOURCES} ${NGHTTP2_RES}) add_library(${SHARED_LIB} SHARED ${NGHTTP2_SOURCES} ${NGHTTP2_RES})
set_target_properties(nghttp2 PROPERTIES
set_target_properties(${SHARED_LIB} PROPERTIES
COMPILE_FLAGS "${WARNCFLAGS}" COMPILE_FLAGS "${WARNCFLAGS}"
VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION} VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION}
C_VISIBILITY_PRESET hidden C_VISIBILITY_PRESET hidden
) )
target_include_directories(nghttp2 INTERFACE
"${CMAKE_CURRENT_BINARY_DIR}/includes" target_include_directories(${SHARED_LIB} INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/includes" $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/includes>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/includes>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
) )
install(TARGETS nghttp2 install(TARGETS ${SHARED_LIB} EXPORT ${EXPORT_SET})
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" list(APPEND nghttp2_exports ${SHARED_LIB})
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif() endif()
if(HAVE_CUNIT OR ENABLE_STATIC_LIB) # Static library (for unittests because of symbol visibility)
# Static library (for unittests because of symbol visibility) add_library(${STATIC_LIB} STATIC ${NGHTTP2_SOURCES})
add_library(nghttp2_static STATIC ${NGHTTP2_SOURCES})
set_target_properties(nghttp2_static PROPERTIES set_target_properties(${STATIC_LIB} PROPERTIES
COMPILE_FLAGS "${WARNCFLAGS}" COMPILE_FLAGS "${WARNCFLAGS}"
VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION} VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION}
ARCHIVE_OUTPUT_NAME nghttp2${STATIC_LIB_SUFFIX} ARCHIVE_OUTPUT_NAME nghttp2${STATIC_LIB_SUFFIX}
) )
target_compile_definitions(nghttp2_static PUBLIC "-DNGHTTP2_STATICLIB")
if(ENABLE_STATIC_LIB) target_include_directories(${STATIC_LIB} INTERFACE
install(TARGETS nghttp2_static $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/includes>
DESTINATION "${CMAKE_INSTALL_LIBDIR}") $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/includes>
endif() $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_compile_definitions(${STATIC_LIB} PUBLIC "-DNGHTTP2_STATICLIB")
if(BUILD_STATIC_LIBS)
install(TARGETS ${STATIC_LIB} EXPORT ${EXPORT_SET})
list(APPEND nghttp2_exports ${STATIC_LIB})
endif() endif()
if(BUILD_SHARED_LIBS)
set(LIB_SELECTED ${SHARED_LIB})
else()
set(LIB_SELECTED ${STATIC_LIB})
endif()
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}::)

File diff suppressed because it is too large Load Diff

View File

@@ -430,7 +430,7 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b) {
return 0; return 0;
} }
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) { nghttp2_ssize nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
size_t len; size_t len;
nghttp2_buf_chain *chain; nghttp2_buf_chain *chain;
nghttp2_buf *buf; nghttp2_buf *buf;
@@ -462,7 +462,7 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
*out = res; *out = res;
return (ssize_t)len; return (nghttp2_ssize)len;
} }
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) { size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) {

View File

@@ -349,7 +349,7 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory * Out of memory
*/ */
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out); nghttp2_ssize nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
/* /*
* Copies all data stored in |bufs| to |out|. This function assumes * Copies all data stored in |bufs| to |out|. This function assumes

View File

@@ -45,11 +45,21 @@ void nghttp2_session_callbacks_set_send_callback(
cbs->send_callback = send_callback; cbs->send_callback = send_callback;
} }
void nghttp2_session_callbacks_set_send_callback2(
nghttp2_session_callbacks *cbs, nghttp2_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(
nghttp2_session_callbacks *cbs, nghttp2_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) {
@@ -128,12 +138,24 @@ void nghttp2_session_callbacks_set_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(
nghttp2_session_callbacks *cbs,
nghttp2_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(
nghttp2_session_callbacks *cbs, nghttp2_data_source_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) {
@@ -152,6 +174,12 @@ void nghttp2_session_callbacks_set_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(
nghttp2_session_callbacks *cbs,
nghttp2_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) {

View File

@@ -36,19 +36,33 @@
*/ */
struct nghttp2_session_callbacks { struct nghttp2_session_callbacks {
/** /**
* Callback function invoked when the session wants to send data to * Deprecated. Use send_callback2 instead. Callback function
* the remote peer. This callback is not necessary if the * invoked when the session wants to send data to the remote peer.
* application uses solely `nghttp2_session_mem_send()` to serialize * This callback is not necessary if the application uses solely
* data to transmit. * `nghttp2_session_mem_send()` to serialize data to transmit.
*/ */
nghttp2_send_callback send_callback; nghttp2_send_callback send_callback;
/** /**
* Callback function invoked when the session wants to receive data * Callback function invoked when the session wants to send data to
* from the remote peer. This callback is not necessary if the * the remote peer. This callback is not necessary if the
* application uses solely `nghttp2_session_mem_recv()` to process * application uses solely `nghttp2_session_mem_send2()` to
* received data. * serialize data to transmit.
*/
nghttp2_send_callback2 send_callback2;
/**
* Deprecated. Use recv_callback2 instead. Callback function
* invoked when the session wants to receive data from the remote
* peer. This callback is not necessary if the application uses
* solely `nghttp2_session_mem_recv()` to process received data.
*/ */
nghttp2_recv_callback recv_callback; nghttp2_recv_callback recv_callback;
/**
* Callback function invoked when the session wants to receive data
* from the remote peer. This callback is not necessary if the
* application uses solely `nghttp2_session_mem_recv2()` to process
* received data.
*/
nghttp2_recv_callback2 recv_callback2;
/** /**
* Callback function invoked by `nghttp2_session_recv()` when a * Callback function invoked by `nghttp2_session_recv()` when a
* frame is received. * frame is received.
@@ -100,22 +114,39 @@ struct nghttp2_session_callbacks {
nghttp2_on_invalid_header_callback on_invalid_header_callback; nghttp2_on_invalid_header_callback on_invalid_header_callback;
nghttp2_on_invalid_header_callback2 on_invalid_header_callback2; nghttp2_on_invalid_header_callback2 on_invalid_header_callback2;
/** /**
* Callback function invoked when the library asks application how * Deprecated. Use select_padding_callback2 instead. Callback
* many padding bytes are required for the transmission of the given * function invoked when the library asks application how many
* padding bytes are required for the transmission of the given
* frame. * frame.
*/ */
nghttp2_select_padding_callback select_padding_callback; nghttp2_select_padding_callback select_padding_callback;
/** /**
* The callback function used to determine the length allowed in * Callback function invoked when the library asks application how
* many padding bytes are required for the transmission of the given
* frame.
*/
nghttp2_select_padding_callback2 select_padding_callback2;
/**
* Deprecated. Use read_length_callback2 instead. The callback
* function used to determine the length allowed in
* `nghttp2_data_source_read_callback()` * `nghttp2_data_source_read_callback()`
*/ */
nghttp2_data_source_read_length_callback read_length_callback; nghttp2_data_source_read_length_callback read_length_callback;
/**
* The callback function used to determine the length allowed in
* `nghttp2_data_source_read_callback2()`
*/
nghttp2_data_source_read_length_callback2 read_length_callback2;
/** /**
* Sets callback function invoked when a frame header is received. * Sets callback function invoked when a frame header is received.
*/ */
nghttp2_on_begin_frame_callback on_begin_frame_callback; nghttp2_on_begin_frame_callback on_begin_frame_callback;
nghttp2_send_data_callback send_data_callback; nghttp2_send_data_callback send_data_callback;
/**
* Deprecated. Use pack_extension_callback2 instead.
*/
nghttp2_pack_extension_callback pack_extension_callback; nghttp2_pack_extension_callback pack_extension_callback;
nghttp2_pack_extension_callback2 pack_extension_callback2;
nghttp2_unpack_extension_callback unpack_extension_callback; nghttp2_unpack_extension_callback unpack_extension_callback;
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback; nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
nghttp2_error_callback error_callback; nghttp2_error_callback error_callback;

View File

@@ -850,9 +850,10 @@ static size_t encode_length(uint8_t *buf, size_t n, size_t prefix) {
* in the next call will be stored in |*shift_ptr|) and returns number * in the next call will be stored in |*shift_ptr|) and returns number
* of bytes processed, or returns -1, indicating decoding error. * of bytes processed, or returns -1, indicating decoding error.
*/ */
static ssize_t decode_length(uint32_t *res, size_t *shift_ptr, int *fin, static nghttp2_ssize decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
uint32_t initial, size_t shift, const uint8_t *in, uint32_t initial, size_t shift,
const uint8_t *last, size_t prefix) { const uint8_t *in, const uint8_t *last,
size_t prefix) {
uint32_t k = (uint8_t)((1 << prefix) - 1); uint32_t k = (uint8_t)((1 << prefix) - 1);
uint32_t n = initial; uint32_t n = initial;
const uint8_t *start = in; const uint8_t *start = in;
@@ -871,7 +872,7 @@ static ssize_t decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
if (++in == last) { if (++in == last) {
*res = n; *res = n;
return (ssize_t)(in - start); return (nghttp2_ssize)(in - start);
} }
} }
@@ -906,12 +907,12 @@ static ssize_t decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
if (in == last) { if (in == last) {
*res = n; *res = n;
return (ssize_t)(in - start); return (nghttp2_ssize)(in - start);
} }
*res = n; *res = n;
*fin = 1; *fin = 1;
return (ssize_t)(in + 1 - start); return (nghttp2_ssize)(in + 1 - start);
} }
static int emit_table_size(nghttp2_bufs *bufs, size_t table_size) { static int emit_table_size(nghttp2_bufs *bufs, size_t table_size) {
@@ -1164,7 +1165,7 @@ static int add_hd_table_incremental(nghttp2_hd_context *context,
} }
typedef struct { typedef struct {
ssize_t index; nghttp2_ssize index;
/* Nonzero if both name and value are matched. */ /* Nonzero if both name and value are matched. */
int name_value_match; int name_value_match;
} search_result; } search_result;
@@ -1213,8 +1214,8 @@ static search_result search_hd_table(nghttp2_hd_context *context,
return res; return res;
} }
res.index = res.index = (nghttp2_ssize)(context->next_seq - 1 - ent->seq +
(ssize_t)(context->next_seq - 1 - ent->seq + NGHTTP2_STATIC_TABLE_LENGTH); NGHTTP2_STATIC_TABLE_LENGTH);
res.name_value_match = exact_match; res.name_value_match = exact_match;
return res; return res;
@@ -1343,7 +1344,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
const nghttp2_nv *nv) { const nghttp2_nv *nv) {
int rv; int rv;
search_result res; search_result res;
ssize_t idx; nghttp2_ssize idx;
int indexing_mode; int indexing_mode;
int32_t token; int32_t token;
nghttp2_mem *mem; nghttp2_mem *mem;
@@ -1379,7 +1380,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
if (res.name_value_match) { if (res.name_value_match) {
DEBUGF("deflatehd: name/value match index=%zd\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);
if (rv != 0) { if (rv != 0) {
@@ -1390,7 +1391,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
} }
if (res.index != -1) { if (res.index != -1) {
DEBUGF("deflatehd: name match index=%zd\n", res.index); DEBUGF("deflatehd: name match index=%td\n", res.index);
} }
if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) { if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
@@ -1491,6 +1492,12 @@ fail:
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf, ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
size_t buflen, const nghttp2_nv *nv, size_t buflen, const nghttp2_nv *nv,
size_t nvlen) { size_t nvlen) {
return (ssize_t)nghttp2_hd_deflate_hd2(deflater, buf, buflen, nv, nvlen);
}
nghttp2_ssize nghttp2_hd_deflate_hd2(nghttp2_hd_deflater *deflater,
uint8_t *buf, size_t buflen,
const nghttp2_nv *nv, size_t nvlen) {
nghttp2_bufs bufs; nghttp2_bufs bufs;
int rv; int rv;
nghttp2_mem *mem; nghttp2_mem *mem;
@@ -1517,12 +1524,18 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
return rv; return rv;
} }
return (ssize_t)buflen; return (nghttp2_ssize)buflen;
} }
ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater, ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
const nghttp2_vec *vec, size_t veclen, const nghttp2_vec *vec, size_t veclen,
const nghttp2_nv *nv, size_t nvlen) { const nghttp2_nv *nv, size_t nvlen) {
return (ssize_t)nghttp2_hd_deflate_hd_vec2(deflater, vec, veclen, nv, nvlen);
}
nghttp2_ssize nghttp2_hd_deflate_hd_vec2(nghttp2_hd_deflater *deflater,
const nghttp2_vec *vec, size_t veclen,
const nghttp2_nv *nv, size_t nvlen) {
nghttp2_bufs bufs; nghttp2_bufs bufs;
int rv; int rv;
nghttp2_mem *mem; nghttp2_mem *mem;
@@ -1550,7 +1563,7 @@ ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
return rv; return rv;
} }
return (ssize_t)buflen; return (nghttp2_ssize)buflen;
} }
size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater, size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
@@ -1643,10 +1656,11 @@ static void hd_inflate_set_huffman_encoded(nghttp2_hd_inflater *inflater,
* NGHTTP2_ERR_HEADER_COMP * NGHTTP2_ERR_HEADER_COMP
* Integer decoding failed * Integer decoding failed
*/ */
static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin, static nghttp2_ssize hd_inflate_read_len(nghttp2_hd_inflater *inflater,
const uint8_t *in, const uint8_t *last, int *rfin, const uint8_t *in,
size_t prefix, size_t maxlen) { const uint8_t *last, size_t prefix,
ssize_t rv; size_t maxlen) {
nghttp2_ssize rv;
uint32_t out; uint32_t out;
*rfin = 0; *rfin = 0;
@@ -1684,10 +1698,10 @@ static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin,
* NGHTTP2_ERR_HEADER_COMP * NGHTTP2_ERR_HEADER_COMP
* Huffman decoding failed * Huffman decoding failed
*/ */
static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater, static nghttp2_ssize hd_inflate_read_huff(nghttp2_hd_inflater *inflater,
nghttp2_buf *buf, const uint8_t *in, nghttp2_buf *buf, const uint8_t *in,
const uint8_t *last) { const uint8_t *last) {
ssize_t readlen; nghttp2_ssize readlen;
int fin = 0; int fin = 0;
if ((size_t)(last - in) >= inflater->left) { if ((size_t)(last - in) >= inflater->left) {
last = in + inflater->left; last = in + inflater->left;
@@ -1721,14 +1735,15 @@ static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater,
* NGHTTP2_ERR_HEADER_COMP * NGHTTP2_ERR_HEADER_COMP
* Header decompression failed * Header decompression failed
*/ */
static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, nghttp2_buf *buf, static nghttp2_ssize hd_inflate_read(nghttp2_hd_inflater *inflater,
const uint8_t *in, const uint8_t *last) { nghttp2_buf *buf, const uint8_t *in,
const uint8_t *last) {
size_t len = nghttp2_min((size_t)(last - in), inflater->left); size_t len = nghttp2_min((size_t)(last - in), inflater->left);
buf->last = nghttp2_cpymem(buf->last, in, len); buf->last = nghttp2_cpymem(buf->last, in, len);
inflater->left -= len; inflater->left -= len;
return (ssize_t)len; return (nghttp2_ssize)len;
} }
/* /*
@@ -1843,7 +1858,15 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
nghttp2_nv *nv_out, int *inflate_flags, nghttp2_nv *nv_out, int *inflate_flags,
const uint8_t *in, size_t inlen, int in_final) { const uint8_t *in, size_t inlen, int in_final) {
ssize_t rv; return (nghttp2_ssize)nghttp2_hd_inflate_hd3(inflater, nv_out, inflate_flags,
in, inlen, in_final);
}
nghttp2_ssize nghttp2_hd_inflate_hd3(nghttp2_hd_inflater *inflater,
nghttp2_nv *nv_out, int *inflate_flags,
const uint8_t *in, size_t inlen,
int in_final) {
nghttp2_ssize rv;
nghttp2_hd_nv hd_nv; nghttp2_hd_nv hd_nv;
rv = nghttp2_hd_inflate_hd_nv(inflater, &hd_nv, inflate_flags, in, inlen, rv = nghttp2_hd_inflate_hd_nv(inflater, &hd_nv, inflate_flags, in, inlen,
@@ -1866,11 +1889,11 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
return rv; return rv;
} }
ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
nghttp2_hd_nv *nv_out, int *inflate_flags, nghttp2_hd_nv *nv_out,
const uint8_t *in, size_t inlen, int *inflate_flags, const uint8_t *in,
int in_final) { size_t inlen, int in_final) {
ssize_t rv = 0; nghttp2_ssize rv = 0;
const uint8_t *first = in; const uint8_t *first = in;
const uint8_t *last = in + inlen; const uint8_t *last = in + inlen;
int rfin = 0; int rfin = 0;
@@ -1992,7 +2015,7 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
inflater->state = NGHTTP2_HD_STATE_OPCODE; inflater->state = NGHTTP2_HD_STATE_OPCODE;
*inflate_flags |= NGHTTP2_HD_INFLATE_EMIT; *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} else { } else {
inflater->index = inflater->left; inflater->index = inflater->left;
--inflater->index; --inflater->index;
@@ -2050,7 +2073,7 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
in += rv; in += rv;
DEBUGF("inflatehd: %zd bytes read\n", rv); DEBUGF("inflatehd: %td bytes read\n", rv);
if (inflater->left) { if (inflater->left) {
DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
@@ -2072,7 +2095,7 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
in += rv; in += rv;
DEBUGF("inflatehd: %zd bytes read\n", rv); DEBUGF("inflatehd: %td bytes read\n", rv);
if (inflater->left) { if (inflater->left) {
DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
@@ -2138,7 +2161,7 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
in += rv; in += rv;
DEBUGF("inflatehd: %zd bytes read\n", rv); DEBUGF("inflatehd: %td bytes read\n", rv);
if (inflater->left) { if (inflater->left) {
DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
@@ -2162,18 +2185,18 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
inflater->state = NGHTTP2_HD_STATE_OPCODE; inflater->state = NGHTTP2_HD_STATE_OPCODE;
*inflate_flags |= NGHTTP2_HD_INFLATE_EMIT; *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
case NGHTTP2_HD_STATE_READ_VALUE: case NGHTTP2_HD_STATE_READ_VALUE:
rv = hd_inflate_read(inflater, &inflater->valuebuf, in, last); rv = hd_inflate_read(inflater, &inflater->valuebuf, in, last);
if (rv < 0) { if (rv < 0) {
DEBUGF("inflatehd: value read failure %zd: %s\n", rv, DEBUGF("inflatehd: value read failure %td: %s\n", rv,
nghttp2_strerror((int)rv)); nghttp2_strerror((int)rv));
goto fail; goto fail;
} }
in += rv; in += rv;
DEBUGF("inflatehd: %zd bytes read\n", rv); DEBUGF("inflatehd: %td bytes read\n", rv);
if (inflater->left) { if (inflater->left) {
DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
@@ -2196,7 +2219,7 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
inflater->state = NGHTTP2_HD_STATE_OPCODE; inflater->state = NGHTTP2_HD_STATE_OPCODE;
*inflate_flags |= NGHTTP2_HD_INFLATE_EMIT; *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} }
} }
@@ -2216,7 +2239,7 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
} }
*inflate_flags |= NGHTTP2_HD_INFLATE_FINAL; *inflate_flags |= NGHTTP2_HD_INFLATE_FINAL;
} }
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
almost_ok: almost_ok:
if (in_final) { if (in_final) {
@@ -2226,10 +2249,10 @@ almost_ok:
goto fail; goto fail;
} }
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
fail: fail:
DEBUGF("inflatehd: error return %zd\n", rv); DEBUGF("inflatehd: error return %td\n", rv);
inflater->ctx.bad = 1; inflater->ctx.bad = 1;
return rv; return rv;
@@ -2297,9 +2320,10 @@ int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size) {
return emit_table_size(bufs, table_size); return emit_table_size(bufs, table_size);
} }
ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *fin, nghttp2_ssize nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr,
uint32_t initial, size_t shift, uint8_t *in, int *fin, uint32_t initial, size_t shift,
uint8_t *last, size_t prefix) { uint8_t *in, uint8_t *last,
size_t prefix) {
return decode_length(res, shift_ptr, fin, initial, shift, in, last, prefix); return decode_length(res, shift_ptr, fin, initial, shift, in, last, prefix);
} }

View File

@@ -357,9 +357,10 @@ void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
* that return values and semantics are the same as * that return values and semantics are the same as
* nghttp2_hd_inflate_hd(). * nghttp2_hd_inflate_hd().
*/ */
ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
nghttp2_hd_nv *nv_out, int *inflate_flags, nghttp2_hd_nv *nv_out,
const uint8_t *in, size_t inlen, int in_final); int *inflate_flags, const uint8_t *in,
size_t inlen, int in_final);
/* For unittesting purpose */ /* For unittesting purpose */
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index, int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
@@ -376,9 +377,10 @@ int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index); nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index);
/* For unittesting purpose */ /* For unittesting purpose */
ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *fin, nghttp2_ssize nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr,
uint32_t initial, size_t shift, uint8_t *in, int *fin, uint32_t initial, size_t shift,
uint8_t *last, size_t prefix); uint8_t *in, uint8_t *last,
size_t prefix);
/* Huffman encoding/decoding functions */ /* Huffman encoding/decoding functions */
@@ -427,9 +429,9 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
* NGHTTP2_ERR_HEADER_COMP * NGHTTP2_ERR_HEADER_COMP
* Decoding process has failed. * Decoding process has failed.
*/ */
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, nghttp2_ssize nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_buf *buf, const uint8_t *src, nghttp2_buf *buf, const uint8_t *src,
size_t srclen, int fin); size_t srclen, int fin);
/* /*
* nghttp2_hd_huff_decode_failure_state returns nonzero if |ctx| * nghttp2_hd_huff_decode_failure_state returns nonzero if |ctx|

View File

@@ -107,9 +107,9 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
ctx->fstate = NGHTTP2_HUFF_ACCEPTED; ctx->fstate = NGHTTP2_HUFF_ACCEPTED;
} }
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, nghttp2_ssize nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_buf *buf, const uint8_t *src, nghttp2_buf *buf, const uint8_t *src,
size_t srclen, int final) { size_t srclen, int final) {
const uint8_t *end = src + srclen; const uint8_t *end = src + srclen;
nghttp2_huff_decode node = {ctx->fstate, 0}; nghttp2_huff_decode node = {ctx->fstate, 0};
const nghttp2_huff_decode *t = &node; const nghttp2_huff_decode *t = &node;
@@ -136,7 +136,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
} }
return (ssize_t)srclen; return (nghttp2_ssize)srclen;
} }
int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx) { int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx) {

View File

@@ -27,6 +27,32 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
nghttp2_data_provider_wrap *
nghttp2_data_provider_wrap_v1(nghttp2_data_provider_wrap *dpw,
const nghttp2_data_provider *data_prd) {
if (!data_prd) {
return NULL;
}
dpw->version = NGHTTP2_DATA_PROVIDER_V1;
dpw->data_prd.v1 = *data_prd;
return dpw;
}
nghttp2_data_provider_wrap *
nghttp2_data_provider_wrap_v2(nghttp2_data_provider_wrap *dpw,
const nghttp2_data_provider2 *data_prd) {
if (!data_prd) {
return NULL;
}
dpw->version = NGHTTP2_DATA_PROVIDER_V2;
dpw->data_prd.v2 = *data_prd;
return dpw;
}
void nghttp2_outbound_item_init(nghttp2_outbound_item *item) { void nghttp2_outbound_item_init(nghttp2_outbound_item *item) {
item->cycle = 0; item->cycle = 0;
item->qnext = NULL; item->qnext = NULL;

View File

@@ -33,9 +33,32 @@
#include "nghttp2_frame.h" #include "nghttp2_frame.h"
#include "nghttp2_mem.h" #include "nghttp2_mem.h"
#define NGHTTP2_DATA_PROVIDER_V1 1
#define NGHTTP2_DATA_PROVIDER_V2 2
typedef struct nghttp2_data_provider_wrap {
int version;
union {
struct {
nghttp2_data_source source;
void *read_callback;
};
nghttp2_data_provider v1;
nghttp2_data_provider2 v2;
} data_prd;
} nghttp2_data_provider_wrap;
nghttp2_data_provider_wrap *
nghttp2_data_provider_wrap_v1(nghttp2_data_provider_wrap *dpw,
const nghttp2_data_provider *data_prd);
nghttp2_data_provider_wrap *
nghttp2_data_provider_wrap_v2(nghttp2_data_provider_wrap *dpw,
const nghttp2_data_provider2 *data_prd);
/* struct used for HEADERS and PUSH_PROMISE frame */ /* struct used for HEADERS and PUSH_PROMISE frame */
typedef struct { typedef struct {
nghttp2_data_provider data_prd; nghttp2_data_provider_wrap dpw;
void *stream_user_data; void *stream_user_data;
/* error code when request HEADERS is canceled by RST_STREAM while /* error code when request HEADERS is canceled by RST_STREAM while
it is in queue. */ it is in queue. */
@@ -50,7 +73,7 @@ typedef struct {
/** /**
* The data to be sent for this DATA frame. * The data to be sent for this DATA frame.
*/ */
nghttp2_data_provider data_prd; nghttp2_data_provider_wrap dpw;
/** /**
* The flags of DATA frame. We use separate flags here and * The flags of DATA frame. We use separate flags here and
* nghttp2_data frame. The latter contains flags actually sent to * nghttp2_data frame. The latter contains flags actually sent to

View File

@@ -39,6 +39,7 @@
#include "nghttp2_extpri.h" #include "nghttp2_extpri.h"
#include "nghttp2_time.h" #include "nghttp2_time.h"
#include "nghttp2_debug.h" #include "nghttp2_debug.h"
#include "nghttp2_submit.h"
/* /*
* Returns non-zero if the number of outgoing opened streams is larger * Returns non-zero if the number of outgoing opened streams is larger
@@ -2103,10 +2104,9 @@ static int session_predicate_priority_update_send(nghttp2_session *session,
/* Take into account settings max frame size and both connection-level /* Take into account settings max frame size and both connection-level
flow control here */ flow control here */
static ssize_t static nghttp2_ssize nghttp2_session_enforce_flow_control_limits(
nghttp2_session_enforce_flow_control_limits(nghttp2_session *session, nghttp2_session *session, nghttp2_stream *stream,
nghttp2_stream *stream, nghttp2_ssize requested_window_size) {
ssize_t requested_window_size) {
DEBUGF("send: remote windowsize connection=%d, remote maxframsize=%u, " DEBUGF("send: remote windowsize connection=%d, remote maxframsize=%u, "
"stream(id %d)=%d\n", "stream(id %d)=%d\n",
session->remote_window_size, session->remote_settings.max_frame_size, session->remote_window_size, session->remote_settings.max_frame_size,
@@ -2126,12 +2126,12 @@ nghttp2_session_enforce_flow_control_limits(nghttp2_session *session,
*/ */
static size_t nghttp2_session_next_data_read(nghttp2_session *session, static size_t nghttp2_session_next_data_read(nghttp2_session *session,
nghttp2_stream *stream) { nghttp2_stream *stream) {
ssize_t window_size; nghttp2_ssize window_size;
window_size = nghttp2_session_enforce_flow_control_limits( window_size = nghttp2_session_enforce_flow_control_limits(
session, stream, NGHTTP2_DATA_PAYLOADLEN); session, stream, NGHTTP2_DATA_PAYLOADLEN);
DEBUGF("send: available window=%zd\n", window_size); DEBUGF("send: available window=%td\n", window_size);
return window_size > 0 ? (size_t)window_size : 0; return window_size > 0 ? (size_t)window_size : 0;
} }
@@ -2186,29 +2186,33 @@ static int nghttp2_session_predicate_data_send(nghttp2_session *session,
return NGHTTP2_ERR_INVALID_STREAM_STATE; return NGHTTP2_ERR_INVALID_STREAM_STATE;
} }
static ssize_t session_call_select_padding(nghttp2_session *session, static nghttp2_ssize session_call_select_padding(nghttp2_session *session,
const nghttp2_frame *frame, const nghttp2_frame *frame,
size_t max_payloadlen) { size_t max_payloadlen) {
ssize_t rv; nghttp2_ssize rv;
size_t max_paddedlen;
if (frame->hd.length >= max_payloadlen) { if (frame->hd.length >= max_payloadlen ||
return (ssize_t)frame->hd.length; (!session->callbacks.select_padding_callback2 &&
!session->callbacks.select_padding_callback)) {
return (nghttp2_ssize)frame->hd.length;
} }
if (session->callbacks.select_padding_callback) { max_paddedlen =
size_t max_paddedlen; nghttp2_min(frame->hd.length + NGHTTP2_MAX_PADLEN, max_payloadlen);
max_paddedlen = if (session->callbacks.select_padding_callback2) {
nghttp2_min(frame->hd.length + NGHTTP2_MAX_PADLEN, max_payloadlen); rv = session->callbacks.select_padding_callback2(
session, frame, max_paddedlen, session->user_data);
rv = session->callbacks.select_padding_callback( } else {
rv = (nghttp2_ssize)session->callbacks.select_padding_callback(
session, frame, max_paddedlen, session->user_data); session, frame, max_paddedlen, session->user_data);
if (rv < (ssize_t)frame->hd.length || rv > (ssize_t)max_paddedlen) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return rv;
} }
return (ssize_t)frame->hd.length; if (rv < (nghttp2_ssize)frame->hd.length ||
rv > (nghttp2_ssize)max_paddedlen) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return rv;
} }
/* Add padding to HEADERS or PUSH_PROMISE. We use /* Add padding to HEADERS or PUSH_PROMISE. We use
@@ -2216,7 +2220,7 @@ static ssize_t session_call_select_padding(nghttp2_session *session,
frame->push_promise has also padlen in the same position. */ frame->push_promise has also padlen in the same position. */
static int session_headers_add_pad(nghttp2_session *session, static int session_headers_add_pad(nghttp2_session *session,
nghttp2_frame *frame) { nghttp2_frame *frame) {
ssize_t padded_payloadlen; nghttp2_ssize padded_payloadlen;
nghttp2_active_outbound_item *aob; nghttp2_active_outbound_item *aob;
nghttp2_bufs *framebufs; nghttp2_bufs *framebufs;
size_t padlen; size_t padlen;
@@ -2237,7 +2241,7 @@ static int session_headers_add_pad(nghttp2_session *session,
padlen = (size_t)padded_payloadlen - frame->hd.length; padlen = (size_t)padded_payloadlen - frame->hd.length;
DEBUGF("send: padding selected: payloadlen=%zd, padlen=%zu\n", DEBUGF("send: padding selected: payloadlen=%td, padlen=%zu\n",
padded_payloadlen, padlen); padded_payloadlen, padlen);
nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0); nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0);
@@ -2257,18 +2261,24 @@ static size_t session_estimate_headers_payload(nghttp2_session *session,
static int session_pack_extension(nghttp2_session *session, nghttp2_bufs *bufs, static int session_pack_extension(nghttp2_session *session, nghttp2_bufs *bufs,
nghttp2_frame *frame) { nghttp2_frame *frame) {
ssize_t rv; nghttp2_ssize rv;
nghttp2_buf *buf; nghttp2_buf *buf;
size_t buflen; size_t buflen;
size_t framelen; size_t framelen;
assert(session->callbacks.pack_extension_callback); assert(session->callbacks.pack_extension_callback2 ||
session->callbacks.pack_extension_callback);
buf = &bufs->head->buf; buf = &bufs->head->buf;
buflen = nghttp2_min(nghttp2_buf_avail(buf), NGHTTP2_MAX_PAYLOADLEN); buflen = nghttp2_min(nghttp2_buf_avail(buf), NGHTTP2_MAX_PAYLOADLEN);
rv = session->callbacks.pack_extension_callback(session, buf->last, buflen, if (session->callbacks.pack_extension_callback2) {
frame, session->user_data); rv = session->callbacks.pack_extension_callback2(session, buf->last, buflen,
frame, session->user_data);
} else {
rv = (nghttp2_ssize)session->callbacks.pack_extension_callback(
session, buf->last, buflen, frame, session->user_data);
}
if (rv == NGHTTP2_ERR_CANCEL) { if (rv == NGHTTP2_ERR_CANCEL) {
return (int)rv; return (int)rv;
} }
@@ -2451,7 +2461,7 @@ static int session_prep_frame(nghttp2_session *session,
return rv; return rv;
} }
DEBUGF("send: before padding, HEADERS serialized in %zd bytes\n", DEBUGF("send: before padding, HEADERS serialized in %zu bytes\n",
nghttp2_bufs_len(&session->aob.framebufs)); nghttp2_bufs_len(&session->aob.framebufs));
rv = session_headers_add_pad(session, frame); rv = session_headers_add_pad(session, frame);
@@ -2460,7 +2470,7 @@ static int session_prep_frame(nghttp2_session *session,
return rv; return rv;
} }
DEBUGF("send: HEADERS finally serialized in %zd bytes\n", DEBUGF("send: HEADERS finally serialized in %zu bytes\n",
nghttp2_bufs_len(&session->aob.framebufs)); nghttp2_bufs_len(&session->aob.framebufs));
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) { if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
@@ -2877,7 +2887,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
/* Call on_frame_send_callback after /* Call on_frame_send_callback after
nghttp2_stream_detach_item(), so that application can issue nghttp2_stream_detach_item(), so that application can issue
nghttp2_submit_data() in the callback. */ nghttp2_submit_data2() in the callback. */
if (session->callbacks.on_frame_send_callback) { if (session->callbacks.on_frame_send_callback) {
rv = session_call_on_frame_send(session, frame); rv = session_call_on_frame_send(session, frame);
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
@@ -2949,15 +2959,17 @@ static int session_after_frame_sent1(nghttp2_session *session) {
} }
/* We assume aux_data is a pointer to nghttp2_headers_aux_data */ /* We assume aux_data is a pointer to nghttp2_headers_aux_data */
aux_data = &item->aux_data.headers; aux_data = &item->aux_data.headers;
if (aux_data->data_prd.read_callback) { if (aux_data->dpw.data_prd.read_callback) {
/* nghttp2_submit_data() makes a copy of aux_data->data_prd */ /* nghttp2_submit_data_shared() makes a copy of
rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, aux_data->dpw */
frame->hd.stream_id, &aux_data->data_prd); rv = nghttp2_submit_data_shared(session, NGHTTP2_FLAG_END_STREAM,
frame->hd.stream_id, &aux_data->dpw);
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
/* TODO nghttp2_submit_data() may fail if stream has already /* TODO nghttp2_submit_data_shared() may fail if stream has
DATA frame item. We might have to handle it here. */ already DATA frame item. We might have to handle it
here. */
} }
return 0; return 0;
} }
@@ -2978,14 +2990,15 @@ static int session_after_frame_sent1(nghttp2_session *session) {
} }
/* We assume aux_data is a pointer to nghttp2_headers_aux_data */ /* We assume aux_data is a pointer to nghttp2_headers_aux_data */
aux_data = &item->aux_data.headers; aux_data = &item->aux_data.headers;
if (aux_data->data_prd.read_callback) { if (aux_data->dpw.data_prd.read_callback) {
rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, rv = nghttp2_submit_data_shared(session, NGHTTP2_FLAG_END_STREAM,
frame->hd.stream_id, &aux_data->data_prd); frame->hd.stream_id, &aux_data->dpw);
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
/* TODO nghttp2_submit_data() may fail if stream has already /* TODO nghttp2_submit_data_shared() may fail if stream has
DATA frame item. We might have to handle it here. */ already DATA frame item. We might have to handle it
here. */
} }
return 0; return 0;
default: default:
@@ -3144,7 +3157,7 @@ static void session_after_frame_sent2(nghttp2_session *session) {
aux_data = &item->aux_data.data; aux_data = &item->aux_data.data;
/* On EOF, we have already detached data. Please note that /* On EOF, we have already detached data. Please note that
application may issue nghttp2_submit_data() in application may issue nghttp2_submit_data2() in
on_frame_send_callback (call from session_after_frame_sent1), on_frame_send_callback (call from session_after_frame_sent1),
which attach data to stream. We don't want to detach it. */ which attach data to stream. We don't want to detach it. */
if (aux_data->eof) { if (aux_data->eof) {
@@ -3191,7 +3204,7 @@ static int session_call_send_data(nghttp2_session *session,
aux_data = &item->aux_data.data; aux_data = &item->aux_data.data;
rv = session->callbacks.send_data_callback(session, frame, buf->pos, length, rv = session->callbacks.send_data_callback(session, frame, buf->pos, length,
&aux_data->data_prd.source, &aux_data->dpw.data_prd.source,
session->user_data); session->user_data);
switch (rv) { switch (rv) {
@@ -3205,9 +3218,9 @@ static int session_call_send_data(nghttp2_session *session,
} }
} }
static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, static nghttp2_ssize nghttp2_session_mem_send_internal(nghttp2_session *session,
const uint8_t **data_ptr, const uint8_t **data_ptr,
int fast_cb) { int fast_cb) {
int rv; int rv;
nghttp2_active_outbound_item *aob; nghttp2_active_outbound_item *aob;
nghttp2_bufs *framebufs; nghttp2_bufs *framebufs;
@@ -3385,7 +3398,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
} }
} }
DEBUGF("send: start transmitting frame type=%u, length=%zd\n", DEBUGF("send: start transmitting frame type=%u, length=%td\n",
framebufs->cur->buf.pos[3], framebufs->cur->buf.pos[3],
framebufs->cur->buf.last - framebufs->cur->buf.pos); framebufs->cur->buf.last - framebufs->cur->buf.pos);
@@ -3425,7 +3438,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
everything, we will adjust it. */ everything, we will adjust it. */
buf->pos += datalen; buf->pos += datalen;
return (ssize_t)datalen; return (nghttp2_ssize)datalen;
} }
case NGHTTP2_OB_SEND_NO_COPY: { case NGHTTP2_OB_SEND_NO_COPY: {
nghttp2_stream *stream; nghttp2_stream *stream;
@@ -3502,7 +3515,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
buf->pos += datalen; buf->pos += datalen;
return (ssize_t)datalen; return (nghttp2_ssize)datalen;
} }
} }
} }
@@ -3510,8 +3523,13 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
ssize_t nghttp2_session_mem_send(nghttp2_session *session, ssize_t nghttp2_session_mem_send(nghttp2_session *session,
const uint8_t **data_ptr) { const uint8_t **data_ptr) {
return (ssize_t)nghttp2_session_mem_send2(session, data_ptr);
}
nghttp2_ssize nghttp2_session_mem_send2(nghttp2_session *session,
const uint8_t **data_ptr) {
int rv; int rv;
ssize_t len; nghttp2_ssize len;
*data_ptr = NULL; *data_ptr = NULL;
@@ -3528,7 +3546,7 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
rv = session_after_frame_sent1(session); rv = session_after_frame_sent1(session);
if (rv < 0) { if (rv < 0) {
assert(nghttp2_is_fatal(rv)); assert(nghttp2_is_fatal(rv));
return (ssize_t)rv; return (nghttp2_ssize)rv;
} }
} }
@@ -3537,8 +3555,8 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
int nghttp2_session_send(nghttp2_session *session) { int nghttp2_session_send(nghttp2_session *session) {
const uint8_t *data = NULL; const uint8_t *data = NULL;
ssize_t datalen; nghttp2_ssize datalen;
ssize_t sentlen; nghttp2_ssize sentlen;
nghttp2_bufs *framebufs; nghttp2_bufs *framebufs;
framebufs = &session->aob.framebufs; framebufs = &session->aob.framebufs;
@@ -3548,8 +3566,13 @@ int nghttp2_session_send(nghttp2_session *session) {
if (datalen <= 0) { if (datalen <= 0) {
return (int)datalen; return (int)datalen;
} }
sentlen = session->callbacks.send_callback(session, data, (size_t)datalen, if (session->callbacks.send_callback2) {
0, session->user_data); sentlen = session->callbacks.send_callback2(
session, data, (size_t)datalen, 0, session->user_data);
} else {
sentlen = (nghttp2_ssize)session->callbacks.send_callback(
session, data, (size_t)datalen, 0, session->user_data);
}
if (sentlen < 0) { if (sentlen < 0) {
if (sentlen == NGHTTP2_ERR_WOULDBLOCK) { if (sentlen == NGHTTP2_ERR_WOULDBLOCK) {
/* Transmission canceled. Rewind the offset */ /* Transmission canceled. Rewind the offset */
@@ -3564,11 +3587,17 @@ int nghttp2_session_send(nghttp2_session *session) {
} }
} }
static ssize_t session_recv(nghttp2_session *session, uint8_t *buf, static nghttp2_ssize session_recv(nghttp2_session *session, uint8_t *buf,
size_t len) { size_t len) {
ssize_t rv; nghttp2_ssize rv;
rv = session->callbacks.recv_callback(session, buf, len, 0,
session->user_data); if (session->callbacks.recv_callback2) {
rv = session->callbacks.recv_callback2(session, buf, len, 0,
session->user_data);
} else {
rv = (nghttp2_ssize)session->callbacks.recv_callback(session, buf, len, 0,
session->user_data);
}
if (rv > 0) { if (rv > 0) {
if ((size_t)rv > len) { if ((size_t)rv > len) {
return NGHTTP2_ERR_CALLBACK_FAILURE; return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -3870,7 +3899,7 @@ static int session_inflate_handle_invalid_connection(nghttp2_session *session,
static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
size_t *readlen_ptr, uint8_t *in, size_t inlen, size_t *readlen_ptr, uint8_t *in, size_t inlen,
int final, int call_header_cb) { int final, int call_header_cb) {
ssize_t proclen; nghttp2_ssize proclen;
int rv; int rv;
int inflate_flags; int inflate_flags;
nghttp2_hd_nv nv; nghttp2_hd_nv nv;
@@ -3923,7 +3952,7 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
inlen -= (size_t)proclen; inlen -= (size_t)proclen;
*readlen_ptr += (size_t)proclen; *readlen_ptr += (size_t)proclen;
DEBUGF("recv: proclen=%zd\n", proclen); DEBUGF("recv: proclen=%td\n", proclen);
if (call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) { if (call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) {
rv = 0; rv = 0;
@@ -5763,7 +5792,7 @@ static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe,
* Computes number of padding based on flags. This function returns * Computes number of padding based on flags. This function returns
* the calculated length if it succeeds, or -1. * the calculated length if it succeeds, or -1.
*/ */
static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) { static nghttp2_ssize inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) {
size_t padlen; size_t padlen;
/* 1 for Pad Length field */ /* 1 for Pad Length field */
@@ -5778,7 +5807,7 @@ static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) {
iframe->padlen = padlen; iframe->padlen = padlen;
return (ssize_t)padlen; return (nghttp2_ssize)padlen;
} }
/* /*
@@ -5787,9 +5816,9 @@ static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) {
* |payloadleft| does not include |readlen|. If padding was started * |payloadleft| does not include |readlen|. If padding was started
* strictly before this data chunk, this function returns -1. * strictly before this data chunk, this function returns -1.
*/ */
static ssize_t inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe, static nghttp2_ssize
size_t payloadleft, inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe,
size_t readlen) { size_t payloadleft, size_t readlen) {
size_t trail_padlen = size_t trail_padlen =
nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen); nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen);
@@ -5799,19 +5828,24 @@ static ssize_t inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe,
if (readlen < padlen) { if (readlen < padlen) {
return -1; return -1;
} }
return (ssize_t)(readlen - padlen); return (nghttp2_ssize)(readlen - padlen);
} }
return (ssize_t)(readlen); return (nghttp2_ssize)(readlen);
} }
static const uint8_t static_in[] = {0}; static const uint8_t static_in[] = {0};
ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
size_t inlen) { size_t inlen) {
return (ssize_t)nghttp2_session_mem_recv2(session, in, inlen);
}
nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
const uint8_t *in, size_t inlen) {
const uint8_t *first, *last; const uint8_t *first, *last;
nghttp2_inbound_frame *iframe = &session->iframe; nghttp2_inbound_frame *iframe = &session->iframe;
size_t readlen; size_t readlen;
ssize_t padlen; nghttp2_ssize padlen;
int rv; int rv;
int busy = 0; int busy = 0;
nghttp2_frame_hd cont_hd; nghttp2_frame_hd cont_hd;
@@ -5841,7 +5875,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (!nghttp2_session_want_read(session)) { if (!nghttp2_session_want_read(session)) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
for (;;) { for (;;) {
@@ -5871,7 +5905,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen; in += readlen;
if (nghttp2_buf_mark_avail(&iframe->sbuf)) { if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} }
if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS || if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS ||
@@ -5893,7 +5927,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
iframe->state = NGHTTP2_IB_READ_HEAD; iframe->state = NGHTTP2_IB_READ_HEAD;
@@ -5908,7 +5942,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen; in += readlen;
if (nghttp2_buf_mark_avail(&iframe->sbuf)) { if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} }
nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->sbuf.pos); nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->sbuf.pos);
@@ -5929,7 +5963,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
switch (iframe->frame.hd.type) { switch (iframe->frame.hd.type) {
@@ -5944,7 +5978,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
rv = session_on_data_received_fail_fast(session); rv = session_on_data_received_fail_fast(session);
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (rv == NGHTTP2_ERR_IGN_PAYLOAD) { if (rv == NGHTTP2_ERR_IGN_PAYLOAD) {
DEBUGF("recv: DATA not allowed stream_id=%d\n", DEBUGF("recv: DATA not allowed stream_id=%d\n",
@@ -5966,7 +6000,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (rv == 1) { if (rv == 1) {
@@ -5993,7 +6027,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (rv == 1) { if (rv == 1) {
@@ -6036,7 +6070,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
busy = 1; busy = 1;
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
@@ -6137,7 +6171,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) * iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) *
@@ -6175,7 +6209,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (rv == 1) { if (rv == 1) {
@@ -6235,7 +6269,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
default: default:
DEBUGF("recv: extension frame\n"); DEBUGF("recv: extension frame\n");
@@ -6346,7 +6380,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (iframe->payloadleft < 4) { if (iframe->payloadleft < 4) {
@@ -6404,11 +6438,11 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen; in += readlen;
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;
DEBUGF("recv: readlen=%zu, payloadleft=%zu, left=%zd\n", readlen, DEBUGF("recv: readlen=%zu, payloadleft=%zu, left=%zu\n", readlen,
iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf));
if (nghttp2_buf_mark_avail(&iframe->sbuf)) { if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} }
switch (iframe->frame.hd.type) { switch (iframe->frame.hd.type) {
@@ -6424,7 +6458,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
iframe->frame.headers.padlen = (size_t)padlen; iframe->frame.headers.padlen = (size_t)padlen;
@@ -6451,7 +6485,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
busy = 1; busy = 1;
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
@@ -6481,7 +6515,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
} }
@@ -6495,7 +6529,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
@@ -6513,7 +6547,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
iframe->frame.push_promise.padlen = (size_t)padlen; iframe->frame.push_promise.padlen = (size_t)padlen;
@@ -6539,7 +6573,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
busy = 1; busy = 1;
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
@@ -6568,7 +6602,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
@@ -6603,7 +6637,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
@@ -6661,7 +6695,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break; break;
case NGHTTP2_IB_READ_HEADER_BLOCK: case NGHTTP2_IB_READ_HEADER_BLOCK:
case NGHTTP2_IB_IGN_HEADER_BLOCK: { case NGHTTP2_IB_IGN_HEADER_BLOCK: {
ssize_t data_readlen; nghttp2_ssize data_readlen;
size_t trail_padlen; size_t trail_padlen;
int final; int final;
#ifdef DEBUGBUILD #ifdef DEBUGBUILD
@@ -6705,14 +6739,14 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (rv == NGHTTP2_ERR_PAUSE) { if (rv == NGHTTP2_ERR_PAUSE) {
in += hd_proclen; in += hd_proclen;
iframe->payloadleft -= hd_proclen; iframe->payloadleft -= hd_proclen;
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} }
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
@@ -6819,7 +6853,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
assert(iframe->state == NGHTTP2_IB_IGN_ALL); assert(iframe->state == NGHTTP2_IB_IGN_ALL);
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
case NGHTTP2_IB_READ_SETTINGS: case NGHTTP2_IB_READ_SETTINGS:
DEBUGF("recv: [IB_READ_SETTINGS]\n"); DEBUGF("recv: [IB_READ_SETTINGS]\n");
@@ -6849,7 +6883,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
@@ -6883,7 +6917,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
@@ -6903,7 +6937,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen; in += readlen;
if (nghttp2_buf_mark_avail(&iframe->sbuf)) { if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} }
nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->sbuf.pos); nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->sbuf.pos);
@@ -6925,7 +6959,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
/* CONTINUATION won't bear NGHTTP2_PADDED flag */ /* CONTINUATION won't bear NGHTTP2_PADDED flag */
@@ -6961,7 +6995,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf));
if (nghttp2_buf_mark_avail(&iframe->sbuf)) { if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} }
/* Pad Length field is subject to flow control */ /* Pad Length field is subject to flow control */
@@ -6971,7 +7005,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
/* Pad Length field is consumed immediately */ /* Pad Length field is consumed immediately */
@@ -6983,7 +7017,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id); stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
@@ -7006,7 +7040,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
iframe->frame.data.padlen = (size_t)padlen; iframe->frame.data.padlen = (size_t)padlen;
@@ -7033,7 +7067,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->payloadleft); iframe->payloadleft);
if (readlen > 0) { if (readlen > 0) {
ssize_t data_readlen; nghttp2_ssize data_readlen;
rv = nghttp2_session_update_recv_connection_window_size(session, rv = nghttp2_session_update_recv_connection_window_size(session,
readlen); readlen);
@@ -7042,7 +7076,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
rv = nghttp2_session_update_recv_stream_window_size( rv = nghttp2_session_update_recv_stream_window_size(
@@ -7061,7 +7095,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
data_readlen = 0; data_readlen = 0;
} }
padlen = (ssize_t)readlen - data_readlen; padlen = (nghttp2_ssize)readlen - data_readlen;
if (padlen > 0) { if (padlen > 0) {
/* Padding is considered as "consumed" immediately */ /* Padding is considered as "consumed" immediately */
@@ -7073,11 +7107,11 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
} }
DEBUGF("recv: data_readlen=%zd\n", data_readlen); DEBUGF("recv: data_readlen=%td\n", data_readlen);
if (data_readlen > 0) { if (data_readlen > 0) {
if (session_enforce_http_messaging(session)) { if (session_enforce_http_messaging(session)) {
@@ -7092,7 +7126,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_DATA) { if (iframe->state == NGHTTP2_IB_IGN_DATA) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
} }
@@ -7111,7 +7145,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
session, iframe->frame.hd.flags, iframe->frame.hd.stream_id, session, iframe->frame.hd.flags, iframe->frame.hd.stream_id,
in - readlen, (size_t)data_readlen, session->user_data); in - readlen, (size_t)data_readlen, session->user_data);
if (rv == NGHTTP2_ERR_PAUSE) { if (rv == NGHTTP2_ERR_PAUSE) {
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} }
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
@@ -7153,7 +7187,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
@@ -7166,7 +7200,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
} }
} }
@@ -7179,7 +7213,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break; break;
case NGHTTP2_IB_IGN_ALL: case NGHTTP2_IB_IGN_ALL:
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
case NGHTTP2_IB_READ_EXTENSION_PAYLOAD: case NGHTTP2_IB_READ_EXTENSION_PAYLOAD:
DEBUGF("recv: [IB_READ_EXTENSION_PAYLOAD]\n"); DEBUGF("recv: [IB_READ_EXTENSION_PAYLOAD]\n");
@@ -7274,7 +7308,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
if (iframe->state == NGHTTP2_IB_IGN_ALL) { if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (ssize_t)inlen; return (nghttp2_ssize)inlen;
} }
session_inbound_frame_reset(session); session_inbound_frame_reset(session);
@@ -7291,16 +7325,17 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
assert(in == last); assert(in == last);
return (ssize_t)(in - first); return (nghttp2_ssize)(in - first);
} }
int nghttp2_session_recv(nghttp2_session *session) { int nghttp2_session_recv(nghttp2_session *session) {
uint8_t buf[NGHTTP2_INBOUND_BUFFER_LENGTH]; uint8_t buf[NGHTTP2_INBOUND_BUFFER_LENGTH];
while (1) { while (1) {
ssize_t readlen; nghttp2_ssize readlen;
readlen = session_recv(session, buf, sizeof(buf)); readlen = session_recv(session, buf, sizeof(buf));
if (readlen > 0) { if (readlen > 0) {
ssize_t proclen = nghttp2_session_mem_recv(session, buf, (size_t)readlen); nghttp2_ssize proclen =
nghttp2_session_mem_recv2(session, buf, (size_t)readlen);
if (proclen < 0) { if (proclen < 0) {
return (int)proclen; return (int)proclen;
} }
@@ -7642,8 +7677,8 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
nghttp2_stream *stream) { nghttp2_stream *stream) {
int rv; int rv;
uint32_t data_flags; uint32_t data_flags;
ssize_t payloadlen; nghttp2_ssize payloadlen;
ssize_t padded_payloadlen; nghttp2_ssize padded_payloadlen;
nghttp2_buf *buf; nghttp2_buf *buf;
size_t max_payloadlen; size_t max_payloadlen;
@@ -7651,19 +7686,26 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
buf = &bufs->cur->buf; buf = &bufs->cur->buf;
if (session->callbacks.read_length_callback) { if (session->callbacks.read_length_callback2 ||
session->callbacks.read_length_callback) {
if (session->callbacks.read_length_callback2) {
payloadlen = session->callbacks.read_length_callback2(
session, frame->hd.type, stream->stream_id,
session->remote_window_size, stream->remote_window_size,
session->remote_settings.max_frame_size, session->user_data);
} else {
payloadlen = (nghttp2_ssize)session->callbacks.read_length_callback(
session, frame->hd.type, stream->stream_id,
session->remote_window_size, stream->remote_window_size,
session->remote_settings.max_frame_size, session->user_data);
}
payloadlen = session->callbacks.read_length_callback( DEBUGF("send: read_length_callback=%td\n", payloadlen);
session, frame->hd.type, stream->stream_id, session->remote_window_size,
stream->remote_window_size, session->remote_settings.max_frame_size,
session->user_data);
DEBUGF("send: read_length_callback=%zd\n", payloadlen);
payloadlen = nghttp2_session_enforce_flow_control_limits(session, stream, payloadlen = nghttp2_session_enforce_flow_control_limits(session, stream,
payloadlen); payloadlen);
DEBUGF("send: read_length_callback after flow control=%zd\n", payloadlen); DEBUGF("send: read_length_callback after flow control=%td\n", payloadlen);
if (payloadlen <= 0) { if (payloadlen <= 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE; return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -7679,9 +7721,9 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
DEBUGF("send: realloc buffer failed rv=%d", rv); DEBUGF("send: realloc buffer failed rv=%d", rv);
/* If reallocation failed, old buffers are still in tact. So /* If reallocation failed, old buffers are still in tact. So
use safe limit. */ use safe limit. */
payloadlen = (ssize_t)datamax; payloadlen = (nghttp2_ssize)datamax;
DEBUGF("send: use safe limit payloadlen=%zd", payloadlen); DEBUGF("send: use safe limit payloadlen=%td", payloadlen);
} else { } else {
assert(&session->aob.framebufs == bufs); assert(&session->aob.framebufs == bufs);
@@ -7695,9 +7737,23 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
assert(nghttp2_buf_avail(buf) >= datamax); assert(nghttp2_buf_avail(buf) >= datamax);
data_flags = NGHTTP2_DATA_FLAG_NONE; data_flags = NGHTTP2_DATA_FLAG_NONE;
payloadlen = aux_data->data_prd.read_callback( switch (aux_data->dpw.version) {
session, frame->hd.stream_id, buf->pos, datamax, &data_flags, case NGHTTP2_DATA_PROVIDER_V1:
&aux_data->data_prd.source, session->user_data); payloadlen = (nghttp2_ssize)aux_data->dpw.data_prd.v1.read_callback(
session, frame->hd.stream_id, buf->pos, datamax, &data_flags,
&aux_data->dpw.data_prd.source, session->user_data);
break;
case NGHTTP2_DATA_PROVIDER_V2:
payloadlen = aux_data->dpw.data_prd.v2.read_callback(
session, frame->hd.stream_id, buf->pos, datamax, &data_flags,
&aux_data->dpw.data_prd.source, session->user_data);
break;
default:
assert(0);
abort();
}
if (payloadlen == NGHTTP2_ERR_DEFERRED || if (payloadlen == NGHTTP2_ERR_DEFERRED ||
payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE || payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE ||
@@ -8275,7 +8331,7 @@ int nghttp2_session_change_stream_priority(
/* We don't intentionally call nghttp2_session_adjust_idle_stream() /* We don't intentionally call nghttp2_session_adjust_idle_stream()
so that idle stream created by this function, and existing ones so that idle stream created by this function, and existing ones
are kept for application. We will adjust number of idle stream are kept for application. We will adjust number of idle stream
in nghttp2_session_mem_send or nghttp2_session_mem_recv is in nghttp2_session_mem_send2 or nghttp2_session_mem_recv2 is
called. */ called. */
return 0; return 0;
} }
@@ -8313,7 +8369,7 @@ int nghttp2_session_create_idle_stream(nghttp2_session *session,
/* We don't intentionally call nghttp2_session_adjust_idle_stream() /* We don't intentionally call nghttp2_session_adjust_idle_stream()
so that idle stream created by this function, and existing ones so that idle stream created by this function, and existing ones
are kept for application. We will adjust number of idle stream are kept for application. We will adjust number of idle stream
in nghttp2_session_mem_send or nghttp2_session_mem_recv is in nghttp2_session_mem_send2 or nghttp2_session_mem_recv2 is
called. */ called. */
return 0; return 0;
} }

View File

@@ -68,7 +68,7 @@ static int32_t submit_headers_shared(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,
nghttp2_nv *nva_copy, size_t nvlen, nghttp2_nv *nva_copy, size_t nvlen,
const nghttp2_data_provider *data_prd, const nghttp2_data_provider_wrap *dpw,
void *stream_user_data) { void *stream_user_data) {
int rv; int rv;
uint8_t flags_copy; uint8_t flags_copy;
@@ -87,8 +87,8 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
nghttp2_outbound_item_init(item); nghttp2_outbound_item_init(item);
if (data_prd != NULL && data_prd->read_callback != NULL) { if (dpw != NULL && dpw->data_prd.read_callback != NULL) {
item->aux_data.headers.data_prd = *data_prd; item->aux_data.headers.dpw = *dpw;
} }
item->aux_data.headers.stream_user_data = stream_user_data; item->aux_data.headers.stream_user_data = stream_user_data;
@@ -143,7 +143,7 @@ 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_priority_spec *pri_spec,
const nghttp2_nv *nva, size_t nvlen, const nghttp2_nv *nva, size_t nvlen,
const nghttp2_data_provider *data_prd, 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;
@@ -165,7 +165,7 @@ static int32_t submit_headers_shared_nva(nghttp2_session *session,
} }
return submit_headers_shared(session, flags, stream_id, &copy_pri_spec, return submit_headers_shared(session, flags, stream_id, &copy_pri_spec,
nva_copy, nvlen, data_prd, 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,
@@ -740,9 +740,9 @@ fail_item_malloc:
} }
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec, static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
const nghttp2_data_provider *data_prd) { const nghttp2_data_provider_wrap *dpw) {
uint8_t flags = NGHTTP2_FLAG_NONE; uint8_t flags = NGHTTP2_FLAG_NONE;
if (data_prd == NULL || data_prd->read_callback == NULL) { if (dpw == NULL || dpw->data_prd.read_callback == NULL) {
flags |= NGHTTP2_FLAG_END_STREAM; flags |= NGHTTP2_FLAG_END_STREAM;
} }
@@ -753,11 +753,11 @@ static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
return flags; return flags;
} }
int32_t nghttp2_submit_request(nghttp2_session *session, static int32_t submit_request_shared(nghttp2_session *session,
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,
const nghttp2_data_provider *data_prd, const nghttp2_data_provider_wrap *dpw,
void *stream_user_data) { void *stream_user_data) {
uint8_t flags; uint8_t flags;
int rv; int rv;
@@ -775,23 +775,47 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
pri_spec = NULL; pri_spec = NULL;
} }
flags = set_request_flags(pri_spec, data_prd); flags = set_request_flags(pri_spec, dpw);
return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen, return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen,
data_prd, stream_user_data); dpw, stream_user_data);
} }
static uint8_t set_response_flags(const nghttp2_data_provider *data_prd) { int32_t nghttp2_submit_request(nghttp2_session *session,
const nghttp2_priority_spec *pri_spec,
const nghttp2_nv *nva, size_t nvlen,
const nghttp2_data_provider *data_prd,
void *stream_user_data) {
nghttp2_data_provider_wrap dpw;
return submit_request_shared(session, pri_spec, nva, nvlen,
nghttp2_data_provider_wrap_v1(&dpw, data_prd),
stream_user_data);
}
int32_t nghttp2_submit_request2(nghttp2_session *session,
const nghttp2_priority_spec *pri_spec,
const nghttp2_nv *nva, size_t nvlen,
const nghttp2_data_provider2 *data_prd,
void *stream_user_data) {
nghttp2_data_provider_wrap dpw;
return submit_request_shared(session, pri_spec, nva, nvlen,
nghttp2_data_provider_wrap_v2(&dpw, data_prd),
stream_user_data);
}
static uint8_t set_response_flags(const nghttp2_data_provider_wrap *dpw) {
uint8_t flags = NGHTTP2_FLAG_NONE; uint8_t flags = NGHTTP2_FLAG_NONE;
if (data_prd == NULL || data_prd->read_callback == NULL) { if (dpw == NULL || dpw->data_prd.read_callback == NULL) {
flags |= NGHTTP2_FLAG_END_STREAM; flags |= NGHTTP2_FLAG_END_STREAM;
} }
return flags; return flags;
} }
int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, static int submit_response_shared(nghttp2_session *session, int32_t stream_id,
const nghttp2_nv *nva, size_t nvlen, const nghttp2_nv *nva, size_t nvlen,
const nghttp2_data_provider *data_prd) { const nghttp2_data_provider_wrap *dpw) {
uint8_t flags; uint8_t flags;
if (stream_id <= 0) { if (stream_id <= 0) {
@@ -802,14 +826,32 @@ int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
return NGHTTP2_ERR_PROTO; return NGHTTP2_ERR_PROTO;
} }
flags = set_response_flags(data_prd); flags = set_response_flags(dpw);
return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen, return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen,
data_prd, NULL); dpw, NULL);
} }
int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
int32_t stream_id, const nghttp2_nv *nva, size_t nvlen,
const nghttp2_data_provider *data_prd) { const nghttp2_data_provider *data_prd) {
nghttp2_data_provider_wrap dpw;
return submit_response_shared(session, stream_id, nva, nvlen,
nghttp2_data_provider_wrap_v1(&dpw, data_prd));
}
int nghttp2_submit_response2(nghttp2_session *session, int32_t stream_id,
const nghttp2_nv *nva, size_t nvlen,
const nghttp2_data_provider2 *data_prd) {
nghttp2_data_provider_wrap dpw;
return submit_response_shared(session, stream_id, nva, nvlen,
nghttp2_data_provider_wrap_v2(&dpw, data_prd));
}
int nghttp2_submit_data_shared(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
const nghttp2_data_provider_wrap *dpw) {
int rv; int rv;
nghttp2_outbound_item *item; nghttp2_outbound_item *item;
nghttp2_frame *frame; nghttp2_frame *frame;
@@ -832,7 +874,7 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
frame = &item->frame; frame = &item->frame;
aux_data = &item->aux_data.data; aux_data = &item->aux_data.data;
aux_data->data_prd = *data_prd; aux_data->dpw = *dpw;
aux_data->eof = 0; aux_data->eof = 0;
aux_data->flags = nflags; aux_data->flags = nflags;
@@ -848,9 +890,37 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
return 0; return 0;
} }
int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
const nghttp2_data_provider *data_prd) {
nghttp2_data_provider_wrap dpw;
assert(data_prd);
return nghttp2_submit_data_shared(
session, flags, stream_id, nghttp2_data_provider_wrap_v1(&dpw, data_prd));
}
int nghttp2_submit_data2(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
const nghttp2_data_provider2 *data_prd) {
nghttp2_data_provider_wrap dpw;
assert(data_prd);
return nghttp2_submit_data_shared(
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,
const nghttp2_settings_entry *iv, const nghttp2_settings_entry *iv,
size_t niv) { size_t niv) {
return (ssize_t)nghttp2_pack_settings_payload2(buf, buflen, iv, niv);
}
nghttp2_ssize nghttp2_pack_settings_payload2(uint8_t *buf, size_t buflen,
const nghttp2_settings_entry *iv,
size_t niv) {
if (!nghttp2_iv_check(iv, niv)) { if (!nghttp2_iv_check(iv, niv)) {
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
@@ -859,7 +929,7 @@ ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
return NGHTTP2_ERR_INSUFF_BUFSIZE; return NGHTTP2_ERR_INSUFF_BUFSIZE;
} }
return (ssize_t)nghttp2_frame_pack_settings_payload(buf, iv, niv); return (nghttp2_ssize)nghttp2_frame_pack_settings_payload(buf, iv, niv);
} }
int nghttp2_submit_extension(nghttp2_session *session, uint8_t type, int nghttp2_submit_extension(nghttp2_session *session, uint8_t type,
@@ -875,7 +945,8 @@ int nghttp2_submit_extension(nghttp2_session *session, uint8_t type,
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
if (!session->callbacks.pack_extension_callback) { if (!session->callbacks.pack_extension_callback2 &&
!session->callbacks.pack_extension_callback) {
return NGHTTP2_ERR_INVALID_STATE; return NGHTTP2_ERR_INVALID_STATE;
} }

View File

@@ -31,4 +31,10 @@
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
typedef struct nghttp2_data_provider_wrap nghttp2_data_provider_wrap;
int nghttp2_submit_data_shared(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
const nghttp2_data_provider_wrap *dpw);
#endif /* NGHTTP2_SUBMIT_H */ #endif /* NGHTTP2_SUBMIT_H */

View File

@@ -6,7 +6,7 @@ PREV_TAG=$2
git checkout refs/tags/$TAG git checkout refs/tags/$TAG
git log --pretty=fuller --date=short refs/tags/$PREV_TAG..HEAD > ChangeLog git log --pretty=fuller --date=short refs/tags/$PREV_TAG..HEAD > ChangeLog
git submodule update --init git submodule update --init --depth 1
autoreconf -i autoreconf -i
./configure --with-mruby && \ ./configure --with-mruby && \

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# nghttp2 - HTTP/2 C Library # nghttp2 - HTTP/2 C Library

View File

@@ -21,6 +21,8 @@ include_directories(
${JANSSON_INCLUDE_DIRS} ${JANSSON_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS}
${LIBBPF_INCLUDE_DIRS} ${LIBBPF_INCLUDE_DIRS}
${LIBBROTLIENC_INCLUDE_DIRS}
${LIBBROTLIDEC_INCLUDE_DIRS}
) )
# XXX per-target? # XXX per-target?
@@ -38,6 +40,8 @@ link_libraries(
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
${APP_LIBRARIES} ${APP_LIBRARIES}
${LIBBPF_LIBRARIES} ${LIBBPF_LIBRARIES}
${LIBBROTLIENC_LIBRARIES}
${LIBBROTLIDEC_LIBRARIES}
) )
if(ENABLE_APP) if(ENABLE_APP)
@@ -163,45 +167,45 @@ if(ENABLE_APP)
target_link_libraries(nghttpx_static neverbleed) target_link_libraries(nghttpx_static neverbleed)
endif() endif()
set(NGHTTPX_UNITTEST_SOURCES
if(HAVE_CUNIT) shrpx-unittest.cc
set(NGHTTPX_UNITTEST_SOURCES shrpx_tls_test.cc
shrpx-unittest.cc shrpx_downstream_test.cc
shrpx_tls_test.cc shrpx_config_test.cc
shrpx_downstream_test.cc shrpx_worker_test.cc
shrpx_config_test.cc shrpx_http_test.cc
shrpx_worker_test.cc shrpx_router_test.cc
shrpx_http_test.cc http2_test.cc
shrpx_router_test.cc util_test.cc
http2_test.cc nghttp2_gzip_test.c
util_test.cc nghttp2_gzip.c
nghttp2_gzip_test.c buffer_test.cc
nghttp2_gzip.c memchunk_test.cc
buffer_test.cc template_test.cc
memchunk_test.cc base64_test.cc
template_test.cc ${CMAKE_SOURCE_DIR}/tests/munit/munit.c
base64_test.cc )
add_executable(nghttpx-unittest EXCLUDE_FROM_ALL
${NGHTTPX_UNITTEST_SOURCES}
$<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:url-parser>
) )
add_executable(nghttpx-unittest EXCLUDE_FROM_ALL target_include_directories(nghttpx-unittest PRIVATE
${NGHTTPX_UNITTEST_SOURCES} ${CMAKE_SOURCE_DIR}/tests/munit
$<TARGET_OBJECTS:llhttp> )
$<TARGET_OBJECTS:url-parser> target_compile_definitions(nghttpx-unittest
) PRIVATE "-DNGHTTP2_SRC_DIR=\"${CMAKE_SOURCE_DIR}/src\""
target_include_directories(nghttpx-unittest PRIVATE ${CUNIT_INCLUDE_DIRS}) )
target_compile_definitions(nghttpx-unittest target_link_libraries(nghttpx-unittest nghttpx_static)
PRIVATE "-DNGHTTP2_SRC_DIR=\"${CMAKE_SOURCE_DIR}/src\"" if(HAVE_MRUBY)
) target_link_libraries(nghttpx-unittest mruby-lib)
target_link_libraries(nghttpx-unittest nghttpx_static ${CUNIT_LIBRARIES})
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()
if(HAVE_NEVERBLEED)
target_link_libraries(nghttpx-unittest neverbleed)
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:url-parser> $<TARGET_OBJECTS:url-parser>
@@ -221,8 +225,7 @@ if(ENABLE_APP)
$<TARGET_OBJECTS:url-parser> $<TARGET_OBJECTS:url-parser>
) )
install(TARGETS nghttp nghttpd nghttpx h2load install(TARGETS nghttp nghttpd nghttpx h2load)
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif() endif()
if(ENABLE_HPACK_TOOLS) if(ENABLE_HPACK_TOOLS)
@@ -238,6 +241,5 @@ if(ENABLE_HPACK_TOOLS)
) )
add_executable(inflatehd ${inflatehd_SOURCES}) add_executable(inflatehd ${inflatehd_SOURCES})
add_executable(deflatehd ${deflatehd_SOURCES}) add_executable(deflatehd ${deflatehd_SOURCES})
install(TARGETS inflatehd deflatehd install(TARGETS inflatehd deflatehd)
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif() endif()

View File

@@ -607,10 +607,10 @@ int Http2Handler::fill_wb() {
for (;;) { for (;;) {
const uint8_t *data; const uint8_t *data;
auto datalen = nghttp2_session_mem_send(session_, &data); auto datalen = nghttp2_session_mem_send2(session_, &data);
if (datalen < 0) { if (datalen < 0) {
std::cerr << "nghttp2_session_mem_send() returned error: " std::cerr << "nghttp2_session_mem_send2() returned error: "
<< nghttp2_strerror(datalen) << std::endl; << nghttp2_strerror(datalen) << std::endl;
return -1; return -1;
} }
@@ -648,10 +648,10 @@ int Http2Handler::read_clear() {
util::hexdump(stdout, buf.data(), nread); util::hexdump(stdout, buf.data(), nread);
} }
rv = nghttp2_session_mem_recv(session_, buf.data(), nread); rv = nghttp2_session_mem_recv2(session_, buf.data(), nread);
if (rv < 0) { if (rv < 0) {
if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) { if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
std::cerr << "nghttp2_session_mem_recv() returned error: " std::cerr << "nghttp2_session_mem_recv2() returned error: "
<< nghttp2_strerror(rv) << std::endl; << nghttp2_strerror(rv) << std::endl;
} }
return -1; return -1;
@@ -771,10 +771,10 @@ int Http2Handler::read_tls() {
util::hexdump(stdout, buf.data(), nread); util::hexdump(stdout, buf.data(), nread);
} }
rv = nghttp2_session_mem_recv(session_, buf.data(), nread); rv = nghttp2_session_mem_recv2(session_, buf.data(), nread);
if (rv < 0) { if (rv < 0) {
if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) { if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
std::cerr << "nghttp2_session_mem_recv() returned error: " std::cerr << "nghttp2_session_mem_recv2() returned error: "
<< nghttp2_strerror(rv) << std::endl; << nghttp2_strerror(rv) << std::endl;
} }
return -1; return -1;
@@ -917,7 +917,7 @@ int Http2Handler::verify_alpn_result() {
int Http2Handler::submit_file_response(const StringRef &status, Stream *stream, int Http2Handler::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_provider *data_prd) { nghttp2_data_provider2 *data_prd) {
std::string last_modified_str; std::string last_modified_str;
auto nva = make_array(http2::make_nv_ls_nocopy(":status", status), auto nva = make_array(http2::make_nv_ls_nocopy(":status", status),
http2::make_nv_ls_nocopy("server", NGHTTPD_SERVER), http2::make_nv_ls_nocopy("server", NGHTTPD_SERVER),
@@ -942,13 +942,13 @@ int Http2Handler::submit_file_response(const StringRef &status, Stream *stream,
if (!trailer_names.empty()) { if (!trailer_names.empty()) {
nva[nvlen++] = http2::make_nv_ls_nocopy("trailer", trailer_names); nva[nvlen++] = http2::make_nv_ls_nocopy("trailer", trailer_names);
} }
return nghttp2_submit_response(session_, stream->stream_id, nva.data(), nvlen, return nghttp2_submit_response2(session_, stream->stream_id, nva.data(),
data_prd); nvlen, data_prd);
} }
int Http2Handler::submit_response(const StringRef &status, int32_t stream_id, int Http2Handler::submit_response(const StringRef &status, int32_t stream_id,
const HeaderRefs &headers, const HeaderRefs &headers,
nghttp2_data_provider *data_prd) { nghttp2_data_provider2 *data_prd) {
auto nva = std::vector<nghttp2_nv>(); auto nva = std::vector<nghttp2_nv>();
nva.reserve(4 + headers.size()); nva.reserve(4 + headers.size());
nva.push_back(http2::make_nv_ls_nocopy(":status", status)); nva.push_back(http2::make_nv_ls_nocopy(":status", status));
@@ -965,13 +965,13 @@ int Http2Handler::submit_response(const StringRef &status, int32_t stream_id,
for (auto &nv : headers) { for (auto &nv : headers) {
nva.push_back(http2::make_nv_nocopy(nv.name, nv.value, nv.no_index)); nva.push_back(http2::make_nv_nocopy(nv.name, nv.value, nv.no_index));
} }
int r = nghttp2_submit_response(session_, stream_id, nva.data(), nva.size(), int r = nghttp2_submit_response2(session_, stream_id, nva.data(), nva.size(),
data_prd); data_prd);
return r; return r;
} }
int Http2Handler::submit_response(const StringRef &status, int32_t stream_id, int Http2Handler::submit_response(const StringRef &status, int32_t stream_id,
nghttp2_data_provider *data_prd) { nghttp2_data_provider2 *data_prd) {
auto nva = make_array(http2::make_nv_ls_nocopy(":status", status), auto nva = make_array(http2::make_nv_ls_nocopy(":status", status),
http2::make_nv_ls_nocopy("server", NGHTTPD_SERVER), http2::make_nv_ls_nocopy("server", NGHTTPD_SERVER),
http2::make_nv_ls("date", sessions_->get_cached_date()), http2::make_nv_ls("date", sessions_->get_cached_date()),
@@ -985,8 +985,8 @@ int Http2Handler::submit_response(const StringRef &status, int32_t stream_id,
} }
} }
return nghttp2_submit_response(session_, stream_id, nva.data(), nvlen, return nghttp2_submit_response2(session_, stream_id, nva.data(), nvlen,
data_prd); data_prd);
} }
int Http2Handler::submit_non_final_response(const std::string &status, int Http2Handler::submit_non_final_response(const std::string &status,
@@ -1076,9 +1076,10 @@ void Http2Handler::terminate_session(uint32_t error_code) {
nghttp2_session_terminate_session(session_, error_code); nghttp2_session_terminate_session(session_, error_code);
} }
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, nghttp2_ssize file_read_callback(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length, uint32_t *data_flags, uint8_t *buf, size_t length,
nghttp2_data_source *source, void *user_data) { uint32_t *data_flags,
nghttp2_data_source *source, void *user_data) {
int rv; int rv;
auto hd = static_cast<Http2Handler *>(user_data); auto hd = static_cast<Http2Handler *>(user_data);
auto stream = hd->get_stream(stream_id); auto stream = hd->get_stream(stream_id);
@@ -1127,7 +1128,7 @@ void prepare_status_response(Stream *stream, Http2Handler *hd, int status) {
// we don't set stream->file_ent since we don't want to expire it. // we don't set stream->file_ent since we don't want to expire it.
stream->body_length = file_ent->length; stream->body_length = file_ent->length;
nghttp2_data_provider data_prd; nghttp2_data_provider2 data_prd;
data_prd.source.fd = file_ent->fd; data_prd.source.fd = file_ent->fd;
data_prd.read_callback = file_read_callback; data_prd.read_callback = file_read_callback;
@@ -1155,7 +1156,7 @@ void prepare_echo_response(Stream *stream, Http2Handler *hd) {
hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR); hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
return; return;
} }
nghttp2_data_provider data_prd; nghttp2_data_provider2 data_prd;
data_prd.source.fd = stream->file_ent->fd; data_prd.source.fd = stream->file_ent->fd;
data_prd.read_callback = file_read_callback; data_prd.read_callback = file_read_callback;
@@ -1378,7 +1379,7 @@ void prepare_response(Stream *stream, Http2Handler *hd,
stream->body_length = file_ent->length; stream->body_length = file_ent->length;
nghttp2_data_provider data_prd; nghttp2_data_provider2 data_prd;
data_prd.source.fd = file_ent->fd; data_prd.source.fd = file_ent->fd;
data_prd.read_callback = file_read_callback; data_prd.read_callback = file_read_callback;
@@ -1676,9 +1677,9 @@ int send_data_callback(nghttp2_session *session, nghttp2_frame *frame,
} // namespace } // namespace
namespace { namespace {
ssize_t select_padding_callback(nghttp2_session *session, nghttp2_ssize select_padding_callback(nghttp2_session *session,
const nghttp2_frame *frame, size_t max_payload, const nghttp2_frame *frame,
void *user_data) { size_t max_payload, void *user_data) {
auto hd = static_cast<Http2Handler *>(user_data); auto hd = static_cast<Http2Handler *>(user_data);
return std::min(max_payload, frame->hd.length + hd->get_config()->padding); return std::min(max_payload, frame->hd.length + hd->get_config()->padding);
} }
@@ -1765,7 +1766,7 @@ void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config) {
send_data_callback); send_data_callback);
if (config->padding) { if (config->padding) {
nghttp2_session_callbacks_set_select_padding_callback( nghttp2_session_callbacks_set_select_padding_callback2(
callbacks, select_padding_callback); callbacks, select_padding_callback);
} }
} }
@@ -2205,6 +2206,15 @@ int HttpServer::run() {
// ALPN selection callback // ALPN selection callback
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this); SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this);
#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI)
if (!SSL_CTX_add_cert_compression_alg(
ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI,
nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) {
std::cerr << "SSL_CTX_add_cert_compression_alg failed." << std::endl;
return -1;
}
#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI
} }
auto loop = EV_DEFAULT; auto loop = EV_DEFAULT;

View File

@@ -41,6 +41,7 @@
#include <ev.h> #include <ev.h>
#define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include "http2.h" #include "http2.h"
@@ -172,14 +173,14 @@ public:
int submit_file_response(const StringRef &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_provider *data_prd); nghttp2_data_provider2 *data_prd);
int submit_response(const StringRef &status, int32_t stream_id, int submit_response(const StringRef &status, int32_t stream_id,
nghttp2_data_provider *data_prd); nghttp2_data_provider2 *data_prd);
int submit_response(const StringRef &status, int32_t stream_id, int submit_response(const StringRef &status, int32_t stream_id,
const HeaderRefs &headers, const HeaderRefs &headers,
nghttp2_data_provider *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);

View File

@@ -53,6 +53,8 @@ AM_CPPFLAGS = \
@JANSSON_CFLAGS@ \ @JANSSON_CFLAGS@ \
@LIBBPF_CFLAGS@ \ @LIBBPF_CFLAGS@ \
@ZLIB_CFLAGS@ \ @ZLIB_CFLAGS@ \
@LIBBROTLIENC_CFLAGS@ \
@LIBBROTLIDEC_CFLAGS@ \
@EXTRA_DEFS@ \ @EXTRA_DEFS@ \
@DEFS@ @DEFS@
AM_LDFLAGS = @LIBTOOL_LDFLAGS@ AM_LDFLAGS = @LIBTOOL_LDFLAGS@
@@ -73,6 +75,8 @@ LDADD = $(top_builddir)/lib/libnghttp2.la \
@JANSSON_LIBS@ \ @JANSSON_LIBS@ \
@LIBBPF_LIBS@ \ @LIBBPF_LIBS@ \
@ZLIB_LIBS@ \ @ZLIB_LIBS@ \
@LIBBROTLIENC_LIBS@ \
@LIBBROTLIDEC_LIBS@ \
@APPLDFLAGS@ @APPLDFLAGS@
if ENABLE_APP if ENABLE_APP
@@ -203,7 +207,6 @@ libnghttpx_a_CPPFLAGS += -I${top_srcdir}/third-party/neverbleed
nghttpx_LDADD += ${top_builddir}/third-party/libneverbleed.la nghttpx_LDADD += ${top_builddir}/third-party/libneverbleed.la
endif # HAVE_NEVERBLEED endif # HAVE_NEVERBLEED
if HAVE_CUNIT
check_PROGRAMS += nghttpx-unittest check_PROGRAMS += nghttpx-unittest
nghttpx_unittest_SOURCES = shrpx-unittest.cc \ nghttpx_unittest_SOURCES = shrpx-unittest.cc \
shrpx_tls_test.cc shrpx_tls_test.h \ shrpx_tls_test.cc shrpx_tls_test.h \
@@ -219,10 +222,13 @@ nghttpx_unittest_SOURCES = shrpx-unittest.cc \
buffer_test.cc buffer_test.h \ buffer_test.cc buffer_test.h \
memchunk_test.cc memchunk_test.h \ memchunk_test.cc memchunk_test.h \
template_test.cc template_test.h \ template_test.cc template_test.h \
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/munitxx.h
nghttpx_unittest_CPPFLAGS = ${AM_CPPFLAGS} \ nghttpx_unittest_CPPFLAGS = ${AM_CPPFLAGS} \
-I$(top_srcdir)/tests/munit \
-DNGHTTP2_SRC_DIR=\"$(top_srcdir)/src\" -DNGHTTP2_SRC_DIR=\"$(top_srcdir)/src\"
nghttpx_unittest_LDADD = libnghttpx.a ${LDADD} @CUNIT_LIBS@ @TESTLDADD@ nghttpx_unittest_LDADD = libnghttpx.a ${LDADD} @TESTLDADD@
if HAVE_MRUBY if HAVE_MRUBY
nghttpx_unittest_CPPFLAGS += \ nghttpx_unittest_CPPFLAGS += \
@@ -237,7 +243,6 @@ nghttpx_unittest_LDADD += ${top_builddir}/third-party/libneverbleed.la
endif # HAVE_NEVERBLEED endif # HAVE_NEVERBLEED
TESTS += nghttpx-unittest TESTS += nghttpx-unittest
endif # HAVE_CUNIT
endif # ENABLE_APP endif # ENABLE_APP

View File

@@ -119,7 +119,7 @@ struct BlockAllocator {
} }
if (!head || if (!head ||
head->end - head->last < static_cast<ssize_t>(size + sizeof(size_t))) { static_cast<size_t>(head->end - head->last) < size + sizeof(size_t)) {
head = alloc_mem_block(block_size); head = alloc_mem_block(block_size);
} }

View File

@@ -53,8 +53,6 @@
#include <iomanip> #include <iomanip>
#include <fstream> #include <fstream>
#include <zlib.h>
#include "app_helper.h" #include "app_helper.h"
#include "util.h" #include "util.h"
#include "http2.h" #include "http2.h"
@@ -477,42 +475,4 @@ std::chrono::steady_clock::time_point get_time() {
return std::chrono::steady_clock::now(); return std::chrono::steady_clock::now();
} }
ssize_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in,
size_t inlen) {
int rv;
z_stream zst{};
uint8_t temp_out[8_k];
auto temp_outlen = sizeof(temp_out);
rv = deflateInit2(&zst, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 9,
Z_DEFAULT_STRATEGY);
if (rv != Z_OK) {
return -1;
}
zst.avail_in = inlen;
zst.next_in = (uint8_t *)in;
zst.avail_out = temp_outlen;
zst.next_out = temp_out;
rv = deflate(&zst, Z_FINISH);
deflateEnd(&zst);
if (rv != Z_STREAM_END) {
return -1;
}
temp_outlen -= zst.avail_out;
if (temp_outlen > outlen) {
return -1;
}
memcpy(out, temp_out, temp_outlen);
return temp_outlen;
}
} // namespace nghttp2 } // namespace nghttp2

View File

@@ -90,9 +90,6 @@ void set_color_output(bool f);
// used. // used.
void set_output(FILE *file); void set_output(FILE *file);
ssize_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in,
size_t inlen);
} // namespace nghttp2 } // namespace nghttp2
#endif // APP_HELPER_H #endif // APP_HELPER_H

View File

@@ -27,7 +27,7 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <CUnit/CUnit.h> #include "munitxx.h"
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
@@ -35,26 +35,38 @@
namespace nghttp2 { namespace nghttp2 {
namespace {
const MunitTest tests[]{
munit_void_test(test_base64_encode),
munit_void_test(test_base64_decode),
munit_test_end(),
};
} // namespace
const MunitSuite base64_suite{
"/base64", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
};
void test_base64_encode(void) { void test_base64_encode(void) {
{ {
std::string in = "\xff"; std::string in = "\xff";
auto out = base64::encode(std::begin(in), std::end(in)); auto out = base64::encode(std::begin(in), std::end(in));
CU_ASSERT("/w==" == out); assert_stdstring_equal("/w==", out);
} }
{ {
std::string in = "\xff\xfe"; std::string in = "\xff\xfe";
auto out = base64::encode(std::begin(in), std::end(in)); auto out = base64::encode(std::begin(in), std::end(in));
CU_ASSERT("//4=" == out); assert_stdstring_equal("//4=", out);
} }
{ {
std::string in = "\xff\xfe\xfd"; std::string in = "\xff\xfe\xfd";
auto out = base64::encode(std::begin(in), std::end(in)); auto out = base64::encode(std::begin(in), std::end(in));
CU_ASSERT("//79" == out); assert_stdstring_equal("//79", out);
} }
{ {
std::string in = "\xff\xfe\xfd\xfc"; std::string in = "\xff\xfe\xfd\xfc";
auto out = base64::encode(std::begin(in), std::end(in)); auto out = base64::encode(std::begin(in), std::end(in));
CU_ASSERT("//79/A==" == out); assert_stdstring_equal("//79/A==", out);
} }
} }
@@ -63,58 +75,65 @@ void test_base64_decode(void) {
{ {
std::string in = "/w=="; std::string in = "/w==";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff" == out); assert_stdstring_equal("\xff", out);
CU_ASSERT("\xff" == base64::decode(balloc, std::begin(in), std::end(in))); assert_stdstring_equal(
"\xff", base64::decode(balloc, std::begin(in), std::end(in)).str());
} }
{ {
std::string in = "//4="; std::string in = "//4=";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe" == out); assert_stdstring_equal("\xff\xfe", out);
CU_ASSERT("\xff\xfe" == assert_stdstring_equal(
base64::decode(balloc, std::begin(in), std::end(in))); "\xff\xfe", base64::decode(balloc, std::begin(in), std::end(in)).str());
} }
{ {
std::string in = "//79"; std::string in = "//79";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe\xfd" == out); assert_stdstring_equal("\xff\xfe\xfd", out);
CU_ASSERT("\xff\xfe\xfd" == assert_stdstring_equal(
base64::decode(balloc, std::begin(in), std::end(in))); "\xff\xfe\xfd",
base64::decode(balloc, std::begin(in), std::end(in)).str());
} }
{ {
std::string in = "//79/A=="; std::string in = "//79/A==";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe\xfd\xfc" == out); assert_stdstring_equal("\xff\xfe\xfd\xfc", out);
CU_ASSERT("\xff\xfe\xfd\xfc" == assert_stdstring_equal(
base64::decode(balloc, std::begin(in), std::end(in))); "\xff\xfe\xfd\xfc",
base64::decode(balloc, std::begin(in), std::end(in)).str());
} }
{ {
// we check the number of valid input must be multiples of 4 // we check the number of valid input must be multiples of 4
std::string in = "//79="; std::string in = "//79=";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out); assert_stdstring_equal("", out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); assert_stdstring_equal(
"", base64::decode(balloc, std::begin(in), std::end(in)).str());
} }
{ {
// ending invalid character at the boundary of multiples of 4 is // ending invalid character at the boundary of multiples of 4 is
// bad // bad
std::string in = "bmdodHRw\n"; std::string in = "bmdodHRw\n";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out); assert_stdstring_equal("", out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); assert_stdstring_equal(
"", base64::decode(balloc, std::begin(in), std::end(in)).str());
} }
{ {
// after seeing '=', subsequent input must be also '='. // after seeing '=', subsequent input must be also '='.
std::string in = "//79/A=A"; std::string in = "//79/A=A";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out); assert_stdstring_equal("", out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); assert_stdstring_equal(
"", base64::decode(balloc, std::begin(in), std::end(in)).str());
} }
{ {
// additional '=' at the end is bad // additional '=' at the end is bad
std::string in = "//79/A======"; std::string in = "//79/A======";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out); assert_stdstring_equal("", out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); assert_stdstring_equal(
"", base64::decode(balloc, std::begin(in), std::end(in)).str());
} }
} }

View File

@@ -29,10 +29,16 @@
# include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
#define MUNIT_ENABLE_ASSERT_ALIASES
#include "munit.h"
namespace nghttp2 { namespace nghttp2 {
void test_base64_encode(void); extern const MunitSuite base64_suite;
void test_base64_decode(void);
munit_void_test_decl(test_base64_encode);
munit_void_test_decl(test_base64_decode);
} // namespace nghttp2 } // namespace nghttp2

View File

@@ -28,7 +28,7 @@
#include <iostream> #include <iostream>
#include <tuple> #include <tuple>
#include <CUnit/CUnit.h> #include "munitxx.h"
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
@@ -36,43 +36,54 @@
namespace nghttp2 { namespace nghttp2 {
namespace {
const MunitTest tests[]{
munit_void_test(test_buffer_write),
munit_test_end(),
};
} // namespace
const MunitSuite buffer_suite{
"/buffer", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
};
void test_buffer_write(void) { void test_buffer_write(void) {
Buffer<16> b; Buffer<16> b;
CU_ASSERT(0 == b.rleft()); assert_size(0, ==, b.rleft());
CU_ASSERT(16 == b.wleft()); assert_size(16, ==, b.wleft());
b.write("012", 3); b.write("012", 3);
CU_ASSERT(3 == b.rleft()); assert_size(3, ==, b.rleft());
CU_ASSERT(13 == b.wleft()); assert_size(13, ==, b.wleft());
CU_ASSERT(b.pos == std::begin(b.buf)); assert_ptr_equal(b.pos, std::begin(b.buf));
b.drain(3); b.drain(3);
CU_ASSERT(0 == b.rleft()); assert_size(0, ==, b.rleft());
CU_ASSERT(13 == b.wleft()); assert_size(13, ==, b.wleft());
CU_ASSERT(3 == b.pos - std::begin(b.buf)); assert_ptrdiff(3, ==, b.pos - std::begin(b.buf));
auto n = b.write("0123456789ABCDEF", 16); auto n = b.write("0123456789ABCDEF", 16);
CU_ASSERT(n == 13); assert_ssize(13, ==, n);
CU_ASSERT(13 == b.rleft()); assert_size(13, ==, b.rleft());
CU_ASSERT(0 == b.wleft()); assert_size(0, ==, b.wleft());
CU_ASSERT(3 == b.pos - std::begin(b.buf)); assert_ptrdiff(3, ==, b.pos - std::begin(b.buf));
CU_ASSERT(0 == memcmp(b.pos, "0123456789ABC", 13)); assert_memory_equal(13, b.pos, "0123456789ABC");
b.reset(); b.reset();
CU_ASSERT(0 == b.rleft()); assert_size(0, ==, b.rleft());
CU_ASSERT(16 == b.wleft()); assert_size(16, ==, b.wleft());
CU_ASSERT(b.pos == std::begin(b.buf)); assert_ptr_equal(b.pos, std::begin(b.buf));
b.write(5); b.write(5);
CU_ASSERT(5 == b.rleft()); assert_size(5, ==, b.rleft());
CU_ASSERT(11 == b.wleft()); assert_size(11, ==, b.wleft());
CU_ASSERT(b.pos == std::begin(b.buf)); assert_ptr_equal(b.pos, std::begin(b.buf));
} }
} // namespace nghttp2 } // namespace nghttp2

View File

@@ -29,9 +29,15 @@
# include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
#define MUNIT_ENABLE_ASSERT_ALIASES
#include "munit.h"
namespace nghttp2 { namespace nghttp2 {
void test_buffer_write(void); extern const MunitSuite buffer_suite;
munit_void_test_decl(test_buffer_write);
} // namespace nghttp2 } // namespace nghttp2

View File

@@ -41,6 +41,7 @@
#include <jansson.h> #include <jansson.h>
#define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include "template.h" #include "template.h"
@@ -113,11 +114,10 @@ static void output_to_json(nghttp2_hd_deflater *deflater, const uint8_t *buf,
static void deflate_hd(nghttp2_hd_deflater *deflater, static void deflate_hd(nghttp2_hd_deflater *deflater,
const std::vector<nghttp2_nv> &nva, size_t inputlen, const std::vector<nghttp2_nv> &nva, size_t inputlen,
int seq) { int seq) {
ssize_t rv;
std::array<uint8_t, 64_k> buf; std::array<uint8_t, 64_k> buf;
rv = nghttp2_hd_deflate_hd(deflater, buf.data(), buf.size(), auto rv = nghttp2_hd_deflate_hd2(deflater, buf.data(), buf.size(),
(nghttp2_nv *)nva.data(), nva.size()); (nghttp2_nv *)nva.data(), nva.size());
if (rv < 0) { if (rv < 0) {
fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq); fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@@ -410,7 +410,7 @@ namespace {
void client_request_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) { void client_request_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
auto client = static_cast<Client *>(w->data); auto client = static_cast<Client *>(w->data);
if (client->streams.size() >= (size_t)config.max_concurrent_streams) { if (client->streams.size() >= config.max_concurrent_streams) {
ev_timer_stop(client->worker->loop, w); ev_timer_stop(client->worker->loop, w);
return; return;
} }
@@ -582,8 +582,12 @@ int Client::make_socket(addrinfo *addr) {
} }
} }
if (ssl && !util::numeric_host(config.host.c_str())) { if (ssl) {
SSL_set_tlsext_host_name(ssl, config.host.c_str()); if (!config.sni.empty()) {
SSL_set_tlsext_host_name(ssl, config.sni.c_str());
} else if (!util::numeric_host(config.host.c_str())) {
SSL_set_tlsext_host_name(ssl, config.host.c_str());
}
} }
if (config.is_quic()) { if (config.is_quic()) {
@@ -2301,6 +2305,9 @@ Options:
--max-udp-payload-size=<SIZE> --max-udp-payload-size=<SIZE>
Specify the maximum outgoing UDP datagram payload size. Specify the maximum outgoing UDP datagram payload size.
--ktls Enable ktls. --ktls Enable ktls.
--sni=<DNSNAME>
Send <DNSNAME> in TLS SNI, overriding the host name
specified in URI.
-v, --verbose -v, --verbose
Output debug information. Output debug information.
--version Display version information and exit. --version Display version information and exit.
@@ -2363,6 +2370,7 @@ int main(int argc, char **argv) {
{"max-udp-payload-size", required_argument, &flag, 17}, {"max-udp-payload-size", required_argument, &flag, 17},
{"ktls", no_argument, &flag, 18}, {"ktls", no_argument, &flag, 18},
{"alpn-list", required_argument, &flag, 19}, {"alpn-list", required_argument, &flag, 19},
{"sni", required_argument, &flag, 20},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int option_index = 0; int option_index = 0;
auto c = getopt_long(argc, argv, auto c = getopt_long(argc, argv,
@@ -2699,6 +2707,10 @@ int main(int argc, char **argv) {
// alpn-list option // alpn-list option
config.alpn_list = util::parse_config_str_list(StringRef{optarg}); config.alpn_list = util::parse_config_str_list(StringRef{optarg});
break; break;
case 20:
// --sni
config.sni = optarg;
break;
} }
break; break;
default: default:
@@ -2973,6 +2985,15 @@ int main(int argc, char **argv) {
} }
} }
#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI)
if (!SSL_CTX_add_cert_compression_alg(
ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI,
nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) {
std::cerr << "SSL_CTX_add_cert_compression_alg failed" << std::endl;
exit(EXIT_FAILURE);
}
#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI
std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION; std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION;
Headers shared_nva; Headers shared_nva;
shared_nva.emplace_back(":scheme", config.scheme); shared_nva.emplace_back(":scheme", config.scheme);
@@ -3079,18 +3100,18 @@ int main(int argc, char **argv) {
#ifndef NOTHREADS #ifndef NOTHREADS
size_t nreqs_per_thread = 0; size_t nreqs_per_thread = 0;
ssize_t nreqs_rem = 0; size_t nreqs_rem = 0;
if (!config.timing_script) { if (!config.timing_script) {
nreqs_per_thread = config.nreqs / config.nthreads; nreqs_per_thread = config.nreqs / config.nthreads;
nreqs_rem = config.nreqs % config.nthreads; nreqs_rem = config.nreqs % config.nthreads;
} }
size_t nclients_per_thread = config.nclients / config.nthreads; auto nclients_per_thread = config.nclients / config.nthreads;
ssize_t nclients_rem = config.nclients % config.nthreads; auto nclients_rem = config.nclients % config.nthreads;
size_t rate_per_thread = config.rate / config.nthreads; auto rate_per_thread = config.rate / config.nthreads;
ssize_t rate_per_thread_rem = config.rate % config.nthreads; auto rate_per_thread_rem = config.rate % config.nthreads;
size_t max_samples_per_thread = size_t max_samples_per_thread =
std::max(static_cast<size_t>(256), MAX_SAMPLES / config.nthreads); std::max(static_cast<size_t>(256), MAX_SAMPLES / config.nthreads);

View File

@@ -43,6 +43,7 @@
#include <chrono> #include <chrono>
#include <array> #include <array>
#define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#ifdef ENABLE_HTTP3 #ifdef ENABLE_HTTP3
@@ -92,7 +93,7 @@ struct Config {
size_t nclients; size_t nclients;
size_t nthreads; size_t nthreads;
// The maximum number of concurrent streams per session. // The maximum number of concurrent streams per session.
ssize_t max_concurrent_streams; size_t max_concurrent_streams;
size_t window_bits; size_t window_bits;
size_t connection_window_bits; size_t connection_window_bits;
size_t max_frame_size; size_t max_frame_size;
@@ -138,6 +139,9 @@ struct Config {
size_t max_udp_payload_size; size_t max_udp_payload_size;
// Enable ktls. // Enable ktls.
bool ktls; bool ktls;
// sni is the value sent in TLS SNI, overriding DNS name of the
// remote host.
std::string sni;
Config(); Config();
~Config(); ~Config();

View File

@@ -124,9 +124,10 @@ int before_frame_send_callback(nghttp2_session *session,
} // namespace } // namespace
namespace { namespace {
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, nghttp2_ssize file_read_callback(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length, uint32_t *data_flags, uint8_t *buf, size_t length,
nghttp2_data_source *source, void *user_data) { uint32_t *data_flags,
nghttp2_data_source *source, void *user_data) {
auto client = static_cast<Client *>(user_data); auto client = static_cast<Client *>(user_data);
auto config = client->worker->config; auto config = client->worker->config;
auto req_stat = client->get_req_stat(stream_id); auto req_stat = client->get_req_stat(stream_id);
@@ -158,8 +159,8 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
} // namespace } // namespace
namespace { namespace {
ssize_t send_callback(nghttp2_session *session, const uint8_t *data, nghttp2_ssize send_callback(nghttp2_session *session, const uint8_t *data,
size_t length, int flags, void *user_data) { size_t length, int flags, void *user_data) {
auto client = static_cast<Client *>(user_data); auto client = static_cast<Client *>(user_data);
auto &wb = client->wb; auto &wb = client->wb;
@@ -198,7 +199,7 @@ void Http2Session::on_connect() {
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_send_callback(callbacks, send_callback); nghttp2_session_callbacks_set_send_callback2(callbacks, send_callback);
nghttp2_option *opt; nghttp2_option *opt;
@@ -257,11 +258,11 @@ int Http2Session::submit_request() {
client_->reqidx = 0; client_->reqidx = 0;
} }
nghttp2_data_provider prd{{0}, file_read_callback}; nghttp2_data_provider2 prd{{0}, file_read_callback};
auto stream_id = auto stream_id =
nghttp2_submit_request(session_, nullptr, nva.data(), nva.size(), nghttp2_submit_request2(session_, nullptr, nva.data(), nva.size(),
config->data_fd == -1 ? nullptr : &prd, nullptr); config->data_fd == -1 ? nullptr : &prd, nullptr);
if (stream_id < 0) { if (stream_id < 0) {
return -1; return -1;
} }
@@ -272,7 +273,7 @@ int Http2Session::submit_request() {
} }
int Http2Session::on_read(const uint8_t *data, size_t len) { int Http2Session::on_read(const uint8_t *data, size_t len) {
auto rv = nghttp2_session_mem_recv(session_, data, len); auto rv = nghttp2_session_mem_recv2(session_, data, len);
if (rv < 0) { if (rv < 0) {
return -1; return -1;
} }
@@ -308,7 +309,7 @@ void Http2Session::terminate() {
} }
size_t Http2Session::max_concurrent_streams() { size_t Http2Session::max_concurrent_streams() {
return (size_t)client_->worker->config->max_concurrent_streams; return client_->worker->config->max_concurrent_streams;
} }
} // namespace h2load } // namespace h2load

View File

@@ -124,7 +124,7 @@ int Http3Session::on_write() { return -1; }
void Http3Session::terminate() {} void Http3Session::terminate() {}
size_t Http3Session::max_concurrent_streams() { size_t Http3Session::max_concurrent_streams() {
return (size_t)client_->worker->config->max_concurrent_streams; return client_->worker->config->max_concurrent_streams;
} }
namespace { namespace {

View File

@@ -654,7 +654,8 @@ int Client::write_quic() {
ngtcp2_conn_get_path_max_tx_udp_payload_size(quic.conn); ngtcp2_conn_get_path_max_tx_udp_payload_size(quic.conn);
#endif // UDP_SEGMENT #endif // UDP_SEGMENT
auto max_pktcnt = auto max_pktcnt =
ngtcp2_conn_get_send_quantum(quic.conn) / max_udp_payload_size; std::max(ngtcp2_conn_get_send_quantum(quic.conn) / max_udp_payload_size,
static_cast<size_t>(1));
uint8_t *bufpos = quic.tx.data.get(); uint8_t *bufpos = quic.tx.data.get();
ngtcp2_path_storage ps; ngtcp2_path_storage ps;
size_t gso_size = 0; size_t gso_size = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -29,25 +29,31 @@
# include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
#define MUNIT_ENABLE_ASSERT_ALIASES
#include "munit.h"
namespace shrpx { namespace shrpx {
void test_http2_add_header(void); extern const MunitSuite http2_suite;
void test_http2_get_header(void);
void test_http2_copy_headers_to_nva(void); munit_void_test_decl(test_http2_add_header);
void test_http2_build_http1_headers_from_headers(void); munit_void_test_decl(test_http2_get_header);
void test_http2_lws(void); munit_void_test_decl(test_http2_copy_headers_to_nva);
void test_http2_rewrite_location_uri(void); munit_void_test_decl(test_http2_build_http1_headers_from_headers);
void test_http2_parse_http_status_code(void); munit_void_test_decl(test_http2_lws);
void test_http2_index_header(void); munit_void_test_decl(test_http2_rewrite_location_uri);
void test_http2_lookup_token(void); munit_void_test_decl(test_http2_parse_http_status_code);
void test_http2_parse_link_header(void); munit_void_test_decl(test_http2_index_header);
void test_http2_path_join(void); munit_void_test_decl(test_http2_lookup_token);
void test_http2_normalize_path(void); munit_void_test_decl(test_http2_parse_link_header);
void test_http2_rewrite_clean_path(void); munit_void_test_decl(test_http2_path_join);
void test_http2_get_pure_path_component(void); munit_void_test_decl(test_http2_normalize_path);
void test_http2_construct_push_component(void); munit_void_test_decl(test_http2_rewrite_clean_path);
void test_http2_contains_trailers(void); munit_void_test_decl(test_http2_get_pure_path_component);
void test_http2_check_transfer_encoding(void); munit_void_test_decl(test_http2_construct_push_component);
munit_void_test_decl(test_http2_contains_trailers);
munit_void_test_decl(test_http2_check_transfer_encoding);
} // namespace shrpx } // namespace shrpx

View File

@@ -41,6 +41,7 @@
#include <jansson.h> #include <jansson.h>
#define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include "template.h" #include "template.h"
@@ -93,7 +94,6 @@ static void to_json(nghttp2_hd_inflater *inflater, json_t *headers,
} }
static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) { static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) {
ssize_t rv;
nghttp2_nv nv; nghttp2_nv nv;
int inflate_flags; int inflate_flags;
size_t old_settings_table_size = size_t old_settings_table_size =
@@ -120,8 +120,8 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) {
seq); seq);
return -1; return -1;
} }
rv = nghttp2_hd_inflate_change_table_size(inflater, auto rv = nghttp2_hd_inflate_change_table_size(
json_integer_value(table_size)); inflater, json_integer_value(table_size));
if (rv != 0) { if (rv != 0) {
fprintf(stderr, fprintf(stderr,
"nghttp2_hd_change_table_size() failed with error %s at %d\n", "nghttp2_hd_change_table_size() failed with error %s at %d\n",
@@ -147,7 +147,8 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) {
auto p = buf.data(); auto p = buf.data();
for (;;) { for (;;) {
inflate_flags = 0; inflate_flags = 0;
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, p, buflen, 1); auto rv =
nghttp2_hd_inflate_hd3(inflater, &nv, &inflate_flags, p, buflen, 1);
if (rv < 0) { if (rv < 0) {
fprintf(stderr, "inflate failed with error code %zd at %d\n", rv, seq); fprintf(stderr, "inflate failed with error code %zd at %d\n", rv, seq);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@@ -1,162 +0,0 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libevent_util.h"
#include <cstring>
#include <algorithm>
namespace nghttp2 {
namespace util {
EvbufferBuffer::EvbufferBuffer()
: evbuffer_(nullptr),
bucket_(nullptr),
buf_(nullptr),
bufmax_(0),
buflen_(0),
limit_(0),
writelen_(0) {}
EvbufferBuffer::EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
ssize_t limit)
: evbuffer_(evbuffer),
bucket_(limit == -1 ? nullptr : evbuffer_new()),
buf_(buf),
bufmax_(bufmax),
buflen_(0),
limit_(limit),
writelen_(0) {}
void EvbufferBuffer::reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
ssize_t limit) {
evbuffer_ = evbuffer;
buf_ = buf;
if (limit != -1 && !bucket_) {
bucket_ = evbuffer_new();
}
bufmax_ = bufmax;
buflen_ = 0;
limit_ = limit;
writelen_ = 0;
}
EvbufferBuffer::~EvbufferBuffer() {
if (bucket_) {
evbuffer_free(bucket_);
}
}
int EvbufferBuffer::write_buffer() {
for (auto pos = buf_, end = buf_ + buflen_; pos < end;) {
// To avoid merging chunks in evbuffer, we first add to temporal
// buffer bucket_ and then move its chain to evbuffer_.
auto nwrite = std::min(end - pos, limit_);
auto rv = evbuffer_add(bucket_, pos, nwrite);
if (rv == -1) {
return -1;
}
rv = evbuffer_add_buffer(evbuffer_, bucket_);
if (rv == -1) {
return -1;
}
pos += nwrite;
}
return 0;
}
int EvbufferBuffer::flush() {
int rv;
if (buflen_ > 0) {
if (limit_ == -1) {
rv = evbuffer_add(evbuffer_, buf_, buflen_);
} else {
rv = write_buffer();
}
if (rv == -1) {
return -1;
}
writelen_ += buflen_;
buflen_ = 0;
}
return 0;
}
int EvbufferBuffer::add(const uint8_t *data, size_t datalen) {
int rv;
if (buflen_ + datalen > bufmax_) {
if (buflen_ > 0) {
if (limit_ == -1) {
rv = evbuffer_add(evbuffer_, buf_, buflen_);
} else {
rv = write_buffer();
}
if (rv == -1) {
return -1;
}
writelen_ += buflen_;
buflen_ = 0;
}
if (datalen > bufmax_) {
if (limit_ == -1) {
rv = evbuffer_add(evbuffer_, data, datalen);
} else {
rv = write_buffer();
}
if (rv == -1) {
return -1;
}
writelen_ += buflen_;
return 0;
}
}
memcpy(buf_ + buflen_, data, datalen);
buflen_ += datalen;
return 0;
}
size_t EvbufferBuffer::get_buflen() const { return buflen_; }
size_t EvbufferBuffer::get_writelen() const { return writelen_; }
void bev_enable_unless(bufferevent *bev, int events) {
if ((bufferevent_get_enabled(bev) & events) == events) {
return;
}
bufferevent_enable(bev, events);
}
void bev_disable_unless(bufferevent *bev, int events) {
if ((bufferevent_get_enabled(bev) & events) == 0) {
return;
}
bufferevent_disable(bev, events);
}
} // namespace util
} // namespace nghttp2

View File

@@ -1,75 +0,0 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LIBEVENT_UTIL_H
#define LIBEVENT_UTIL_H
#include "nghttp2_config.h"
#include <event2/buffer.h>
#include <event2/bufferevent.h>
namespace nghttp2 {
namespace util {
class EvbufferBuffer {
public:
EvbufferBuffer();
// If |limit| is not -1, at most min(limit, bufmax) size bytes are
// added to evbuffer_.
EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
ssize_t limit = -1);
~EvbufferBuffer();
void reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
ssize_t limit = -1);
int flush();
int add(const uint8_t *data, size_t datalen);
size_t get_buflen() const;
int write_buffer();
// Returns the number of written bytes to evbuffer_ so far. reset()
// resets this value to 0.
size_t get_writelen() const;
private:
evbuffer *evbuffer_;
evbuffer *bucket_;
uint8_t *buf_;
size_t bufmax_;
size_t buflen_;
ssize_t limit_;
size_t writelen_;
};
// These functions are provided to reduce epoll_ctl syscall. Avoid
// calling bufferevent_enable/disable() unless it is required by
// sniffing current enabled events.
void bev_enable_unless(bufferevent *bev, int events);
void bev_disable_unless(bufferevent *bev, int events);
} // namespace util
} // namespace nghttp2
#endif // LIBEVENT_UTIL_H

View File

@@ -24,7 +24,7 @@
*/ */
#include "memchunk_test.h" #include "memchunk_test.h"
#include <CUnit/CUnit.h> #include "munitxx.h"
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
@@ -33,52 +33,72 @@
namespace nghttp2 { namespace nghttp2 {
namespace {
const MunitTest tests[]{
munit_void_test(test_pool_recycle),
munit_void_test(test_memchunks_append),
munit_void_test(test_memchunks_drain),
munit_void_test(test_memchunks_riovec),
munit_void_test(test_memchunks_recycle),
munit_void_test(test_memchunks_reset),
munit_void_test(test_peek_memchunks_append),
munit_void_test(test_peek_memchunks_disable_peek_drain),
munit_void_test(test_peek_memchunks_disable_peek_no_drain),
munit_void_test(test_peek_memchunks_reset),
munit_test_end(),
};
} // namespace
const MunitSuite memchunk_suite{
"/memchunk", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
};
void test_pool_recycle(void) { void test_pool_recycle(void) {
MemchunkPool pool; MemchunkPool pool;
CU_ASSERT(!pool.pool); assert_null(pool.pool);
CU_ASSERT(0 == pool.poolsize); assert_size(0, ==, pool.poolsize);
CU_ASSERT(nullptr == pool.freelist); assert_null(pool.freelist);
auto m1 = pool.get(); auto m1 = pool.get();
CU_ASSERT(m1 == pool.pool); assert_ptr_equal(m1, pool.pool);
CU_ASSERT(MemchunkPool::value_type::size == pool.poolsize); assert_size(MemchunkPool::value_type::size, ==, pool.poolsize);
CU_ASSERT(nullptr == pool.freelist); assert_null(pool.freelist);
auto m2 = pool.get(); auto m2 = pool.get();
CU_ASSERT(m2 == pool.pool); assert_ptr_equal(m2, pool.pool);
CU_ASSERT(2 * MemchunkPool::value_type::size == pool.poolsize); assert_size(2 * MemchunkPool::value_type::size, ==, pool.poolsize);
CU_ASSERT(nullptr == pool.freelist); assert_null(pool.freelist);
CU_ASSERT(m1 == m2->knext); assert_ptr_equal(m1, m2->knext);
CU_ASSERT(nullptr == m1->knext); assert_null(m1->knext);
auto m3 = pool.get(); auto m3 = pool.get();
CU_ASSERT(m3 == pool.pool); assert_ptr_equal(m3, pool.pool);
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize); assert_size(3 * MemchunkPool::value_type::size, ==, pool.poolsize);
CU_ASSERT(nullptr == pool.freelist); assert_null(pool.freelist);
pool.recycle(m3); pool.recycle(m3);
CU_ASSERT(m3 == pool.pool); assert_ptr_equal(m3, pool.pool);
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize); assert_size(3 * MemchunkPool::value_type::size, ==, pool.poolsize);
CU_ASSERT(m3 == pool.freelist); assert_ptr_equal(m3, pool.freelist);
auto m4 = pool.get(); auto m4 = pool.get();
CU_ASSERT(m3 == m4); assert_ptr_equal(m3, m4);
CU_ASSERT(m4 == pool.pool); assert_ptr_equal(m4, pool.pool);
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize); assert_size(3 * MemchunkPool::value_type::size, ==, pool.poolsize);
CU_ASSERT(nullptr == pool.freelist); assert_null(pool.freelist);
pool.recycle(m2); pool.recycle(m2);
pool.recycle(m1); pool.recycle(m1);
CU_ASSERT(m1 == pool.freelist); assert_ptr_equal(m1, pool.freelist);
CU_ASSERT(m2 == m1->next); assert_ptr_equal(m2, m1->next);
CU_ASSERT(nullptr == m2->next); assert_null(m2->next);
} }
using Memchunk16 = Memchunk<16>; using Memchunk16 = Memchunk<16>;
@@ -94,37 +114,37 @@ void test_memchunks_append(void) {
auto m = chunks.tail; auto m = chunks.tail;
CU_ASSERT(3 == m->len()); assert_size(3, ==, m->len());
CU_ASSERT(13 == m->left()); assert_size(13, ==, m->left());
chunks.append("3456789abcdef@"); chunks.append("3456789abcdef@");
CU_ASSERT(16 == m->len()); assert_size(16, ==, m->len());
CU_ASSERT(0 == m->left()); assert_size(0, ==, m->left());
m = chunks.tail; m = chunks.tail;
CU_ASSERT(1 == m->len()); assert_size(1, ==, m->len());
CU_ASSERT(15 == m->left()); assert_size(15, ==, m->left());
CU_ASSERT(17 == chunks.rleft()); assert_size(17, ==, chunks.rleft());
char buf[16]; char buf[16];
size_t nread; size_t nread;
nread = chunks.remove(buf, 8); nread = chunks.remove(buf, 8);
CU_ASSERT(8 == nread); assert_size(8, ==, nread);
CU_ASSERT(0 == memcmp("01234567", buf, nread)); assert_memory_equal(nread, "01234567", buf);
CU_ASSERT(9 == chunks.rleft()); assert_size(9, ==, chunks.rleft());
nread = chunks.remove(buf, sizeof(buf)); nread = chunks.remove(buf, sizeof(buf));
CU_ASSERT(9 == nread); assert_size(9, ==, nread);
CU_ASSERT(0 == memcmp("89abcdef@", buf, nread)); assert_memory_equal(nread, "89abcdef@", buf);
CU_ASSERT(0 == chunks.rleft()); assert_size(0, ==, chunks.rleft());
CU_ASSERT(nullptr == chunks.head); assert_null(chunks.head);
CU_ASSERT(nullptr == chunks.tail); assert_null(chunks.tail);
CU_ASSERT(32 == pool.poolsize); assert_size(32, ==, pool.poolsize);
} }
void test_memchunks_drain(void) { void test_memchunks_drain(void) {
@@ -137,14 +157,14 @@ void test_memchunks_drain(void) {
nread = chunks.drain(3); nread = chunks.drain(3);
CU_ASSERT(3 == nread); assert_size(3, ==, nread);
char buf[16]; char buf[16];
nread = chunks.remove(buf, sizeof(buf)); nread = chunks.remove(buf, sizeof(buf));
CU_ASSERT(7 == nread); assert_size(7, ==, nread);
CU_ASSERT(0 == memcmp("3456789", buf, nread)); assert_memory_equal(nread, "3456789", buf);
} }
void test_memchunks_riovec(void) { void test_memchunks_riovec(void) {
@@ -160,24 +180,24 @@ void test_memchunks_riovec(void) {
auto m = chunks.head; auto m = chunks.head;
CU_ASSERT(2 == iovcnt); assert_int(2, ==, iovcnt);
CU_ASSERT(m->buf.data() == iov[0].iov_base); assert_ptr_equal(m->buf.data(), iov[0].iov_base);
CU_ASSERT(m->len() == iov[0].iov_len); assert_size(m->len(), ==, iov[0].iov_len);
m = m->next; m = m->next;
CU_ASSERT(m->buf.data() == iov[1].iov_base); assert_ptr_equal(m->buf.data(), iov[1].iov_base);
CU_ASSERT(m->len() == iov[1].iov_len); assert_size(m->len(), ==, iov[1].iov_len);
chunks.drain(2 * 16); chunks.drain(2 * 16);
iovcnt = chunks.riovec(iov.data(), iov.size()); iovcnt = chunks.riovec(iov.data(), iov.size());
CU_ASSERT(1 == iovcnt); assert_int(1, ==, iovcnt);
m = chunks.head; m = chunks.head;
CU_ASSERT(m->buf.data() == iov[0].iov_base); assert_ptr_equal(m->buf.data(), iov[0].iov_base);
CU_ASSERT(m->len() == iov[0].iov_len); assert_size(m->len(), ==, iov[0].iov_len);
} }
void test_memchunks_recycle(void) { void test_memchunks_recycle(void) {
@@ -187,14 +207,14 @@ void test_memchunks_recycle(void) {
std::array<char, 32> buf{}; std::array<char, 32> buf{};
chunks.append(buf.data(), buf.size()); chunks.append(buf.data(), buf.size());
} }
CU_ASSERT(32 == pool.poolsize); assert_size(32, ==, pool.poolsize);
CU_ASSERT(nullptr != pool.freelist); assert_not_null(pool.freelist);
auto m = pool.freelist; auto m = pool.freelist;
m = m->next; m = m->next;
CU_ASSERT(nullptr != m); assert_not_null(m);
CU_ASSERT(nullptr == m->next); assert_null(m->next);
} }
void test_memchunks_reset(void) { void test_memchunks_reset(void) {
@@ -205,19 +225,19 @@ void test_memchunks_reset(void) {
chunks.append(b.data(), b.size()); chunks.append(b.data(), b.size());
CU_ASSERT(32 == chunks.rleft()); assert_size(32, ==, chunks.rleft());
chunks.reset(); chunks.reset();
CU_ASSERT(0 == chunks.rleft()); assert_size(0, ==, chunks.rleft());
CU_ASSERT(nullptr == chunks.head); assert_null(chunks.head);
CU_ASSERT(nullptr == chunks.tail); assert_null(chunks.tail);
auto m = pool.freelist; auto m = pool.freelist;
CU_ASSERT(nullptr != m); assert_not_null(m);
CU_ASSERT(nullptr != m->next); assert_not_null(m->next);
CU_ASSERT(nullptr == m->next->next); assert_null(m->next->next);
} }
void test_peek_memchunks_append(void) { void test_peek_memchunks_append(void) {
@@ -232,27 +252,27 @@ void test_peek_memchunks_append(void) {
pchunks.append(b.data(), b.size()); pchunks.append(b.data(), b.size());
CU_ASSERT(32 == pchunks.rleft()); assert_size(32, ==, pchunks.rleft());
CU_ASSERT(32 == pchunks.rleft_buffered()); assert_size(32, ==, pchunks.rleft_buffered());
CU_ASSERT(0 == pchunks.remove(nullptr, 0)); assert_size(0, ==, pchunks.remove(nullptr, 0));
CU_ASSERT(32 == pchunks.rleft()); assert_size(32, ==, pchunks.rleft());
CU_ASSERT(32 == pchunks.rleft_buffered()); assert_size(32, ==, pchunks.rleft_buffered());
CU_ASSERT(12 == pchunks.remove(d.data(), 12)); assert_size(12, ==, pchunks.remove(d.data(), 12));
CU_ASSERT(std::equal(std::begin(b), std::begin(b) + 12, std::begin(d))); assert_true(std::equal(std::begin(b), std::begin(b) + 12, std::begin(d)));
CU_ASSERT(20 == pchunks.rleft()); assert_size(20, ==, pchunks.rleft());
CU_ASSERT(32 == pchunks.rleft_buffered()); assert_size(32, ==, pchunks.rleft_buffered());
CU_ASSERT(20 == pchunks.remove(d.data(), d.size())); assert_size(20, ==, pchunks.remove(d.data(), d.size()));
CU_ASSERT(std::equal(std::begin(b) + 12, std::end(b), std::begin(d))); assert_true(std::equal(std::begin(b) + 12, std::end(b), std::begin(d)));
CU_ASSERT(0 == pchunks.rleft()); assert_size(0, ==, pchunks.rleft());
CU_ASSERT(32 == pchunks.rleft_buffered()); assert_size(32, ==, pchunks.rleft_buffered());
} }
void test_peek_memchunks_disable_peek_drain(void) { void test_peek_memchunks_disable_peek_drain(void) {
@@ -267,20 +287,20 @@ void test_peek_memchunks_disable_peek_drain(void) {
pchunks.append(b.data(), b.size()); pchunks.append(b.data(), b.size());
CU_ASSERT(12 == pchunks.remove(d.data(), 12)); assert_size(12, ==, pchunks.remove(d.data(), 12));
pchunks.disable_peek(true); pchunks.disable_peek(true);
CU_ASSERT(!pchunks.peeking); assert_false(pchunks.peeking);
CU_ASSERT(20 == pchunks.rleft()); assert_size(20, ==, pchunks.rleft());
CU_ASSERT(20 == pchunks.rleft_buffered()); assert_size(20, ==, pchunks.rleft_buffered());
CU_ASSERT(20 == pchunks.remove(d.data(), d.size())); assert_size(20, ==, pchunks.remove(d.data(), d.size()));
CU_ASSERT(std::equal(std::begin(b) + 12, std::end(b), std::begin(d))); assert_true(std::equal(std::begin(b) + 12, std::end(b), std::begin(d)));
CU_ASSERT(0 == pchunks.rleft()); assert_size(0, ==, pchunks.rleft());
CU_ASSERT(0 == pchunks.rleft_buffered()); assert_size(0, ==, pchunks.rleft_buffered());
} }
void test_peek_memchunks_disable_peek_no_drain(void) { void test_peek_memchunks_disable_peek_no_drain(void) {
@@ -295,20 +315,20 @@ void test_peek_memchunks_disable_peek_no_drain(void) {
pchunks.append(b.data(), b.size()); pchunks.append(b.data(), b.size());
CU_ASSERT(12 == pchunks.remove(d.data(), 12)); assert_size(12, ==, pchunks.remove(d.data(), 12));
pchunks.disable_peek(false); pchunks.disable_peek(false);
CU_ASSERT(!pchunks.peeking); assert_false(pchunks.peeking);
CU_ASSERT(32 == pchunks.rleft()); assert_size(32, ==, pchunks.rleft());
CU_ASSERT(32 == pchunks.rleft_buffered()); assert_size(32, ==, pchunks.rleft_buffered());
CU_ASSERT(32 == pchunks.remove(d.data(), d.size())); assert_size(32, ==, pchunks.remove(d.data(), d.size()));
CU_ASSERT(std::equal(std::begin(b), std::end(b), std::begin(d))); assert_true(std::equal(std::begin(b), std::end(b), std::begin(d)));
CU_ASSERT(0 == pchunks.rleft()); assert_size(0, ==, pchunks.rleft());
CU_ASSERT(0 == pchunks.rleft_buffered()); assert_size(0, ==, pchunks.rleft_buffered());
} }
void test_peek_memchunks_reset(void) { void test_peek_memchunks_reset(void) {
@@ -323,18 +343,18 @@ void test_peek_memchunks_reset(void) {
pchunks.append(b.data(), b.size()); pchunks.append(b.data(), b.size());
CU_ASSERT(12 == pchunks.remove(d.data(), 12)); assert_size(12, ==, pchunks.remove(d.data(), 12));
pchunks.disable_peek(true); pchunks.disable_peek(true);
pchunks.reset(); pchunks.reset();
CU_ASSERT(0 == pchunks.rleft()); assert_size(0, ==, pchunks.rleft());
CU_ASSERT(0 == pchunks.rleft_buffered()); assert_size(0, ==, pchunks.rleft_buffered());
CU_ASSERT(nullptr == pchunks.cur); assert_null(pchunks.cur);
CU_ASSERT(nullptr == pchunks.cur_pos); assert_null(pchunks.cur_pos);
CU_ASSERT(nullptr == pchunks.cur_last); assert_null(pchunks.cur_last);
CU_ASSERT(pchunks.peeking); assert_true(pchunks.peeking);
} }
} // namespace nghttp2 } // namespace nghttp2

View File

@@ -29,18 +29,24 @@
# include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
#define MUNIT_ENABLE_ASSERT_ALIASES
#include "munit.h"
namespace nghttp2 { namespace nghttp2 {
void test_pool_recycle(void); extern const MunitSuite memchunk_suite;
void test_memchunks_append(void);
void test_memchunks_drain(void); munit_void_test_decl(test_pool_recycle);
void test_memchunks_riovec(void); munit_void_test_decl(test_memchunks_append);
void test_memchunks_recycle(void); munit_void_test_decl(test_memchunks_drain);
void test_memchunks_reset(void); munit_void_test_decl(test_memchunks_riovec);
void test_peek_memchunks_append(void); munit_void_test_decl(test_memchunks_recycle);
void test_peek_memchunks_disable_peek_drain(void); munit_void_test_decl(test_memchunks_reset);
void test_peek_memchunks_disable_peek_no_drain(void); munit_void_test_decl(test_peek_memchunks_append);
void test_peek_memchunks_reset(void); munit_void_test_decl(test_peek_memchunks_disable_peek_drain);
munit_void_test_decl(test_peek_memchunks_disable_peek_no_drain);
munit_void_test_decl(test_peek_memchunks_reset);
} // namespace nghttp2 } // namespace nghttp2

View File

@@ -157,7 +157,7 @@ std::string strip_fragment(const char *raw_uri) {
} // namespace } // namespace
Request::Request(const std::string &uri, const http_parser_url &u, Request::Request(const std::string &uri, const http_parser_url &u,
const nghttp2_data_provider *data_prd, int64_t data_length, const nghttp2_data_provider2 *data_prd, int64_t data_length,
const nghttp2_priority_spec &pri_spec, int level) const nghttp2_priority_spec &pri_spec, int level)
: uri(uri), : uri(uri),
u(u), u(u),
@@ -370,11 +370,11 @@ void continue_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
auto req = static_cast<Request *>(w->data); auto req = static_cast<Request *>(w->data);
int error; int error;
error = nghttp2_submit_data(client->session, NGHTTP2_FLAG_END_STREAM, error = nghttp2_submit_data2(client->session, NGHTTP2_FLAG_END_STREAM,
req->stream_id, req->data_prd); req->stream_id, req->data_prd);
if (error) { if (error) {
std::cerr << "[ERROR] nghttp2_submit_data() returned error: " std::cerr << "[ERROR] nghttp2_submit_data2() returned error: "
<< nghttp2_strerror(error) << std::endl; << nghttp2_strerror(error) << std::endl;
nghttp2_submit_rst_stream(client->session, NGHTTP2_FLAG_NONE, nghttp2_submit_rst_stream(client->session, NGHTTP2_FLAG_NONE,
req->stream_id, NGHTTP2_INTERNAL_ERROR); req->stream_id, NGHTTP2_INTERNAL_ERROR);
@@ -525,13 +525,13 @@ int submit_request(HttpClient *client, const Headers &headers, Request *req) {
nva.data(), nva.size(), req); nva.data(), nva.size(), req);
} else { } else {
stream_id = stream_id =
nghttp2_submit_request(client->session, &req->pri_spec, nva.data(), nghttp2_submit_request2(client->session, &req->pri_spec, nva.data(),
nva.size(), req->data_prd, req); nva.size(), req->data_prd, req);
} }
if (stream_id < 0) { if (stream_id < 0) {
std::cerr << "[ERROR] nghttp2_submit_" std::cerr << "[ERROR] nghttp2_submit_"
<< (expect_continue ? "headers" : "request") << (expect_continue ? "headers" : "request2")
<< "() returned error: " << nghttp2_strerror(stream_id) << "() returned error: " << nghttp2_strerror(stream_id)
<< std::endl; << std::endl;
return -1; return -1;
@@ -953,14 +953,14 @@ size_t populate_settings(nghttp2_settings_entry *iv) {
} // namespace } // namespace
int HttpClient::on_upgrade_connect() { int HttpClient::on_upgrade_connect() {
ssize_t rv; nghttp2_ssize rv;
record_connect_end_time(); record_connect_end_time();
assert(!reqvec.empty()); assert(!reqvec.empty());
std::array<nghttp2_settings_entry, 16> iv; std::array<nghttp2_settings_entry, 16> iv;
size_t niv = populate_settings(iv.data()); size_t niv = populate_settings(iv.data());
assert(settings_payload.size() >= 8 * niv); assert(settings_payload.size() >= 8 * niv);
rv = nghttp2_pack_settings_payload(settings_payload.data(), rv = nghttp2_pack_settings_payload2(settings_payload.data(),
settings_payload.size(), iv.data(), niv); settings_payload.size(), iv.data(), niv);
if (rv < 0) { if (rv < 0) {
return -1; return -1;
} }
@@ -1250,9 +1250,9 @@ int HttpClient::on_read(const uint8_t *data, size_t len) {
util::hexdump(stdout, data, len); util::hexdump(stdout, data, len);
} }
auto rv = nghttp2_session_mem_recv(session, data, len); auto rv = nghttp2_session_mem_recv2(session, data, len);
if (rv < 0) { if (rv < 0) {
std::cerr << "[ERROR] nghttp2_session_mem_recv() returned error: " std::cerr << "[ERROR] nghttp2_session_mem_recv2() returned error: "
<< nghttp2_strerror(rv) << std::endl; << nghttp2_strerror(rv) << std::endl;
return -1; return -1;
} }
@@ -1276,9 +1276,9 @@ int HttpClient::on_write() {
} }
const uint8_t *data; const uint8_t *data;
auto len = nghttp2_session_mem_send(session, &data); auto len = nghttp2_session_mem_send2(session, &data);
if (len < 0) { if (len < 0) {
std::cerr << "[ERROR] nghttp2_session_send() returned error: " std::cerr << "[ERROR] nghttp2_session_send2() returned error: "
<< nghttp2_strerror(len) << std::endl; << nghttp2_strerror(len) << std::endl;
return -1; return -1;
} }
@@ -1449,7 +1449,7 @@ void HttpClient::update_hostport() {
} }
bool HttpClient::add_request(const std::string &uri, bool HttpClient::add_request(const std::string &uri,
const nghttp2_data_provider *data_prd, const nghttp2_data_provider2 *data_prd,
int64_t data_length, int64_t data_length,
const nghttp2_priority_spec &pri_spec, int level) { const nghttp2_priority_spec &pri_spec, int level) {
http_parser_url u{}; http_parser_url u{};
@@ -1768,9 +1768,9 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
} // namespace } // namespace
namespace { namespace {
ssize_t select_padding_callback(nghttp2_session *session, nghttp2_ssize select_padding_callback(nghttp2_session *session,
const nghttp2_frame *frame, size_t max_payload, const nghttp2_frame *frame,
void *user_data) { size_t max_payload, void *user_data) {
return std::min(max_payload, frame->hd.length + config.padding); return std::min(max_payload, frame->hd.length + config.padding);
} }
} // namespace } // namespace
@@ -2241,7 +2241,7 @@ namespace {
int communicate( int communicate(
const std::string &scheme, const std::string &host, uint16_t port, const std::string &scheme, const std::string &host, uint16_t port,
std::vector< std::vector<
std::tuple<std::string, nghttp2_data_provider *, int64_t, int32_t>> std::tuple<std::string, nghttp2_data_provider2 *, int64_t, int32_t>>
requests, requests,
const nghttp2_session_callbacks *callbacks) { const nghttp2_session_callbacks *callbacks) {
int result = 0; int result = 0;
@@ -2311,6 +2311,17 @@ int communicate(
auto proto_list = util::get_default_alpn(); auto proto_list = util::get_default_alpn();
SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size()); SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI)
if (!SSL_CTX_add_cert_compression_alg(
ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI,
nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) {
std::cerr << "[ERROR] SSL_CTX_add_cert_compression_alg failed."
<< std::endl;
result = -1;
goto fin;
}
#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI
} }
{ {
HttpClient client{callbacks, loop, ssl_ctx}; HttpClient client{callbacks, loop, ssl_ctx};
@@ -2391,9 +2402,10 @@ fin:
} // namespace } // namespace
namespace { namespace {
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, nghttp2_ssize file_read_callback(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length, uint32_t *data_flags, uint8_t *buf, size_t length,
nghttp2_data_source *source, void *user_data) { uint32_t *data_flags,
nghttp2_data_source *source, void *user_data) {
int rv; int rv;
auto req = static_cast<Request *>( auto req = static_cast<Request *>(
nghttp2_session_get_stream_user_data(session, stream_id)); nghttp2_session_get_stream_user_data(session, stream_id));
@@ -2429,14 +2441,14 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
} }
} }
return nread; return static_cast<nghttp2_ssize>(nread);
} }
if (req->data_offset > req->data_length || nread == 0) { if (req->data_offset > req->data_length || nread == 0) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
} }
return nread; return static_cast<nghttp2_ssize>(nread);
} }
} // namespace } // namespace
@@ -2480,7 +2492,7 @@ int run(char **uris, int n) {
callbacks, on_frame_not_send_callback); callbacks, on_frame_not_send_callback);
if (config.padding) { if (config.padding) {
nghttp2_session_callbacks_set_select_padding_callback( nghttp2_session_callbacks_set_select_padding_callback2(
callbacks, select_padding_callback); callbacks, select_padding_callback);
} }
@@ -2489,7 +2501,7 @@ int run(char **uris, int n) {
uint16_t prev_port = 0; uint16_t prev_port = 0;
int failures = 0; int failures = 0;
int data_fd = -1; int data_fd = -1;
nghttp2_data_provider data_prd; nghttp2_data_provider2 data_prd;
struct stat data_stat; struct stat data_stat;
if (!config.datafile.empty()) { if (!config.datafile.empty()) {
@@ -2557,7 +2569,7 @@ int run(char **uris, int n) {
data_prd.read_callback = file_read_callback; data_prd.read_callback = file_read_callback;
} }
std::vector< std::vector<
std::tuple<std::string, nghttp2_data_provider *, int64_t, int32_t>> std::tuple<std::string, nghttp2_data_provider2 *, int64_t, int32_t>>
requests; requests;
size_t next_weight_idx = 0; size_t next_weight_idx = 0;

View File

@@ -45,6 +45,7 @@
#include <ev.h> #include <ev.h>
#define NGHTTP2_NO_SSIZE_T
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include "llhttp.h" #include "llhttp.h"
@@ -77,7 +78,7 @@ struct Config {
int64_t encoder_header_table_size; int64_t encoder_header_table_size;
size_t padding; size_t padding;
size_t max_concurrent_streams; size_t max_concurrent_streams;
ssize_t peer_max_concurrent_streams; size_t peer_max_concurrent_streams;
int multiply; int multiply;
// milliseconds // milliseconds
ev_tstamp timeout; ev_tstamp timeout;
@@ -137,7 +138,7 @@ struct ContinueTimer {
struct Request { struct Request {
// For pushed request, |uri| is empty and |u| is zero-cleared. // For pushed request, |uri| is empty and |u| is zero-cleared.
Request(const std::string &uri, const http_parser_url &u, Request(const std::string &uri, const http_parser_url &u,
const nghttp2_data_provider *data_prd, int64_t data_length, const nghttp2_data_provider2 *data_prd, int64_t data_length,
const nghttp2_priority_spec &pri_spec, int level = 0); const nghttp2_priority_spec &pri_spec, int level = 0);
~Request(); ~Request();
@@ -180,7 +181,7 @@ struct Request {
int64_t response_len; int64_t response_len;
nghttp2_gzip *inflater; nghttp2_gzip *inflater;
std::unique_ptr<HtmlParser> html_parser; std::unique_ptr<HtmlParser> html_parser;
const nghttp2_data_provider *data_prd; const nghttp2_data_provider2 *data_prd;
size_t header_buffer_size; size_t header_buffer_size;
int32_t stream_id; int32_t stream_id;
int status; int status;
@@ -246,7 +247,7 @@ struct HttpClient {
bool all_requests_processed() const; bool all_requests_processed() const;
void update_hostport(); void update_hostport();
bool add_request(const std::string &uri, bool add_request(const std::string &uri,
const nghttp2_data_provider *data_prd, int64_t data_length, const nghttp2_data_provider2 *data_prd, int64_t data_length,
const nghttp2_priority_spec &pri_spec, int level = 0); const nghttp2_priority_spec &pri_spec, int level = 0);
void record_start_time(); void record_start_time();

View File

@@ -27,26 +27,35 @@
#include <stdio.h> #include <stdio.h>
#include <assert.h> #include <assert.h>
#include <CUnit/CUnit.h> #include "munit.h"
#include <zlib.h> #include <zlib.h>
#include "nghttp2_gzip.h" #include "nghttp2_gzip.h"
static const MunitTest tests[] = {
munit_void_test(test_nghttp2_gzip_inflate),
munit_test_end(),
};
const MunitSuite gzip_suite = {
"/gzip", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
};
static size_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in, static size_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in,
size_t inlen) { size_t inlen) {
int rv; int rv;
z_stream zst = {0}; z_stream zst = {0};
rv = deflateInit(&zst, Z_DEFAULT_COMPRESSION); rv = deflateInit(&zst, Z_DEFAULT_COMPRESSION);
CU_ASSERT(rv == Z_OK); assert_int(Z_OK, ==, rv);
zst.avail_in = (unsigned int)inlen; zst.avail_in = (unsigned int)inlen;
zst.next_in = (uint8_t *)in; zst.next_in = (uint8_t *)in;
zst.avail_out = (unsigned int)outlen; zst.avail_out = (unsigned int)outlen;
zst.next_out = out; zst.next_out = out;
rv = deflate(&zst, Z_SYNC_FLUSH); rv = deflate(&zst, Z_SYNC_FLUSH);
CU_ASSERT(rv == Z_OK); assert_int(Z_OK, ==, rv);
deflateEnd(&zst); deflateEnd(&zst);
@@ -71,41 +80,44 @@ void test_nghttp2_gzip_inflate(void) {
inlen = deflate_data(in, inlen, (const uint8_t *)input, sizeof(input) - 1); inlen = deflate_data(in, inlen, (const uint8_t *)input, sizeof(input) - 1);
CU_ASSERT(0 == nghttp2_gzip_inflate_new(&inflater)); assert_int(0, ==, nghttp2_gzip_inflate_new(&inflater));
/* First 16 bytes */ /* First 16 bytes */
inptr = in; inptr = in;
inproclen = inlen; inproclen = inlen;
outproclen = 16; outproclen = 16;
CU_ASSERT( assert_int(
0 == nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen)); 0, ==,
CU_ASSERT(16 == outproclen); nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen));
CU_ASSERT(inproclen > 0); assert_size(16, ==, outproclen);
CU_ASSERT(0 == memcmp(inputptr, out, outproclen)); assert_size(0, <, inproclen);
assert_memory_equal(outproclen, inputptr, out);
/* Next 32 bytes */ /* Next 32 bytes */
inptr += inproclen; inptr += inproclen;
inlen -= inproclen; inlen -= inproclen;
inproclen = inlen; inproclen = inlen;
inputptr += outproclen; inputptr += outproclen;
outproclen = 32; outproclen = 32;
CU_ASSERT( assert_int(
0 == nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen)); 0, ==,
CU_ASSERT(32 == outproclen); nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen));
CU_ASSERT(inproclen > 0); assert_size(32, ==, outproclen);
CU_ASSERT(0 == memcmp(inputptr, out, outproclen)); assert_size(0, <, inproclen);
assert_memory_equal(outproclen, inputptr, out);
/* Rest */ /* Rest */
inptr += inproclen; inptr += inproclen;
inlen -= inproclen; inlen -= inproclen;
inproclen = inlen; inproclen = inlen;
inputptr += outproclen; inputptr += outproclen;
outproclen = sizeof(out); outproclen = sizeof(out);
CU_ASSERT( assert_int(
0 == nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen)); 0, ==,
CU_ASSERT(sizeof(input) - 49 == outproclen); nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen));
CU_ASSERT(inproclen > 0); assert_size(sizeof(input) - 49, ==, outproclen);
CU_ASSERT(0 == memcmp(inputptr, out, outproclen)); assert_size(0, <, inproclen);
assert_memory_equal(outproclen, inputptr, out);
inlen -= inproclen; inlen -= inproclen;
CU_ASSERT(0 == inlen); assert_size(0, ==, inlen);
nghttp2_gzip_inflate_del(inflater); nghttp2_gzip_inflate_del(inflater);
} }

View File

@@ -33,7 +33,13 @@
extern "C" { extern "C" {
#endif #endif
void test_nghttp2_gzip_inflate(void); #define MUNIT_ENABLE_ASSERT_ALIASES
#include "munit.h"
extern const MunitSuite gzip_suite;
munit_void_test_decl(test_nghttp2_gzip_inflate);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -26,9 +26,8 @@
# include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
#include <stdio.h> #include "munit.h"
#include <string.h>
#include <CUnit/Basic.h>
// include test cases' include files here // include test cases' include files here
#include "shrpx_tls_test.h" #include "shrpx_tls_test.h"
#include "shrpx_downstream_test.h" #include "shrpx_downstream_test.h"
@@ -47,200 +46,21 @@
#include "shrpx_router_test.h" #include "shrpx_router_test.h"
#include "shrpx_log.h" #include "shrpx_log.h"
static int init_suite1(void) { return 0; }
static int clean_suite1(void) { return 0; }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CU_pSuite pSuite = nullptr;
unsigned int num_tests_failed;
shrpx::create_config(); shrpx::create_config();
// initialize the CUnit test registry const MunitSuite suites[] = {
if (CUE_SUCCESS != CU_initialize_registry()) shrpx::tls_suite, shrpx::downstream_suite,
return CU_get_error(); shrpx::config_suite, shrpx::worker_suite,
shrpx::http_suite, shrpx::router_suite,
shrpx::http2_suite, shrpx::util_suite,
gzip_suite, buffer_suite,
memchunk_suite, template_suite,
base64_suite, {NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE},
};
const MunitSuite suite = {
"", NULL, suites, 1, MUNIT_SUITE_OPTION_NONE,
};
// add a suite to the registry return munit_suite_main(&suite, NULL, argc, argv);
pSuite = CU_add_suite("shrpx_TestSuite", init_suite1, clean_suite1);
if (nullptr == pSuite) {
CU_cleanup_registry();
return CU_get_error();
}
// add the tests to the suite
if (!CU_add_test(pSuite, "tls_create_lookup_tree",
shrpx::test_shrpx_tls_create_lookup_tree) ||
!CU_add_test(pSuite, "tls_cert_lookup_tree_add_ssl_ctx",
shrpx::test_shrpx_tls_cert_lookup_tree_add_ssl_ctx) ||
!CU_add_test(pSuite, "tls_tls_hostname_match",
shrpx::test_shrpx_tls_tls_hostname_match) ||
!CU_add_test(pSuite, "tls_tls_verify_numeric_hostname",
shrpx::test_shrpx_tls_verify_numeric_hostname) ||
!CU_add_test(pSuite, "tls_tls_verify_dns_hostname",
shrpx::test_shrpx_tls_verify_dns_hostname) ||
!CU_add_test(pSuite, "http2_add_header", shrpx::test_http2_add_header) ||
!CU_add_test(pSuite, "http2_get_header", shrpx::test_http2_get_header) ||
!CU_add_test(pSuite, "http2_copy_headers_to_nva",
shrpx::test_http2_copy_headers_to_nva) ||
!CU_add_test(pSuite, "http2_build_http1_headers_from_headers",
shrpx::test_http2_build_http1_headers_from_headers) ||
!CU_add_test(pSuite, "http2_lws", shrpx::test_http2_lws) ||
!CU_add_test(pSuite, "http2_rewrite_location_uri",
shrpx::test_http2_rewrite_location_uri) ||
!CU_add_test(pSuite, "http2_parse_http_status_code",
shrpx::test_http2_parse_http_status_code) ||
!CU_add_test(pSuite, "http2_index_header",
shrpx::test_http2_index_header) ||
!CU_add_test(pSuite, "http2_lookup_token",
shrpx::test_http2_lookup_token) ||
!CU_add_test(pSuite, "http2_parse_link_header",
shrpx::test_http2_parse_link_header) ||
!CU_add_test(pSuite, "http2_path_join", shrpx::test_http2_path_join) ||
!CU_add_test(pSuite, "http2_normalize_path",
shrpx::test_http2_normalize_path) ||
!CU_add_test(pSuite, "http2_rewrite_clean_path",
shrpx::test_http2_rewrite_clean_path) ||
!CU_add_test(pSuite, "http2_get_pure_path_component",
shrpx::test_http2_get_pure_path_component) ||
!CU_add_test(pSuite, "http2_construct_push_component",
shrpx::test_http2_construct_push_component) ||
!CU_add_test(pSuite, "http2_contains_trailers",
shrpx::test_http2_contains_trailers) ||
!CU_add_test(pSuite, "http2_check_transfer_encoding",
shrpx::test_http2_check_transfer_encoding) ||
!CU_add_test(pSuite, "downstream_field_store_append_last_header",
shrpx::test_downstream_field_store_append_last_header) ||
!CU_add_test(pSuite, "downstream_field_store_header",
shrpx::test_downstream_field_store_header) ||
!CU_add_test(pSuite, "downstream_crumble_request_cookie",
shrpx::test_downstream_crumble_request_cookie) ||
!CU_add_test(pSuite, "downstream_assemble_request_cookie",
shrpx::test_downstream_assemble_request_cookie) ||
!CU_add_test(pSuite, "downstream_rewrite_location_response_header",
shrpx::test_downstream_rewrite_location_response_header) ||
!CU_add_test(pSuite, "downstream_supports_non_final_response",
shrpx::test_downstream_supports_non_final_response) ||
!CU_add_test(pSuite, "downstream_find_affinity_cookie",
shrpx::test_downstream_find_affinity_cookie) ||
!CU_add_test(pSuite, "config_parse_header",
shrpx::test_shrpx_config_parse_header) ||
!CU_add_test(pSuite, "config_parse_log_format",
shrpx::test_shrpx_config_parse_log_format) ||
!CU_add_test(pSuite, "config_read_tls_ticket_key_file",
shrpx::test_shrpx_config_read_tls_ticket_key_file) ||
!CU_add_test(pSuite, "config_read_tls_ticket_key_file_aes_256",
shrpx::test_shrpx_config_read_tls_ticket_key_file_aes_256) ||
!CU_add_test(pSuite, "worker_match_downstream_addr_group",
shrpx::test_shrpx_worker_match_downstream_addr_group) ||
!CU_add_test(pSuite, "http_create_forwarded",
shrpx::test_shrpx_http_create_forwarded) ||
!CU_add_test(pSuite, "http_create_via_header_value",
shrpx::test_shrpx_http_create_via_header_value) ||
!CU_add_test(pSuite, "http_create_affinity_cookie",
shrpx::test_shrpx_http_create_affinity_cookie) ||
!CU_add_test(pSuite, "http_create_atlsvc_header_field_value",
shrpx::test_shrpx_http_create_altsvc_header_value) ||
!CU_add_test(pSuite, "http_check_http_scheme",
shrpx::test_shrpx_http_check_http_scheme) ||
!CU_add_test(pSuite, "router_match", shrpx::test_shrpx_router_match) ||
!CU_add_test(pSuite, "router_match_wildcard",
shrpx::test_shrpx_router_match_wildcard) ||
!CU_add_test(pSuite, "router_match_prefix",
shrpx::test_shrpx_router_match_prefix) ||
!CU_add_test(pSuite, "util_streq", shrpx::test_util_streq) ||
!CU_add_test(pSuite, "util_strieq", shrpx::test_util_strieq) ||
!CU_add_test(pSuite, "util_inp_strlower",
shrpx::test_util_inp_strlower) ||
!CU_add_test(pSuite, "util_to_base64", shrpx::test_util_to_base64) ||
!CU_add_test(pSuite, "util_to_token68", shrpx::test_util_to_token68) ||
!CU_add_test(pSuite, "util_percent_encode_token",
shrpx::test_util_percent_encode_token) ||
!CU_add_test(pSuite, "util_percent_decode",
shrpx::test_util_percent_decode) ||
!CU_add_test(pSuite, "util_quote_string",
shrpx::test_util_quote_string) ||
!CU_add_test(pSuite, "util_utox", shrpx::test_util_utox) ||
!CU_add_test(pSuite, "util_http_date", shrpx::test_util_http_date) ||
!CU_add_test(pSuite, "util_select_h2", shrpx::test_util_select_h2) ||
!CU_add_test(pSuite, "util_ipv6_numeric_addr",
shrpx::test_util_ipv6_numeric_addr) ||
!CU_add_test(pSuite, "util_utos", shrpx::test_util_utos) ||
!CU_add_test(pSuite, "util_make_string_ref_uint",
shrpx::test_util_make_string_ref_uint) ||
!CU_add_test(pSuite, "util_utos_unit", shrpx::test_util_utos_unit) ||
!CU_add_test(pSuite, "util_utos_funit", shrpx::test_util_utos_funit) ||
!CU_add_test(pSuite, "util_parse_uint_with_unit",
shrpx::test_util_parse_uint_with_unit) ||
!CU_add_test(pSuite, "util_parse_uint", shrpx::test_util_parse_uint) ||
!CU_add_test(pSuite, "util_parse_duration_with_unit",
shrpx::test_util_parse_duration_with_unit) ||
!CU_add_test(pSuite, "util_duration_str",
shrpx::test_util_duration_str) ||
!CU_add_test(pSuite, "util_format_duration",
shrpx::test_util_format_duration) ||
!CU_add_test(pSuite, "util_starts_with", shrpx::test_util_starts_with) ||
!CU_add_test(pSuite, "util_ends_with", shrpx::test_util_ends_with) ||
!CU_add_test(pSuite, "util_parse_http_date",
shrpx::test_util_parse_http_date) ||
!CU_add_test(pSuite, "util_localtime_date",
shrpx::test_util_localtime_date) ||
!CU_add_test(pSuite, "util_get_uint64", shrpx::test_util_get_uint64) ||
!CU_add_test(pSuite, "util_parse_config_str_list",
shrpx::test_util_parse_config_str_list) ||
!CU_add_test(pSuite, "util_make_http_hostport",
shrpx::test_util_make_http_hostport) ||
!CU_add_test(pSuite, "util_make_hostport",
shrpx::test_util_make_hostport) ||
!CU_add_test(pSuite, "util_strifind", shrpx::test_util_strifind) ||
!CU_add_test(pSuite, "util_random_alpha_digit",
shrpx::test_util_random_alpha_digit) ||
!CU_add_test(pSuite, "util_format_hex", shrpx::test_util_format_hex) ||
!CU_add_test(pSuite, "util_is_hex_string",
shrpx::test_util_is_hex_string) ||
!CU_add_test(pSuite, "util_decode_hex", shrpx::test_util_decode_hex) ||
!CU_add_test(pSuite, "util_extract_host",
shrpx::test_util_extract_host) ||
!CU_add_test(pSuite, "util_split_hostport",
shrpx::test_util_split_hostport) ||
!CU_add_test(pSuite, "util_split_str", shrpx::test_util_split_str) ||
!CU_add_test(pSuite, "util_rstrip", shrpx::test_util_rstrip) ||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
!CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
!CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||
!CU_add_test(pSuite, "memchunk_append", nghttp2::test_memchunks_append) ||
!CU_add_test(pSuite, "memchunk_drain", nghttp2::test_memchunks_drain) ||
!CU_add_test(pSuite, "memchunk_riovec", nghttp2::test_memchunks_riovec) ||
!CU_add_test(pSuite, "memchunk_recycle",
nghttp2::test_memchunks_recycle) ||
!CU_add_test(pSuite, "memchunk_reset", nghttp2::test_memchunks_reset) ||
!CU_add_test(pSuite, "peek_memchunk_append",
nghttp2::test_peek_memchunks_append) ||
!CU_add_test(pSuite, "peek_memchunk_disable_peek_drain",
nghttp2::test_peek_memchunks_disable_peek_drain) ||
!CU_add_test(pSuite, "peek_memchunk_disable_peek_no_drain",
nghttp2::test_peek_memchunks_disable_peek_no_drain) ||
!CU_add_test(pSuite, "peek_memchunk_reset",
nghttp2::test_peek_memchunks_reset) ||
!CU_add_test(pSuite, "template_immutable_string",
nghttp2::test_template_immutable_string) ||
!CU_add_test(pSuite, "template_string_ref",
nghttp2::test_template_string_ref) ||
!CU_add_test(pSuite, "base64_encode", nghttp2::test_base64_encode) ||
!CU_add_test(pSuite, "base64_decode", nghttp2::test_base64_decode)) {
CU_cleanup_registry();
return CU_get_error();
}
// Run all tests using the CUnit Basic interface
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
num_tests_failed = CU_get_number_of_tests_failed();
CU_cleanup_registry();
if (CU_get_error() == CUE_SUCCESS) {
return num_tests_failed;
} else {
printf("CUnit Error: %s\n", CU_get_error_msg());
return CU_get_error();
}
} }

View File

@@ -36,6 +36,8 @@
#include <cassert> #include <cassert>
#define NGHTTP2_NO_SSIZE_T
#ifndef HAVE__EXIT #ifndef HAVE__EXIT
# define nghttp2_Exit(status) _exit(status) # define nghttp2_Exit(status) _exit(status)
#else // HAVE__EXIT #else // HAVE__EXIT

View File

@@ -49,6 +49,8 @@
#include <fstream> #include <fstream>
#include <unordered_map> #include <unordered_map>
#include <openssl/evp.h>
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include "url-parser/url_parser.h" #include "url-parser/url_parser.h"
@@ -64,6 +66,10 @@
#include "ssl_compat.h" #include "ssl_compat.h"
#include "xsi_strerror.h" #include "xsi_strerror.h"
#ifndef AI_NUMERICSERV
# define AI_NUMERICSERV 0
#endif
namespace shrpx { namespace shrpx {
namespace { namespace {
@@ -4691,4 +4697,32 @@ int resolve_hostname(Address *addr, const char *hostname, uint16_t port,
return 0; return 0;
} }
#ifdef ENABLE_HTTP3
QUICKeyingMaterial::QUICKeyingMaterial(QUICKeyingMaterial &&other) noexcept
: cid_encryption_ctx{std::exchange(other.cid_encryption_ctx, nullptr)},
reserved{other.reserved},
secret{other.secret},
salt{other.salt},
cid_encryption_key{other.cid_encryption_key},
id{other.id} {}
QUICKeyingMaterial::~QUICKeyingMaterial() noexcept {
if (cid_encryption_ctx) {
EVP_CIPHER_CTX_free(cid_encryption_ctx);
}
}
QUICKeyingMaterial &
QUICKeyingMaterial::operator=(QUICKeyingMaterial &&other) noexcept {
cid_encryption_ctx = std::exchange(other.cid_encryption_ctx, nullptr);
reserved = other.reserved;
secret = other.secret;
salt = other.salt;
cid_encryption_key = other.cid_encryption_key;
id = other.id;
return *this;
}
#endif // ENABLE_HTTP3
} // namespace shrpx } // namespace shrpx

View File

@@ -636,6 +636,11 @@ struct TLSCertificate {
#ifdef ENABLE_HTTP3 #ifdef ENABLE_HTTP3
struct QUICKeyingMaterial { struct QUICKeyingMaterial {
QUICKeyingMaterial() noexcept = default;
QUICKeyingMaterial(QUICKeyingMaterial &&other) noexcept;
~QUICKeyingMaterial() noexcept;
QUICKeyingMaterial &operator=(QUICKeyingMaterial &&other) noexcept;
EVP_CIPHER_CTX *cid_encryption_ctx;
std::array<uint8_t, SHRPX_QUIC_SECRET_RESERVEDLEN> reserved; std::array<uint8_t, SHRPX_QUIC_SECRET_RESERVEDLEN> reserved;
std::array<uint8_t, SHRPX_QUIC_SECRETLEN> secret; std::array<uint8_t, SHRPX_QUIC_SECRETLEN> secret;
std::array<uint8_t, SHRPX_QUIC_SALTLEN> salt; std::array<uint8_t, SHRPX_QUIC_SALTLEN> salt;

View File

@@ -30,43 +30,57 @@
#include <cstdlib> #include <cstdlib>
#include <CUnit/CUnit.h> #include "munitxx.h"
#include "shrpx_config.h" #include "shrpx_config.h"
#include "shrpx_log.h" #include "shrpx_log.h"
namespace shrpx { namespace shrpx {
namespace {
const MunitTest tests[]{
munit_void_test(test_shrpx_config_parse_header),
munit_void_test(test_shrpx_config_parse_log_format),
munit_void_test(test_shrpx_config_read_tls_ticket_key_file),
munit_void_test(test_shrpx_config_read_tls_ticket_key_file_aes_256),
munit_test_end(),
};
} // namespace
const MunitSuite config_suite{
"/config_suite", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
};
void test_shrpx_config_parse_header(void) { void test_shrpx_config_parse_header(void) {
BlockAllocator balloc(4096, 4096); BlockAllocator balloc(4096, 4096);
auto p = parse_header(balloc, StringRef::from_lit("a: b")); auto p = parse_header(balloc, StringRef::from_lit("a: b"));
CU_ASSERT("a" == p.name); assert_stdstring_equal("a", p.name.str());
CU_ASSERT("b" == p.value); assert_stdstring_equal("b", p.value.str());
p = parse_header(balloc, StringRef::from_lit("a: b")); p = parse_header(balloc, StringRef::from_lit("a: b"));
CU_ASSERT("a" == p.name); assert_stdstring_equal("a", p.name.str());
CU_ASSERT("b" == p.value); assert_stdstring_equal("b", p.value.str());
p = parse_header(balloc, StringRef::from_lit(":a: b")); p = parse_header(balloc, StringRef::from_lit(":a: b"));
CU_ASSERT(p.name.empty()); assert_true(p.name.empty());
p = parse_header(balloc, StringRef::from_lit("a: :b")); p = parse_header(balloc, StringRef::from_lit("a: :b"));
CU_ASSERT("a" == p.name); assert_stdstring_equal("a", p.name.str());
CU_ASSERT(":b" == p.value); assert_stdstring_equal(":b", p.value.str());
p = parse_header(balloc, StringRef::from_lit(": b")); p = parse_header(balloc, StringRef::from_lit(": b"));
CU_ASSERT(p.name.empty()); assert_true(p.name.empty());
p = parse_header(balloc, StringRef::from_lit("alpha: bravo charlie")); p = parse_header(balloc, StringRef::from_lit("alpha: bravo charlie"));
CU_ASSERT("alpha" == p.name); assert_stdstring_equal("alpha", p.name.str());
CU_ASSERT("bravo charlie" == p.value); assert_stdstring_equal("bravo charlie", p.value.str());
p = parse_header(balloc, StringRef::from_lit("a,: b")); p = parse_header(balloc, StringRef::from_lit("a,: b"));
CU_ASSERT(p.name.empty()); assert_true(p.name.empty());
p = parse_header(balloc, StringRef::from_lit("a: b\x0a")); p = parse_header(balloc, StringRef::from_lit("a: b\x0a"));
CU_ASSERT(p.name.empty()); assert_true(p.name.empty());
} }
void test_shrpx_config_parse_log_format(void) { void test_shrpx_config_parse_log_format(void) {
@@ -77,100 +91,102 @@ void test_shrpx_config_parse_log_format(void) {
R"($remote_addr - $remote_user [$time_local] )" R"($remote_addr - $remote_user [$time_local] )"
R"("$request" $status $body_bytes_sent )" R"("$request" $status $body_bytes_sent )"
R"("${http_referer}" $http_host "$http_user_agent")")); R"("${http_referer}" $http_host "$http_user_agent")"));
CU_ASSERT(16 == res.size()); assert_size(16, ==, res.size());
CU_ASSERT(LogFragmentType::REMOTE_ADDR == res[0].type); assert_enum_class(LogFragmentType::REMOTE_ADDR, ==, res[0].type);
CU_ASSERT(LogFragmentType::LITERAL == res[1].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[1].type);
CU_ASSERT(" - $remote_user [" == res[1].value); assert_stdstring_equal(" - $remote_user [", res[1].value.str());
CU_ASSERT(LogFragmentType::TIME_LOCAL == res[2].type); assert_enum_class(LogFragmentType::TIME_LOCAL, ==, res[2].type);
CU_ASSERT(LogFragmentType::LITERAL == res[3].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[3].type);
CU_ASSERT("] \"" == res[3].value); assert_stdstring_equal("] \"", res[3].value.str());
CU_ASSERT(LogFragmentType::REQUEST == res[4].type); assert_enum_class(LogFragmentType::REQUEST, ==, res[4].type);
CU_ASSERT(LogFragmentType::LITERAL == res[5].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[5].type);
CU_ASSERT("\" " == res[5].value); assert_stdstring_equal("\" ", res[5].value.str());
CU_ASSERT(LogFragmentType::STATUS == res[6].type); assert_enum_class(LogFragmentType::STATUS, ==, res[6].type);
CU_ASSERT(LogFragmentType::LITERAL == res[7].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[7].type);
CU_ASSERT(" " == res[7].value); assert_stdstring_equal(" ", res[7].value.str());
CU_ASSERT(LogFragmentType::BODY_BYTES_SENT == res[8].type); assert_enum_class(LogFragmentType::BODY_BYTES_SENT, ==, res[8].type);
CU_ASSERT(LogFragmentType::LITERAL == res[9].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[9].type);
CU_ASSERT(" \"" == res[9].value); assert_stdstring_equal(" \"", res[9].value.str());
CU_ASSERT(LogFragmentType::HTTP == res[10].type); assert_enum_class(LogFragmentType::HTTP, ==, res[10].type);
CU_ASSERT("referer" == res[10].value); assert_stdstring_equal("referer", res[10].value.str());
CU_ASSERT(LogFragmentType::LITERAL == res[11].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[11].type);
CU_ASSERT("\" " == res[11].value); assert_stdstring_equal("\" ", res[11].value.str());
CU_ASSERT(LogFragmentType::AUTHORITY == res[12].type); assert_enum_class(LogFragmentType::AUTHORITY, ==, res[12].type);
CU_ASSERT(LogFragmentType::LITERAL == res[13].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[13].type);
CU_ASSERT(" \"" == res[13].value); assert_stdstring_equal(" \"", res[13].value.str());
CU_ASSERT(LogFragmentType::HTTP == res[14].type); assert_enum_class(LogFragmentType::HTTP, ==, res[14].type);
CU_ASSERT("user-agent" == res[14].value); assert_stdstring_equal("user-agent", res[14].value.str());
CU_ASSERT(LogFragmentType::LITERAL == res[15].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[15].type);
CU_ASSERT("\"" == res[15].value); assert_stdstring_equal("\"", res[15].value.str());
res = parse_log_format(balloc, StringRef::from_lit("$")); res = parse_log_format(balloc, StringRef::from_lit("$"));
CU_ASSERT(1 == res.size()); assert_size(1, ==, res.size());
CU_ASSERT(LogFragmentType::LITERAL == res[0].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type);
CU_ASSERT("$" == res[0].value); assert_stdstring_equal("$", res[0].value.str());
res = parse_log_format(balloc, StringRef::from_lit("${")); res = parse_log_format(balloc, StringRef::from_lit("${"));
CU_ASSERT(1 == res.size()); assert_size(1, ==, res.size());
CU_ASSERT(LogFragmentType::LITERAL == res[0].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type);
CU_ASSERT("${" == res[0].value); assert_stdstring_equal("${", res[0].value.str());
res = parse_log_format(balloc, StringRef::from_lit("${a")); res = parse_log_format(balloc, StringRef::from_lit("${a"));
CU_ASSERT(1 == res.size()); assert_size(1, ==, res.size());
CU_ASSERT(LogFragmentType::LITERAL == res[0].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type);
CU_ASSERT("${a" == res[0].value); assert_stdstring_equal("${a", res[0].value.str());
res = parse_log_format(balloc, StringRef::from_lit("${a ")); res = parse_log_format(balloc, StringRef::from_lit("${a "));
CU_ASSERT(1 == res.size()); assert_size(1, ==, res.size());
CU_ASSERT(LogFragmentType::LITERAL == res[0].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type);
CU_ASSERT("${a " == res[0].value); assert_stdstring_equal("${a ", res[0].value.str());
res = parse_log_format(balloc, StringRef::from_lit("$$remote_addr")); res = parse_log_format(balloc, StringRef::from_lit("$$remote_addr"));
CU_ASSERT(2 == res.size()); assert_size(2, ==, res.size());
CU_ASSERT(LogFragmentType::LITERAL == res[0].type); assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type);
CU_ASSERT("$" == res[0].value); assert_stdstring_equal("$", res[0].value.str());
CU_ASSERT(LogFragmentType::REMOTE_ADDR == res[1].type); assert_enum_class(LogFragmentType::REMOTE_ADDR, ==, res[1].type);
CU_ASSERT("" == res[1].value); assert_stdstring_equal("", res[1].value.str());
} }
void test_shrpx_config_read_tls_ticket_key_file(void) { void test_shrpx_config_read_tls_ticket_key_file(void) {
char file1[] = "/tmp/nghttpx-unittest.XXXXXX"; char file1[] = "/tmp/nghttpx-unittest.XXXXXX";
auto fd1 = mkstemp(file1); auto fd1 = mkstemp(file1);
CU_ASSERT(fd1 != -1); assert_int(-1, !=, fd1);
CU_ASSERT(48 == assert_ssize(
write(fd1, "0..............12..............34..............5", 48)); 48, ==,
write(fd1, "0..............12..............34..............5", 48));
char file2[] = "/tmp/nghttpx-unittest.XXXXXX"; char file2[] = "/tmp/nghttpx-unittest.XXXXXX";
auto fd2 = mkstemp(file2); auto fd2 = mkstemp(file2);
CU_ASSERT(fd2 != -1); assert_int(-1, !=, fd2);
CU_ASSERT(48 == assert_ssize(
write(fd2, "6..............78..............9a..............b", 48)); 48, ==,
write(fd2, "6..............78..............9a..............b", 48));
close(fd1); close(fd1);
close(fd2); close(fd2);
@@ -178,44 +194,48 @@ void test_shrpx_config_read_tls_ticket_key_file(void) {
{StringRef{file1}, StringRef{file2}}, EVP_aes_128_cbc(), EVP_sha256()); {StringRef{file1}, StringRef{file2}}, EVP_aes_128_cbc(), EVP_sha256());
unlink(file1); unlink(file1);
unlink(file2); unlink(file2);
CU_ASSERT(ticket_keys.get() != nullptr); assert_not_null(ticket_keys.get());
CU_ASSERT(2 == ticket_keys->keys.size()); assert_size(2, ==, ticket_keys->keys.size());
auto key = &ticket_keys->keys[0]; auto key = &ticket_keys->keys[0];
CU_ASSERT(std::equal(std::begin(key->data.name), std::end(key->data.name), assert_true(std::equal(std::begin(key->data.name), std::end(key->data.name),
"0..............1")); "0..............1"));
CU_ASSERT(std::equal(std::begin(key->data.enc_key), assert_true(std::equal(std::begin(key->data.enc_key),
std::begin(key->data.enc_key) + 16, "2..............3")); std::begin(key->data.enc_key) + 16,
CU_ASSERT(std::equal(std::begin(key->data.hmac_key), "2..............3"));
std::begin(key->data.hmac_key) + 16, assert_true(std::equal(std::begin(key->data.hmac_key),
"4..............5")); std::begin(key->data.hmac_key) + 16,
CU_ASSERT(16 == key->hmac_keylen); "4..............5"));
assert_size(16, ==, key->hmac_keylen);
key = &ticket_keys->keys[1]; key = &ticket_keys->keys[1];
CU_ASSERT(std::equal(std::begin(key->data.name), std::end(key->data.name), assert_true(std::equal(std::begin(key->data.name), std::end(key->data.name),
"6..............7")); "6..............7"));
CU_ASSERT(std::equal(std::begin(key->data.enc_key), assert_true(std::equal(std::begin(key->data.enc_key),
std::begin(key->data.enc_key) + 16, "8..............9")); std::begin(key->data.enc_key) + 16,
CU_ASSERT(std::equal(std::begin(key->data.hmac_key), "8..............9"));
std::begin(key->data.hmac_key) + 16, assert_true(std::equal(std::begin(key->data.hmac_key),
"a..............b")); std::begin(key->data.hmac_key) + 16,
CU_ASSERT(16 == key->hmac_keylen); "a..............b"));
assert_size(16, ==, key->hmac_keylen);
} }
void test_shrpx_config_read_tls_ticket_key_file_aes_256(void) { void test_shrpx_config_read_tls_ticket_key_file_aes_256(void) {
char file1[] = "/tmp/nghttpx-unittest.XXXXXX"; char file1[] = "/tmp/nghttpx-unittest.XXXXXX";
auto fd1 = mkstemp(file1); auto fd1 = mkstemp(file1);
CU_ASSERT(fd1 != -1); assert_int(-1, !=, fd1);
CU_ASSERT(80 == write(fd1, assert_ssize(80, ==,
"0..............12..............................34..." write(fd1,
"...........................5", "0..............12..............................34..."
80)); "...........................5",
80));
char file2[] = "/tmp/nghttpx-unittest.XXXXXX"; char file2[] = "/tmp/nghttpx-unittest.XXXXXX";
auto fd2 = mkstemp(file2); auto fd2 = mkstemp(file2);
CU_ASSERT(fd2 != -1); assert_int(-1, !=, fd2);
CU_ASSERT(80 == write(fd2, assert_ssize(80, ==,
"6..............78..............................9a..." write(fd2,
"...........................b", "6..............78..............................9a..."
80)); "...........................b",
80));
close(fd1); close(fd1);
close(fd2); close(fd2);
@@ -223,27 +243,27 @@ void test_shrpx_config_read_tls_ticket_key_file_aes_256(void) {
{StringRef{file1}, StringRef{file2}}, EVP_aes_256_cbc(), EVP_sha256()); {StringRef{file1}, StringRef{file2}}, EVP_aes_256_cbc(), EVP_sha256());
unlink(file1); unlink(file1);
unlink(file2); unlink(file2);
CU_ASSERT(ticket_keys.get() != nullptr); assert_not_null(ticket_keys.get());
CU_ASSERT(2 == ticket_keys->keys.size()); assert_size(2, ==, ticket_keys->keys.size());
auto key = &ticket_keys->keys[0]; auto key = &ticket_keys->keys[0];
CU_ASSERT(std::equal(std::begin(key->data.name), std::end(key->data.name), assert_true(std::equal(std::begin(key->data.name), std::end(key->data.name),
"0..............1")); "0..............1"));
CU_ASSERT(std::equal(std::begin(key->data.enc_key), assert_true(std::equal(std::begin(key->data.enc_key),
std::end(key->data.enc_key), std::end(key->data.enc_key),
"2..............................3")); "2..............................3"));
CU_ASSERT(std::equal(std::begin(key->data.hmac_key), assert_true(std::equal(std::begin(key->data.hmac_key),
std::end(key->data.hmac_key), std::end(key->data.hmac_key),
"4..............................5")); "4..............................5"));
key = &ticket_keys->keys[1]; key = &ticket_keys->keys[1];
CU_ASSERT(std::equal(std::begin(key->data.name), std::end(key->data.name), assert_true(std::equal(std::begin(key->data.name), std::end(key->data.name),
"6..............7")); "6..............7"));
CU_ASSERT(std::equal(std::begin(key->data.enc_key), assert_true(std::equal(std::begin(key->data.enc_key),
std::end(key->data.enc_key), std::end(key->data.enc_key),
"8..............................9")); "8..............................9"));
CU_ASSERT(std::equal(std::begin(key->data.hmac_key), assert_true(std::equal(std::begin(key->data.hmac_key),
std::end(key->data.hmac_key), std::end(key->data.hmac_key),
"a..............................b")); "a..............................b"));
} }
} // namespace shrpx } // namespace shrpx

View File

@@ -29,13 +29,18 @@
# include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
#define MUNIT_ENABLE_ASSERT_ALIASES
#include "munit.h"
namespace shrpx { namespace shrpx {
void test_shrpx_config_parse_header(void); extern const MunitSuite config_suite;
void test_shrpx_config_parse_log_format(void);
void test_shrpx_config_read_tls_ticket_key_file(void); munit_void_test_decl(test_shrpx_config_parse_header);
void test_shrpx_config_read_tls_ticket_key_file_aes_256(void); munit_void_test_decl(test_shrpx_config_parse_log_format);
void test_shrpx_config_match_downstream_addr_group(void); munit_void_test_decl(test_shrpx_config_read_tls_ticket_key_file);
munit_void_test_decl(test_shrpx_config_read_tls_ticket_key_file_aes_256);
} // namespace shrpx } // namespace shrpx

View File

@@ -863,7 +863,7 @@ void Connection::start_tls_write_idle() {
} }
} }
ssize_t Connection::write_tls(const void *data, size_t len) { nghttp2_ssize Connection::write_tls(const void *data, size_t len) {
// SSL_write requires the same arguments (buf pointer and its // SSL_write requires the same arguments (buf pointer and its
// length) on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. // length) on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.
// get_write_limit() may return smaller length than previously // get_write_limit() may return smaller length than previously
@@ -950,7 +950,7 @@ ssize_t Connection::write_tls(const void *data, size_t len) {
return rv; return rv;
} }
ssize_t Connection::read_tls(void *data, size_t len) { nghttp2_ssize Connection::read_tls(void *data, size_t len) {
ERR_clear_error(); ERR_clear_error();
#if defined(NGHTTP2_GENUINE_OPENSSL) || defined(NGHTTP2_OPENSSL_IS_BORINGSSL) #if defined(NGHTTP2_GENUINE_OPENSSL) || defined(NGHTTP2_OPENSSL_IS_BORINGSSL)
@@ -1061,7 +1061,7 @@ ssize_t Connection::read_tls(void *data, size_t len) {
return rv; return rv;
} }
ssize_t Connection::write_clear(const void *data, size_t len) { nghttp2_ssize Connection::write_clear(const void *data, size_t len) {
len = std::min(len, wlimit.avail()); len = std::min(len, wlimit.avail());
if (len == 0) { if (len == 0) {
return 0; return 0;
@@ -1088,7 +1088,7 @@ ssize_t Connection::write_clear(const void *data, size_t len) {
return nwrite; return nwrite;
} }
ssize_t Connection::writev_clear(struct iovec *iov, int iovcnt) { nghttp2_ssize Connection::writev_clear(struct iovec *iov, int iovcnt) {
iovcnt = limit_iovec(iov, iovcnt, wlimit.avail()); iovcnt = limit_iovec(iov, iovcnt, wlimit.avail());
if (iovcnt == 0) { if (iovcnt == 0) {
return 0; return 0;
@@ -1115,7 +1115,7 @@ ssize_t Connection::writev_clear(struct iovec *iov, int iovcnt) {
return nwrite; return nwrite;
} }
ssize_t Connection::read_clear(void *data, size_t len) { nghttp2_ssize Connection::read_clear(void *data, size_t len) {
len = std::min(len, rlimit.avail()); len = std::min(len, rlimit.avail());
if (len == 0) { if (len == 0) {
return 0; return 0;
@@ -1140,7 +1140,7 @@ ssize_t Connection::read_clear(void *data, size_t len) {
return nread; return nread;
} }
ssize_t Connection::read_nolim_clear(void *data, size_t len) { nghttp2_ssize Connection::read_nolim_clear(void *data, size_t len) {
ssize_t nread; ssize_t nread;
while ((nread = read(fd, data, len)) == -1 && errno == EINTR) while ((nread = read(fd, data, len)) == -1 && errno == EINTR)
; ;
@@ -1158,7 +1158,7 @@ ssize_t Connection::read_nolim_clear(void *data, size_t len) {
return nread; return nread;
} }
ssize_t Connection::peek_clear(void *data, size_t len) { nghttp2_ssize Connection::peek_clear(void *data, size_t len) {
ssize_t nread; ssize_t nread;
while ((nread = recv(fd, data, len, MSG_PEEK)) == -1 && errno == EINTR) while ((nread = recv(fd, data, len, MSG_PEEK)) == -1 && errno == EINTR)
; ;

View File

@@ -33,6 +33,8 @@
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <nghttp2/nghttp2.h>
#ifdef ENABLE_HTTP3 #ifdef ENABLE_HTTP3
# include <ngtcp2/ngtcp2_crypto.h> # include <ngtcp2/ngtcp2_crypto.h>
#endif // ENABLE_HTTP3 #endif // ENABLE_HTTP3
@@ -128,8 +130,8 @@ struct Connection {
// underlying connection blocks), return 0. SHRPX_ERR_EOF is // underlying connection blocks), return 0. SHRPX_ERR_EOF is
// returned in case of EOF and no data was read. Otherwise // returned in case of EOF and no data was read. Otherwise
// SHRPX_ERR_NETWORK is return in case of error. // SHRPX_ERR_NETWORK is return in case of error.
ssize_t write_tls(const void *data, size_t len); nghttp2_ssize write_tls(const void *data, size_t len);
ssize_t read_tls(void *data, size_t len); nghttp2_ssize read_tls(void *data, size_t len);
size_t get_tls_write_limit(); size_t get_tls_write_limit();
// Updates the number of bytes written in warm up period. // Updates the number of bytes written in warm up period.
@@ -138,13 +140,13 @@ struct Connection {
// determine fallback to short record size mode. // determine fallback to short record size mode.
void start_tls_write_idle(); void start_tls_write_idle();
ssize_t write_clear(const void *data, size_t len); nghttp2_ssize write_clear(const void *data, size_t len);
ssize_t writev_clear(struct iovec *iov, int iovcnt); nghttp2_ssize writev_clear(struct iovec *iov, int iovcnt);
ssize_t read_clear(void *data, size_t len); nghttp2_ssize read_clear(void *data, size_t len);
// Read at most |len| bytes of data from socket without rate limit. // Read at most |len| bytes of data from socket without rate limit.
ssize_t read_nolim_clear(void *data, size_t len); nghttp2_ssize read_nolim_clear(void *data, size_t len);
// Peek at most |len| bytes of data from socket without rate limit. // Peek at most |len| bytes of data from socket without rate limit.
ssize_t peek_clear(void *data, size_t len); nghttp2_ssize peek_clear(void *data, size_t len);
void handle_tls_pending_read(); void handle_tls_pending_read();

View File

@@ -739,40 +739,31 @@ void ConnectionHandler::handle_ocsp_complete() {
// that case we get nullptr. // that case we get nullptr.
auto quic_ssl_ctx = quic_all_ssl_ctx_[ocsp_.next]; auto quic_ssl_ctx = quic_all_ssl_ctx_[ocsp_.next];
if (quic_ssl_ctx) { if (quic_ssl_ctx) {
# ifndef NGHTTP2_OPENSSL_IS_BORINGSSL
auto quic_tls_ctx_data = static_cast<tls::TLSContextData *>( auto quic_tls_ctx_data = static_cast<tls::TLSContextData *>(
SSL_CTX_get_app_data(quic_ssl_ctx)); SSL_CTX_get_app_data(quic_ssl_ctx));
# ifdef HAVE_ATOMIC_STD_SHARED_PTR # ifdef HAVE_ATOMIC_STD_SHARED_PTR
std::atomic_store_explicit( std::atomic_store_explicit(
&quic_tls_ctx_data->ocsp_data, &quic_tls_ctx_data->ocsp_data,
std::make_shared<std::vector<uint8_t>>(ocsp_.resp), std::make_shared<std::vector<uint8_t>>(ocsp_.resp),
std::memory_order_release); std::memory_order_release);
# else // !HAVE_ATOMIC_STD_SHARED_PTR # else // !HAVE_ATOMIC_STD_SHARED_PTR
std::lock_guard<std::mutex> g(quic_tls_ctx_data->mu); std::lock_guard<std::mutex> g(quic_tls_ctx_data->mu);
quic_tls_ctx_data->ocsp_data = quic_tls_ctx_data->ocsp_data =
std::make_shared<std::vector<uint8_t>>(ocsp_.resp); std::make_shared<std::vector<uint8_t>>(ocsp_.resp);
# endif // !HAVE_ATOMIC_STD_SHARED_PTR # endif // !HAVE_ATOMIC_STD_SHARED_PTR
# else // NGHTTP2_OPENSSL_IS_BORINGSSL
SSL_CTX_set_ocsp_response(quic_ssl_ctx, ocsp_.resp.data(),
ocsp_.resp.size());
# endif // NGHTTP2_OPENSSL_IS_BORINGSSL
} }
#endif // ENABLE_HTTP3 #endif // ENABLE_HTTP3
#ifndef NGHTTP2_OPENSSL_IS_BORINGSSL #ifdef HAVE_ATOMIC_STD_SHARED_PTR
# ifdef HAVE_ATOMIC_STD_SHARED_PTR
std::atomic_store_explicit( std::atomic_store_explicit(
&tls_ctx_data->ocsp_data, &tls_ctx_data->ocsp_data,
std::make_shared<std::vector<uint8_t>>(std::move(ocsp_.resp)), std::make_shared<std::vector<uint8_t>>(std::move(ocsp_.resp)),
std::memory_order_release); std::memory_order_release);
# else // !HAVE_ATOMIC_STD_SHARED_PTR #else // !HAVE_ATOMIC_STD_SHARED_PTR
std::lock_guard<std::mutex> g(tls_ctx_data->mu); std::lock_guard<std::mutex> g(tls_ctx_data->mu);
tls_ctx_data->ocsp_data = tls_ctx_data->ocsp_data =
std::make_shared<std::vector<uint8_t>>(std::move(ocsp_.resp)); std::make_shared<std::vector<uint8_t>>(std::move(ocsp_.resp));
# endif // !HAVE_ATOMIC_STD_SHARED_PTR #endif // !HAVE_ATOMIC_STD_SHARED_PTR
#else // NGHTTP2_OPENSSL_IS_BORINGSSL
SSL_CTX_set_ocsp_response(ssl_ctx, ocsp_.resp.data(), ocsp_.resp.size());
#endif // NGHTTP2_OPENSSL_IS_BORINGSSL
} }
++ocsp_.next; ++ocsp_.next;
@@ -1288,7 +1279,7 @@ int ConnectionHandler::quic_ipc_read() {
if (decrypt_quic_connection_id(decrypted_dcid.data(), if (decrypt_quic_connection_id(decrypted_dcid.data(),
vc.dcid + SHRPX_QUIC_CID_PREFIX_OFFSET, vc.dcid + SHRPX_QUIC_CID_PREFIX_OFFSET,
qkm.cid_encryption_key.data()) != 0) { qkm.cid_encryption_ctx) != 0) {
return -1; return -1;
} }

View File

@@ -26,12 +26,29 @@
#include <iostream> #include <iostream>
#include <CUnit/CUnit.h> #include "munitxx.h"
#include "shrpx_downstream.h" #include "shrpx_downstream.h"
namespace shrpx { namespace shrpx {
namespace {
const MunitTest tests[]{
munit_void_test(test_downstream_field_store_append_last_header),
munit_void_test(test_downstream_field_store_header),
munit_void_test(test_downstream_crumble_request_cookie),
munit_void_test(test_downstream_assemble_request_cookie),
munit_void_test(test_downstream_rewrite_location_response_header),
munit_void_test(test_downstream_supports_non_final_response),
munit_void_test(test_downstream_find_affinity_cookie),
munit_test_end(),
};
} // namespace
const MunitSuite downstream_suite{
"/downstream", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
};
void test_downstream_field_store_append_last_header(void) { void test_downstream_field_store_append_last_header(void) {
BlockAllocator balloc(16, 16); BlockAllocator balloc(16, 16);
FieldStore fs(balloc, 0); FieldStore fs(balloc, 0);
@@ -57,7 +74,7 @@ void test_downstream_field_store_append_last_header(void) {
HeaderRefs{{StringRef::from_lit("alphabravogolf0123456789"), HeaderRefs{{StringRef::from_lit("alphabravogolf0123456789"),
StringRef::from_lit("CharliedeltAecho0123456789")}, StringRef::from_lit("CharliedeltAecho0123456789")},
{StringRef::from_lit("echo"), StringRef::from_lit("foxtrot")}}; {StringRef::from_lit("echo"), StringRef::from_lit("foxtrot")}};
CU_ASSERT(ans == fs.headers()); assert_true(ans == fs.headers());
} }
void test_downstream_field_store_header(void) { void test_downstream_field_store_header(void) {
@@ -72,14 +89,14 @@ void test_downstream_field_store_header(void) {
http2::HD_CONTENT_LENGTH); http2::HD_CONTENT_LENGTH);
// By token // By token
CU_ASSERT(HeaderRef(StringRef{":authority"}, StringRef{"1"}) == assert_true(HeaderRef(StringRef{":authority"}, StringRef{"1"}) ==
*fs.header(http2::HD__AUTHORITY)); *fs.header(http2::HD__AUTHORITY));
CU_ASSERT(nullptr == fs.header(http2::HD__METHOD)); assert_null(fs.header(http2::HD__METHOD));
// By name // By name
CU_ASSERT(HeaderRef(StringRef{"alpha"}, StringRef{"0"}) == assert_true(HeaderRef(StringRef{"alpha"}, StringRef{"0"}) ==
*fs.header(StringRef::from_lit("alpha"))); *fs.header(StringRef::from_lit("alpha")));
CU_ASSERT(nullptr == fs.header(StringRef::from_lit("bravo"))); assert_null(fs.header(StringRef::from_lit("bravo")));
} }
void test_downstream_crumble_request_cookie(void) { void test_downstream_crumble_request_cookie(void) {
@@ -103,8 +120,8 @@ void test_downstream_crumble_request_cookie(void) {
auto num_cookies = d.count_crumble_request_cookie(); auto num_cookies = d.count_crumble_request_cookie();
CU_ASSERT(5 == nva.size()); assert_size(5, ==, nva.size());
CU_ASSERT(5 == num_cookies); assert_size(5, ==, num_cookies);
HeaderRefs cookies; HeaderRefs cookies;
std::transform(std::begin(nva), std::end(nva), std::back_inserter(cookies), std::transform(std::begin(nva), std::end(nva), std::back_inserter(cookies),
@@ -121,10 +138,10 @@ void test_downstream_crumble_request_cookie(void) {
{StringRef::from_lit("cookie"), StringRef::from_lit("delta")}, {StringRef::from_lit("cookie"), StringRef::from_lit("delta")},
{StringRef::from_lit("cookie"), StringRef::from_lit("echo")}}; {StringRef::from_lit("cookie"), StringRef::from_lit("echo")}};
CU_ASSERT(ans == cookies); assert_true(ans == cookies);
CU_ASSERT(cookies[0].no_index); assert_true(cookies[0].no_index);
CU_ASSERT(cookies[1].no_index); assert_true(cookies[1].no_index);
CU_ASSERT(cookies[2].no_index); assert_true(cookies[2].no_index);
} }
void test_downstream_assemble_request_cookie(void) { void test_downstream_assemble_request_cookie(void) {
@@ -147,7 +164,8 @@ void test_downstream_assemble_request_cookie(void) {
req.fs.add_header_token(StringRef::from_lit("cookie"), req.fs.add_header_token(StringRef::from_lit("cookie"),
StringRef::from_lit("delta;;"), false, StringRef::from_lit("delta;;"), false,
http2::HD_COOKIE); http2::HD_COOKIE);
CU_ASSERT("alpha; bravo; charlie; delta" == d.assemble_request_cookie()); assert_stdstring_equal("alpha; bravo; charlie; delta",
d.assemble_request_cookie().str());
} }
void test_downstream_rewrite_location_response_header(void) { void test_downstream_rewrite_location_response_header(void) {
@@ -161,7 +179,7 @@ void test_downstream_rewrite_location_response_header(void) {
false, http2::HD_LOCATION); false, http2::HD_LOCATION);
d.rewrite_location_response_header(StringRef::from_lit("https")); d.rewrite_location_response_header(StringRef::from_lit("https"));
auto location = resp.fs.header(http2::HD_LOCATION); auto location = resp.fs.header(http2::HD_LOCATION);
CU_ASSERT("https://localhost:8443/" == (*location).value); assert_stdstring_equal("https://localhost:8443/", (*location).value.str());
} }
void test_downstream_supports_non_final_response(void) { void test_downstream_supports_non_final_response(void) {
@@ -171,27 +189,27 @@ void test_downstream_supports_non_final_response(void) {
req.http_major = 3; req.http_major = 3;
req.http_minor = 0; req.http_minor = 0;
CU_ASSERT(d.supports_non_final_response()); assert_true(d.supports_non_final_response());
req.http_major = 2; req.http_major = 2;
req.http_minor = 0; req.http_minor = 0;
CU_ASSERT(d.supports_non_final_response()); assert_true(d.supports_non_final_response());
req.http_major = 1; req.http_major = 1;
req.http_minor = 1; req.http_minor = 1;
CU_ASSERT(d.supports_non_final_response()); assert_true(d.supports_non_final_response());
req.http_major = 1; req.http_major = 1;
req.http_minor = 0; req.http_minor = 0;
CU_ASSERT(!d.supports_non_final_response()); assert_false(d.supports_non_final_response());
req.http_major = 0; req.http_major = 0;
req.http_minor = 9; req.http_minor = 9;
CU_ASSERT(!d.supports_non_final_response()); assert_false(d.supports_non_final_response());
} }
void test_downstream_find_affinity_cookie(void) { void test_downstream_find_affinity_cookie(void) {
@@ -217,15 +235,15 @@ void test_downstream_find_affinity_cookie(void) {
aff = d.find_affinity_cookie(StringRef::from_lit("lb")); aff = d.find_affinity_cookie(StringRef::from_lit("lb"));
CU_ASSERT(0xdeadbeef == aff); assert_uint32(0xdeadbeef, ==, aff);
aff = d.find_affinity_cookie(StringRef::from_lit("LB")); aff = d.find_affinity_cookie(StringRef::from_lit("LB"));
CU_ASSERT(0xf1f2f3f4 == aff); assert_uint32(0xf1f2f3f4, ==, aff);
aff = d.find_affinity_cookie(StringRef::from_lit("short")); aff = d.find_affinity_cookie(StringRef::from_lit("short"));
CU_ASSERT(0 == aff); assert_uint32(0, ==, aff);
} }
} // namespace shrpx } // namespace shrpx

View File

@@ -29,15 +29,21 @@
# include <config.h> # include <config.h>
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
#define MUNIT_ENABLE_ASSERT_ALIASES
#include "munit.h"
namespace shrpx { namespace shrpx {
void test_downstream_field_store_append_last_header(void); extern const MunitSuite downstream_suite;
void test_downstream_field_store_header(void);
void test_downstream_crumble_request_cookie(void); munit_void_test_decl(test_downstream_field_store_append_last_header);
void test_downstream_assemble_request_cookie(void); munit_void_test_decl(test_downstream_field_store_header);
void test_downstream_rewrite_location_response_header(void); munit_void_test_decl(test_downstream_crumble_request_cookie);
void test_downstream_supports_non_final_response(void); munit_void_test_decl(test_downstream_assemble_request_cookie);
void test_downstream_find_affinity_cookie(void); munit_void_test_decl(test_downstream_rewrite_location_response_header);
munit_void_test_decl(test_downstream_supports_non_final_response);
munit_void_test_decl(test_downstream_find_affinity_cookie);
} // namespace shrpx } // namespace shrpx

View File

@@ -167,9 +167,9 @@ std::string colorizeHeaders(const char *hdrs) {
return nhdrs; return nhdrs;
} }
ssize_t select_padding_callback(nghttp2_session *session, nghttp2_ssize select_padding_callback(nghttp2_session *session,
const nghttp2_frame *frame, size_t max_payload, const nghttp2_frame *frame,
void *user_data) { size_t max_payload, void *user_data) {
return std::min(max_payload, frame->hd.length + get_config()->padding); return std::min(max_payload, frame->hd.length + get_config()->padding);
} }

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