Compare commits
84 Commits
Author | SHA1 | Date |
---|---|---|
George Sokianos | c2a039f23f | |
Tatsuhiro Tsujikawa | 05b7929019 | |
Tatsuhiro Tsujikawa | 5b665b3e48 | |
Tatsuhiro Tsujikawa | 5089dcd3f2 | |
Tatsuhiro Tsujikawa | b52f96d38a | |
Tatsuhiro Tsujikawa | 2ca0bb0a2f | |
Tatsuhiro Tsujikawa | fa3d1bfc8f | |
Tatsuhiro Tsujikawa | 30bb4eb8f2 | |
Tatsuhiro Tsujikawa | b4cb3b0090 | |
Tatsuhiro Tsujikawa | 2c62572ae1 | |
Tatsuhiro Tsujikawa | 42904a586c | |
Tatsuhiro Tsujikawa | 8538e1ec42 | |
Tatsuhiro Tsujikawa | e6d608b522 | |
Tatsuhiro Tsujikawa | 00a33281be | |
Tatsuhiro Tsujikawa | 7c7ba0586e | |
Tatsuhiro Tsujikawa | 252c425ea6 | |
Fred Sundvik | 525630ae7a | |
Tatsuhiro Tsujikawa | 5195e8be6a | |
Tatsuhiro Tsujikawa | 358c15e015 | |
Tatsuhiro Tsujikawa | b5b18699cb | |
Tatsuhiro Tsujikawa | 44e4475a31 | |
Tatsuhiro Tsujikawa | a945c057c5 | |
Tatsuhiro Tsujikawa | babeddb649 | |
Tatsuhiro Tsujikawa | 2d790edac5 | |
Tatsuhiro Tsujikawa | 2bef60a6f4 | |
Tatsuhiro Tsujikawa | 17e3bb4ec5 | |
Tatsuhiro Tsujikawa | 5e1b1a0883 | |
Tatsuhiro Tsujikawa | 5b0cbb4892 | |
Tatsuhiro Tsujikawa | 17a5ba4969 | |
Tatsuhiro Tsujikawa | 20d95edc57 | |
Tatsuhiro Tsujikawa | 126b5f9d2b | |
Tatsuhiro Tsujikawa | 46602a961d | |
Tatsuhiro Tsujikawa | 00399695cb | |
Tatsuhiro Tsujikawa | f8e014de40 | |
Tatsuhiro Tsujikawa | 172159305c | |
Tatsuhiro Tsujikawa | aa607875b0 | |
Tatsuhiro Tsujikawa | 954d49f7a0 | |
Tatsuhiro Tsujikawa | 5929aeb47c | |
Tatsuhiro Tsujikawa | b990df49d6 | |
Tatsuhiro Tsujikawa | 2aa9d61ae2 | |
Tatsuhiro Tsujikawa | 0fb2c6f4f4 | |
Tatsuhiro Tsujikawa | 1c9817af0d | |
Tatsuhiro Tsujikawa | bea6cae0d5 | |
Tatsuhiro Tsujikawa | 804ce364bf | |
Tatsuhiro Tsujikawa | 83d7fb7fdd | |
Tatsuhiro Tsujikawa | 266a3d84e4 | |
Tatsuhiro Tsujikawa | e91de24be6 | |
Tatsuhiro Tsujikawa | b062e9f66c | |
Tatsuhiro Tsujikawa | f56448be60 | |
Tatsuhiro Tsujikawa | 17aa7b6a61 | |
Tatsuhiro Tsujikawa | 971d3552c7 | |
Tatsuhiro Tsujikawa | ddd40bae06 | |
Tatsuhiro Tsujikawa | cb11cfcd2c | |
Viktor Szakats | 5eed83ee17 | |
Tatsuhiro Tsujikawa | 11632d3c2c | |
Tatsuhiro Tsujikawa | 8c70d9c2e1 | |
Tatsuhiro Tsujikawa | 3b21fbaf03 | |
Tatsuhiro Tsujikawa | 5abafb4268 | |
Tatsuhiro Tsujikawa | 2f71f5c3c9 | |
Tatsuhiro Tsujikawa | 3f65ab7871 | |
Tatsuhiro Tsujikawa | 8e120de5bd | |
Tatsuhiro Tsujikawa | 8a355db8d9 | |
Tatsuhiro Tsujikawa | 93f1096de3 | |
Tatsuhiro Tsujikawa | f190afd0c0 | |
Tatsuhiro Tsujikawa | ebef6b5ced | |
Tatsuhiro Tsujikawa | 6c45e943b0 | |
Tatsuhiro Tsujikawa | 61caf66f1b | |
Tatsuhiro Tsujikawa | c56cda058e | |
Tatsuhiro Tsujikawa | b63705384a | |
Tatsuhiro Tsujikawa | 7380ff3551 | |
Tatsuhiro Tsujikawa | bfba6764e0 | |
Tatsuhiro Tsujikawa | 634e65df64 | |
Tatsuhiro Tsujikawa | 011fbf7f10 | |
Tatsuhiro Tsujikawa | 0363606924 | |
Tatsuhiro Tsujikawa | 40c7922386 | |
Tatsuhiro Tsujikawa | 958d9ac63b | |
Tatsuhiro Tsujikawa | c06f1e9974 | |
Tatsuhiro Tsujikawa | d3381233b1 | |
Tatsuhiro Tsujikawa | 6d88da58f1 | |
Tatsuhiro Tsujikawa | 77449a9477 | |
Tatsuhiro Tsujikawa | 116feb4a8c | |
Tatsuhiro Tsujikawa | dd63d1df42 | |
PufferOverflow | c47fa08b40 | |
Tatsuhiro Tsujikawa | 4bfd802937 |
|
@ -36,8 +36,8 @@ jobs:
|
|||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get install \
|
||||
g++-11 \
|
||||
clang-12 \
|
||||
g++-12 \
|
||||
clang-14 \
|
||||
autoconf \
|
||||
automake \
|
||||
autotools-dev \
|
||||
|
@ -74,8 +74,8 @@ jobs:
|
|||
- name: Setup clang (Linux)
|
||||
if: runner.os == 'Linux' && matrix.compiler == 'clang'
|
||||
run: |
|
||||
echo 'CC=clang-12' >> $GITHUB_ENV
|
||||
echo 'CXX=clang++-12' >> $GITHUB_ENV
|
||||
echo 'CC=clang-14' >> $GITHUB_ENV
|
||||
echo 'CXX=clang++-14' >> $GITHUB_ENV
|
||||
- name: Setup clang (MacOS)
|
||||
if: runner.os == 'macOS' && matrix.compiler == 'clang'
|
||||
run: |
|
||||
|
@ -84,8 +84,8 @@ jobs:
|
|||
- name: Setup gcc (Linux)
|
||||
if: runner.os == 'Linux' && matrix.compiler == 'gcc'
|
||||
run: |
|
||||
echo 'CC=gcc-11' >> $GITHUB_ENV
|
||||
echo 'CXX=g++-11' >> $GITHUB_ENV
|
||||
echo 'CC=gcc-12' >> $GITHUB_ENV
|
||||
echo 'CXX=g++-12' >> $GITHUB_ENV
|
||||
- name: Setup gcc (MacOS)
|
||||
if: runner.os == 'macOS' && matrix.compiler == 'gcc'
|
||||
run: |
|
||||
|
@ -94,7 +94,7 @@ jobs:
|
|||
- name: Build libbpf
|
||||
if: matrix.http3 == 'http3' && matrix.compiler == 'clang' && runner.os == 'Linux'
|
||||
run: |
|
||||
git clone -b v1.0.0 https://github.com/libbpf/libbpf
|
||||
git clone -b v1.0.1 https://github.com/libbpf/libbpf
|
||||
cd libbpf
|
||||
PREFIX=$PWD/build make -C src install
|
||||
|
||||
|
@ -106,7 +106,7 @@ jobs:
|
|||
- name: Build quictls/openssl v1.1.1
|
||||
if: matrix.http3 == 'http3' && matrix.openssl == 'openssl1'
|
||||
run: |
|
||||
git clone --depth 1 -b OpenSSL_1_1_1q+quic https://github.com/quictls/openssl
|
||||
git clone --depth 1 -b OpenSSL_1_1_1s+quic https://github.com/quictls/openssl
|
||||
cd openssl
|
||||
./config --prefix=$PWD/build
|
||||
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
|
||||
|
@ -117,7 +117,7 @@ jobs:
|
|||
unset CPPFLAGS
|
||||
unset LDFLAGS
|
||||
|
||||
git clone --depth 1 -b openssl-3.0.5+quic https://github.com/quictls/openssl
|
||||
git clone --depth 1 -b openssl-3.0.7+quic https://github.com/quictls/openssl
|
||||
cd openssl
|
||||
./config enable-ktls --prefix=$PWD/build --libdir=$PWD/build/lib
|
||||
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
|
||||
|
@ -127,7 +127,7 @@ jobs:
|
|||
run: |
|
||||
git clone https://boringssl.googlesource.com/boringssl
|
||||
cd boringssl
|
||||
git checkout 04989786e9ab16cef5261bbd05a2b1a8cb312dbf
|
||||
git checkout 31bad2514d21f6207f3925ba56754611c462a873
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON ..
|
||||
|
@ -148,7 +148,7 @@ jobs:
|
|||
- name: Build nghttp3
|
||||
if: matrix.http3 == 'http3'
|
||||
run: |
|
||||
git clone --depth 1 -b v0.7.1 https://github.com/ngtcp2/nghttp3
|
||||
git clone --depth 1 -b v0.8.0 https://github.com/ngtcp2/nghttp3
|
||||
cd nghttp3
|
||||
autoreconf -i
|
||||
./configure --prefix=$PWD/build --enable-lib-only
|
||||
|
@ -157,7 +157,7 @@ jobs:
|
|||
- name: Build ngtcp2
|
||||
if: matrix.http3 == 'http3'
|
||||
run: |
|
||||
git clone --depth 1 -b v0.9.0 https://github.com/ngtcp2/ngtcp2
|
||||
git clone --depth 1 -b v0.12.0 https://github.com/ngtcp2/ngtcp2
|
||||
cd ngtcp2
|
||||
autoreconf -i
|
||||
./configure --prefix=$PWD/build --enable-lib-only PKG_CONFIG_PATH="../openssl/build/lib/pkgconfig" $EXTRA_NGTCP2_OPTS
|
||||
|
|
|
@ -54,4 +54,6 @@ _VC_ROOT/
|
|||
.depend.MSVC
|
||||
*.pyd
|
||||
*.egg-info/
|
||||
python/nghttp2.c
|
||||
|
||||
release
|
||||
libnghttp2.lha
|
1
AUTHORS
1
AUTHORS
|
@ -96,6 +96,7 @@ Pedro Santos
|
|||
Peeyush Aggarwal
|
||||
Peter Wu
|
||||
Piotr Sikora
|
||||
PufferOverflow
|
||||
Raul Gutierrez Segales
|
||||
Remo E
|
||||
Renaud
|
||||
|
|
|
@ -24,12 +24,12 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
# XXX using 1.8.90 instead of 1.9.0-DEV
|
||||
project(nghttp2 VERSION 1.50.0)
|
||||
project(nghttp2 VERSION 1.51.90)
|
||||
|
||||
# See versioning rule:
|
||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
set(LT_CURRENT 38)
|
||||
set(LT_REVISION 0)
|
||||
set(LT_REVISION 1)
|
||||
set(LT_AGE 24)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||
|
@ -52,9 +52,8 @@ endif()
|
|||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# For Python bindings and documentation
|
||||
# (Must be called before PythonLibs for matching versions.)
|
||||
find_package(PythonInterp)
|
||||
# For documentation
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
|
||||
# Auto-detection of features that can be toggled
|
||||
find_package(OpenSSL 1.0.1)
|
||||
|
@ -82,15 +81,8 @@ find_package(Systemd 209)
|
|||
find_package(Jansson 2.5)
|
||||
set(ENABLE_HPACK_TOOLS_DEFAULT ${JANSSON_FOUND})
|
||||
# 2.0.8 is required because we use evconnlistener_set_error_cb()
|
||||
find_package(Libevent 2.0.8 COMPONENTS libevent openssl)
|
||||
find_package(Libevent 2.0.8 COMPONENTS core extra openssl)
|
||||
set(ENABLE_EXAMPLES_DEFAULT ${LIBEVENT_OPENSSL_FOUND})
|
||||
find_package(Cython)
|
||||
find_package(PythonLibs)
|
||||
if(CYTHON_FOUND AND PYTHONLIBS_FOUND)
|
||||
set(ENABLE_PYTHON_BINDINGS_DEFAULT ON)
|
||||
else()
|
||||
set(ENABLE_PYTHON_BINDINGS_DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
find_package(LibXml2 2.6.26)
|
||||
set(WITH_LIBXML2_DEFAULT ${LIBXML2_FOUND})
|
||||
|
@ -99,8 +91,7 @@ set(WITH_JEMALLOC_DEFAULT ${JEMALLOC_FOUND})
|
|||
|
||||
include(CMakeOptions.txt)
|
||||
|
||||
if(ENABLE_LIB_ONLY AND (ENABLE_APP OR ENABLE_HPACK_TOOLS OR ENABLE_EXAMPLES OR
|
||||
ENABLE_PYTHON_BINDINGS))
|
||||
if(ENABLE_LIB_ONLY AND (ENABLE_APP OR ENABLE_HPACK_TOOLS OR ENABLE_EXAMPLES))
|
||||
# Remember when disabled options are disabled for later diagnostics.
|
||||
set(ENABLE_LIB_ONLY_DISABLED_OTHERS 1)
|
||||
else()
|
||||
|
@ -110,7 +101,6 @@ if(ENABLE_LIB_ONLY)
|
|||
set(ENABLE_APP OFF)
|
||||
set(ENABLE_HPACK_TOOLS OFF)
|
||||
set(ENABLE_EXAMPLES OFF)
|
||||
set(ENABLE_PYTHON_BINDINGS OFF)
|
||||
endif()
|
||||
|
||||
# Do not disable assertions based on CMAKE_BUILD_TYPE.
|
||||
|
@ -156,20 +146,6 @@ cmake_pop_check_state()
|
|||
# Additional libraries required for programs under src directory.
|
||||
set(APP_LIBRARIES)
|
||||
|
||||
if(ENABLE_PYTHON_BINDINGS)
|
||||
if(NOT (CYTHON_FOUND AND PYTHONLIBS_FOUND))
|
||||
message(FATAL_ERROR "python bindings were requested "
|
||||
"(ENABLE_PYTHON_BINDINGS=1) but dependencies are not met.")
|
||||
endif()
|
||||
if(NOT PYTHON_VERSION_STRING STREQUAL PYTHONLIBS_VERSION_STRING)
|
||||
message(FATAL_ERROR
|
||||
"Python executable and library must have the same version!"
|
||||
" Found Python ${PYTHON_VERSION_STRING} and"
|
||||
" PythonLibs ${PYTHONLIBS_VERSION_STRING}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD 1)
|
||||
find_package(Threads)
|
||||
if(CMAKE_USE_PTHREADS_INIT)
|
||||
|
@ -243,10 +219,6 @@ endif()
|
|||
# jemalloc
|
||||
set(HAVE_JEMALLOC ${JEMALLOC_FOUND})
|
||||
|
||||
if(ENABLE_ASIO_LIB)
|
||||
find_package(Boost 1.54.0 REQUIRED system thread)
|
||||
endif()
|
||||
|
||||
# libbpf (for bpf)
|
||||
set(HAVE_LIBBPF ${LIBBPF_FOUND})
|
||||
if(LIBBPF_FOUND)
|
||||
|
@ -277,13 +249,13 @@ if(ENABLE_HPACK_TOOLS AND NOT HAVE_JANSSON)
|
|||
message(FATAL_ERROR "HPACK tools were requested (ENABLE_HPACK_TOOLS=1) but dependencies are not met.")
|
||||
endif()
|
||||
|
||||
# C++ library libnghttp2_asio
|
||||
# examples
|
||||
if(ENABLE_EXAMPLES AND NOT (OPENSSL_FOUND AND LIBEVENT_OPENSSL_FOUND))
|
||||
message(FATAL_ERROR "examples were requested (ENABLE_EXAMPLES=1) but dependencies are not met.")
|
||||
endif()
|
||||
|
||||
# third-party http-parser only be built when needed
|
||||
if(ENABLE_EXAMPLES OR ENABLE_APP OR ENABLE_HPACK_TOOLS OR ENABLE_ASIO_LIB)
|
||||
if(ENABLE_EXAMPLES OR ENABLE_APP OR ENABLE_HPACK_TOOLS)
|
||||
set(ENABLE_THIRD_PARTY 1)
|
||||
# mruby (for src/nghttpx)
|
||||
set(HAVE_MRUBY ${WITH_MRUBY})
|
||||
|
@ -467,8 +439,6 @@ set(sbindir "${CMAKE_INSTALL_FULL_SBINDIR}")
|
|||
foreach(name
|
||||
lib/libnghttp2.pc
|
||||
lib/includes/nghttp2/nghttp2ver.h
|
||||
src/libnghttp2_asio.pc
|
||||
python/setup.py
|
||||
integration-tests/config.go
|
||||
integration-tests/setenv
|
||||
doc/conf.py
|
||||
|
@ -479,14 +449,9 @@ foreach(name
|
|||
doc/tutorial-hpack.rst
|
||||
doc/nghttpx-howto.rst
|
||||
doc/h2load-howto.rst
|
||||
doc/libnghttp2_asio.rst
|
||||
doc/python-apiref.rst
|
||||
doc/building-android-binary.rst
|
||||
doc/nghttp2.h.rst
|
||||
doc/nghttp2ver.h.rst
|
||||
doc/asio_http2.h.rst
|
||||
doc/asio_http2_server.h.rst
|
||||
doc/asio_http2_client.h.rst
|
||||
doc/contribute.rst
|
||||
)
|
||||
configure_file("${name}.in" "${name}" @ONLY)
|
||||
|
@ -509,9 +474,7 @@ add_subdirectory(lib)
|
|||
#add_subdirectory(lib/includes)
|
||||
add_subdirectory(third-party)
|
||||
add_subdirectory(src)
|
||||
#add_subdirectory(src/includes)
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(python)
|
||||
add_subdirectory(tests)
|
||||
#add_subdirectory(tests/testdata)
|
||||
add_subdirectory(integration-tests)
|
||||
|
@ -539,10 +502,8 @@ message(STATUS "summary of build options:
|
|||
WARNCFLAGS: ${WARNCFLAGS}
|
||||
CXX1XCXXFLAGS: ${CXX1XCXXFLAGS}
|
||||
Python:
|
||||
Python: ${PYTHON_EXECUTABLE}
|
||||
PYTHON_VERSION: ${PYTHON_VERSION_STRING}
|
||||
Library version:${PYTHONLIBS_VERSION_STRING}
|
||||
Cython: ${CYTHON_EXECUTABLE}
|
||||
Python: ${Python3_EXECUTABLE}
|
||||
Python3_VERSION: ${Python3_VERSION}
|
||||
Test:
|
||||
CUnit: ${HAVE_CUNIT} (LIBS='${CUNIT_LIBRARIES}')
|
||||
Failmalloc: ${ENABLE_FAILMALLOC}
|
||||
|
@ -560,8 +521,6 @@ message(STATUS "summary of build options:
|
|||
Jemalloc: ${HAVE_JEMALLOC} (LIBS='${JEMALLOC_LIBRARIES}')
|
||||
Zlib: ${HAVE_ZLIB} (LIBS='${ZLIB_LIBRARIES}')
|
||||
Systemd: ${HAVE_SYSTEMD} (LIBS='${SYSTEMD_LIBRARIES}')
|
||||
Boost::System: ${Boost_SYSTEM_LIBRARY}
|
||||
Boost::Thread: ${Boost_THREAD_LIBRARY}
|
||||
Third-party:
|
||||
http-parser: ${ENABLE_THIRD_PARTY}
|
||||
MRuby: ${HAVE_MRUBY}
|
||||
|
@ -569,9 +528,7 @@ message(STATUS "summary of build options:
|
|||
Features:
|
||||
Applications: ${ENABLE_APP}
|
||||
HPACK tools: ${ENABLE_HPACK_TOOLS}
|
||||
Libnghttp2_asio:${ENABLE_ASIO_LIB}
|
||||
Examples: ${ENABLE_EXAMPLES}
|
||||
Python bindings:${ENABLE_PYTHON_BINDINGS}
|
||||
Threading: ${ENABLE_THREADS}
|
||||
HTTP/3(EXPERIMENTAL): ${ENABLE_HTTP3}
|
||||
")
|
||||
|
|
|
@ -7,13 +7,10 @@ option(ENABLE_APP "Build applications (nghttp, nghttpd, nghttpx and h2load
|
|||
${ENABLE_APP_DEFAULT})
|
||||
option(ENABLE_HPACK_TOOLS "Build HPACK tools"
|
||||
${ENABLE_HPACK_TOOLS_DEFAULT})
|
||||
option(ENABLE_ASIO_LIB "Build C++ libnghttp2_asio library")
|
||||
option(ENABLE_EXAMPLES "Build examples"
|
||||
${ENABLE_EXAMPLES_DEFAULT})
|
||||
option(ENABLE_PYTHON_BINDINGS "Build Python bindings"
|
||||
${ENABLE_PYTHON_BINDINGS_DEFAULT})
|
||||
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 -DENABLE_PYTHON_BINDINGS=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(ENABLE_SHARED_LIB "Build libnghttp2 as a shared library" ON)
|
||||
option(ENABLE_STATIC_CRT "Build libnghttp2 against the MS LIBCMT[d]")
|
||||
|
|
|
@ -12,59 +12,41 @@
|
|||
|
||||
|
||||
# Only use standalone-toolchain for reduce size
|
||||
FROM ubuntu:xenial
|
||||
FROM ubuntu:22.04
|
||||
MAINTAINER Tatsuhiro Tsujikawa
|
||||
ENV ANDROID_HOME /root
|
||||
ENV TOOLCHAIN $ANDROID_HOME/toolchain
|
||||
ENV PATH $TOOLCHAIN/bin:$PATH
|
||||
|
||||
ENV NDK_VERSION r14b
|
||||
ENV NDK_VERSION r25b
|
||||
ENV NDK /root/android-ndk-$NDK_VERSION
|
||||
ENV TOOLCHAIN $NDK/toolchains/llvm/prebuilt/linux-x86_64
|
||||
ENV TARGET aarch64-linux-android
|
||||
ENV API 33
|
||||
ENV AR $TOOLCHAIN/bin/llvm-ar
|
||||
ENV CC $TOOLCHAIN/bin/$TARGET$API-clang
|
||||
ENV CXX $TOOLCHAIN/bin/$TARGET$API-clang++
|
||||
ENV LD $TOOLCHAIN/bin/ld
|
||||
ENV RANDLIB $TOOLCHAIN/bin/llvm-ranlib
|
||||
ENV STRIP $TOOLCHAIN/bin/llvm-strip
|
||||
ENV PREFIX /root/usr/local
|
||||
|
||||
WORKDIR /root
|
||||
RUN apt-get update && \
|
||||
apt-get install -y unzip make binutils autoconf \
|
||||
automake autotools-dev libtool pkg-config git \
|
||||
curl dpkg-dev libxml2-dev genisoimage libc6-i386 \
|
||||
lib32stdc++6 python&& \
|
||||
rm -rf /var/cache/apk/*
|
||||
lib32stdc++6 && \
|
||||
rm -rf /var/cache/apt/*
|
||||
|
||||
# Install toolchain
|
||||
RUN curl -L -O https://dl.google.com/android/repository/android-ndk-$NDK_VERSION-linux-x86_64.zip && \
|
||||
unzip -q android-ndk-$NDK_VERSION-linux-x86_64.zip && \
|
||||
rm android-ndk-$NDK_VERSION-linux-x86_64.zip && \
|
||||
mkdir -p $ANDROID_HOME/toolchain && \
|
||||
$ANDROID_HOME/android-ndk-$NDK_VERSION/build/tools/make-standalone-toolchain.sh \
|
||||
--install-dir=$ANDROID_HOME/toolchain \
|
||||
--toolchain=arm-linux-androideabi-4.9 \
|
||||
--force && \
|
||||
rm -r android-ndk-$NDK_VERSION
|
||||
|
||||
ENV PREFIX /root/usr/local
|
||||
# Download NDK
|
||||
RUN curl -L -O https://dl.google.com/android/repository/android-ndk-$NDK_VERSION-linux.zip && \
|
||||
unzip -q android-ndk-$NDK_VERSION-linux.zip && \
|
||||
rm android-ndk-$NDK_VERSION-linux.zip
|
||||
|
||||
# Setup version of libraries
|
||||
ENV OPENSSL_VERSION 1.0.2d
|
||||
ENV SPDYLAY_VERSION v1.4.0
|
||||
ENV LIBEV_VERSION 4.19
|
||||
ENV ZLIB_VERSION 1.2.8
|
||||
ENV CARES_VERSION 1.13.0
|
||||
ENV NGHTTP2_VERSION v1.24.0
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN git clone https://github.com/tatsuhiro-t/spdylay -b $SPDYLAY_VERSION --depth 1
|
||||
WORKDIR /root/build/spdylay
|
||||
RUN autoreconf -i && \
|
||||
./configure \
|
||||
--disable-shared \
|
||||
--host=arm-linux-androideabi \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
--without-libxml2 \
|
||||
--disable-src \
|
||||
--disable-examples \
|
||||
CPPFLAGS="-I$PREFIX/include" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||
LDFLAGS="-L$PREFIX/lib" && \
|
||||
make install
|
||||
ENV OPENSSL_VERSION 1.1.1q
|
||||
ENV LIBEV_VERSION 4.33
|
||||
ENV ZLIB_VERSION 1.2.13
|
||||
ENV CARES_VERSION 1.18.1
|
||||
ENV NGHTTP2_VERSION master
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN curl -L -O https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz && \
|
||||
|
@ -72,20 +54,18 @@ RUN curl -L -O https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz &&
|
|||
rm openssl-$OPENSSL_VERSION.tar.gz
|
||||
|
||||
WORKDIR /root/build/openssl-$OPENSSL_VERSION
|
||||
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
|
||||
./Configure --prefix=$PREFIX android && \
|
||||
RUN export ANDROID_NDK_HOME=$NDK PATH=$TOOLCHAIN/bin:$PATH && \
|
||||
./Configure no-shared --prefix=$PREFIX android-arm64 && \
|
||||
make && make install_sw
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN curl -L -O http://dist.schmorp.de/libev/Attic/libev-$LIBEV_VERSION.tar.gz && \
|
||||
curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch && \
|
||||
tar xf libev-$LIBEV_VERSION.tar.gz && \
|
||||
rm libev-$LIBEV_VERSION.tar.gz
|
||||
|
||||
WORKDIR /root/build/libev-$LIBEV_VERSION
|
||||
RUN patch -p1 < ../libev-4.19-android.patch && \
|
||||
./configure \
|
||||
--host=arm-linux-androideabi \
|
||||
RUN ./configure \
|
||||
--host=$TARGET \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
--disable-shared \
|
||||
|
@ -95,17 +75,12 @@ RUN patch -p1 < ../libev-4.19-android.patch && \
|
|||
make install
|
||||
|
||||
WORKDIR /root/build
|
||||
RUN curl -L -O https://downloads.sourceforge.net/project/libpng/zlib/$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz && \
|
||||
RUN curl -L -O https://zlib.net/zlib-$ZLIB_VERSION.tar.gz && \
|
||||
tar xf zlib-$ZLIB_VERSION.tar.gz && \
|
||||
rm zlib-$ZLIB_VERSION.tar.gz
|
||||
|
||||
WORKDIR /root/build/zlib-$ZLIB_VERSION
|
||||
RUN HOST=arm-linux-androideabi \
|
||||
CC=$HOST-gcc \
|
||||
AR=$HOST-ar \
|
||||
LD=$HOST-ld \
|
||||
RANLIB=$HOST-ranlib \
|
||||
STRIP=$HOST-strip \
|
||||
RUN HOST=$TARGET \
|
||||
./configure \
|
||||
--prefix=$PREFIX \
|
||||
--libdir=$PREFIX/lib \
|
||||
|
@ -121,7 +96,7 @@ RUN curl -L -O https://c-ares.haxx.se/download/c-ares-$CARES_VERSION.tar.gz && \
|
|||
|
||||
WORKDIR /root/build/c-ares-$CARES_VERSION
|
||||
RUN ./configure \
|
||||
--host=arm-linux-androideabi \
|
||||
--host=$TARGET \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
--disable-shared && \
|
||||
|
@ -134,17 +109,13 @@ RUN autoreconf -i && \
|
|||
./configure \
|
||||
--enable-app \
|
||||
--disable-shared \
|
||||
--host=arm-linux-androideabi \
|
||||
--host=$TARGET \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--with-xml-prefix="$PREFIX" \
|
||||
--without-libxml2 \
|
||||
--disable-python-bindings \
|
||||
--disable-examples \
|
||||
--disable-threads \
|
||||
CC="$TOOLCHAIN"/bin/arm-linux-androideabi-clang \
|
||||
CXX="$TOOLCHAIN"/bin/arm-linux-androideabi-clang++ \
|
||||
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||
LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
|
||||
make && \
|
||||
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp
|
||||
$STRIP src/nghttpx src/nghttpd src/nghttp
|
||||
|
|
12
Makefile.am
12
Makefile.am
|
@ -20,19 +20,14 @@
|
|||
# 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.
|
||||
SUBDIRS = lib third-party src bpf examples python tests integration-tests \
|
||||
SUBDIRS = lib third-party src bpf examples tests integration-tests \
|
||||
doc contrib script
|
||||
|
||||
# Now with python setuptools, make uninstall will leave many files we
|
||||
# cannot easily remove (e.g., easy-install.pth). Disable it for
|
||||
# distcheck rule.
|
||||
AM_DISTCHECK_CONFIGURE_FLAGS = --disable-python-bindings
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
dist_doc_DATA = README.rst
|
||||
|
||||
EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make \
|
||||
EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-env \
|
||||
Dockerfile.android \
|
||||
cmakeconfig.h.in \
|
||||
CMakeLists.txt \
|
||||
|
@ -42,7 +37,6 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make \
|
|||
cmake/FindLibev.cmake \
|
||||
cmake/FindCUnit.cmake \
|
||||
cmake/Version.cmake \
|
||||
cmake/FindCython.cmake \
|
||||
cmake/FindLibevent.cmake \
|
||||
cmake/FindJansson.cmake \
|
||||
cmake/FindLibcares.cmake \
|
||||
|
@ -61,5 +55,5 @@ clang-format:
|
|||
CLANGFORMAT=`git config --get clangformat.binary`; \
|
||||
test -z $${CLANGFORMAT} && CLANGFORMAT="clang-format"; \
|
||||
$${CLANGFORMAT} -i lib/*.{c,h} lib/includes/nghttp2/*.h \
|
||||
src/*.{c,cc,h} src/includes/nghttp2/*.h examples/*.{c,cc} \
|
||||
src/*.{c,cc,h} examples/*.{c,cc} \
|
||||
tests/*.{c,h} bpf/*.c fuzz/*.cc
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
USE_CLIB2=YES
|
||||
ifeq ($(USE_CLIB2), YES)
|
||||
LIBC=clib2
|
||||
else
|
||||
LIBC=newlib
|
||||
endif
|
||||
|
||||
all: build
|
||||
|
||||
init:
|
||||
git submodule update --init
|
||||
autoreconf -i
|
||||
automake
|
||||
autoconf
|
||||
|
||||
build: init
|
||||
CC="ppc-amigaos-gcc" CFLAGS="-mcrt=${LIBC} -fPIC" LDFLAGS="-mcrt=${LIBC}" CXXFLAGS="-mcrt=${LIBC} -fPIC" ./configure --host=ppc-amigaos && \
|
||||
make -j$(shell nproc)
|
||||
|
||||
clean:
|
||||
make -f Makefile clean
|
||||
rm -rf autom4te.cache
|
||||
rm compile config.guess config.h config.h.in config.log config.status config.sub configure depcomp install-sh libtool ltmain.sh missing stamp-h1 test-driver INSTALL Makefile Makefile.in *.m4
|
||||
|
||||
release:
|
||||
mkdir -p release/local/common/include/nghttp2
|
||||
mkdir -p release/local/clib2/lib
|
||||
mkdir -p release/local/newlib/lib
|
||||
make -f Makefile.os4 USE_CLIB2=YES
|
||||
cp ./lib/.libs/libnghttp2.a ./lib/.libs/libnghttp2.la release/local/clib2/lib/
|
||||
cp ./lib/includes/nghttp2/* release/local/common/include/nghttp2/
|
||||
make -f Makefile.os4 clean
|
||||
make -f Makefile.os4 USE_CLIB2=NO
|
||||
cp ./lib/.libs/libnghttp2.a ./lib/.libs/libnghttp2.la ./lib/.libs/libnghttp2.so release/local/newlib/lib/
|
||||
lha -aeq libnghttp2.lha release/
|
280
README.rst
280
README.rst
|
@ -14,9 +14,11 @@ An HPACK encoder and decoder are available as a public API.
|
|||
Development Status
|
||||
------------------
|
||||
|
||||
We have implemented `RFC 7540 <https://tools.ietf.org/html/rfc7540>`_
|
||||
HTTP/2 and `RFC 7541 <https://tools.ietf.org/html/rfc7541>`_ HPACK -
|
||||
Header Compression for HTTP/2
|
||||
nghttp2 was originally developed based on `RFC 7540
|
||||
<https://tools.ietf.org/html/rfc7540>`_ HTTP/2 and `RFC 7541
|
||||
<https://tools.ietf.org/html/rfc7541>`_ HPACK - Header Compression for
|
||||
HTTP/2. Now we are updating our code to implement `RFC 9113
|
||||
<https://datatracker.ietf.org/doc/html/rfc9113>`_.
|
||||
|
||||
The nghttp2 code base was forked from the spdylay
|
||||
(https://github.com/tatsuhiro-t/spdylay) project.
|
||||
|
@ -101,29 +103,6 @@ To mitigate heap fragmentation in long running server programs
|
|||
Alpine Linux currently does not support malloc replacement
|
||||
due to musl limitations. See details in issue `#762 <https://github.com/nghttp2/nghttp2/issues/762>`_.
|
||||
|
||||
libnghttp2_asio C++ library (deprecated, has moved to
|
||||
https://github.com/nghttp2/nghttp2-asio) requires the following
|
||||
packages:
|
||||
|
||||
* libboost-dev >= 1.54.0
|
||||
* libboost-thread-dev >= 1.54.0
|
||||
|
||||
The Python bindings (deprecated) require the following packages:
|
||||
|
||||
* cython >= 0.19
|
||||
* python >= 3.8
|
||||
* python-setuptools
|
||||
|
||||
If you are using Ubuntu 16.04 LTS (Xenial Xerus) or Debian 8 (jessie)
|
||||
and above, run the following to install the required packages:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
sudo apt-get install g++ make binutils autoconf automake autotools-dev libtool pkg-config \
|
||||
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \
|
||||
libc-ares-dev libjemalloc-dev libsystemd-dev \
|
||||
cython python3-dev python-setuptools
|
||||
|
||||
To enable mruby support for nghttpx, `mruby
|
||||
<https://github.com/mruby/mruby>`_ is required. We need to build
|
||||
mruby with C++ ABI explicitly turned on, and probably need other
|
||||
|
@ -148,10 +127,10 @@ To enable the experimental HTTP/3 support for h2load and nghttpx, the
|
|||
following libraries are required:
|
||||
|
||||
* `OpenSSL with QUIC support
|
||||
<https://github.com/quictls/openssl/tree/OpenSSL_1_1_1q+quic>`_; or
|
||||
<https://github.com/quictls/openssl/tree/OpenSSL_1_1_1s+quic>`_; or
|
||||
`BoringSSL <https://boringssl.googlesource.com/boringssl/>`_ (commit
|
||||
04989786e9ab16cef5261bbd05a2b1a8cb312dbf)
|
||||
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 0.9.0
|
||||
31bad2514d21f6207f3925ba56754611c462a873)
|
||||
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 0.10.0
|
||||
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 0.7.0
|
||||
|
||||
Use ``--enable-http3`` configure option to enable HTTP/3 feature for
|
||||
|
@ -167,7 +146,7 @@ Use ``--with-libbpf`` configure option to build eBPF program.
|
|||
libelf-dev is needed to build libbpf.
|
||||
|
||||
For Ubuntu 20.04, you can build libbpf from `the source code
|
||||
<https://github.com/libbpf/libbpf/releases/tag/v1.0.0>`_. nghttpx
|
||||
<https://github.com/libbpf/libbpf/releases/tag/v1.0.1>`_. nghttpx
|
||||
requires eBPF program for reloading its configuration and hot swapping
|
||||
its executable.
|
||||
|
||||
|
@ -221,6 +200,18 @@ language features.
|
|||
responsible to specify the correct values to these variables. For
|
||||
complete list of these variables, run ``./configure -h``.
|
||||
|
||||
If you are using Ubuntu 22.04 LTS, run the following to install the
|
||||
required packages:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
sudo apt-get install g++ clang make binutils autoconf automake \
|
||||
autotools-dev libtool pkg-config \
|
||||
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev \
|
||||
libevent-dev libjansson-dev \
|
||||
libc-ares-dev libjemalloc-dev libsystemd-dev \
|
||||
ruby-dev bison libelf-dev
|
||||
|
||||
Building nghttp2 from release tar archive
|
||||
-----------------------------------------
|
||||
|
||||
|
@ -352,7 +343,7 @@ Build custom OpenSSL:
|
|||
|
||||
.. code-block:: text
|
||||
|
||||
$ git clone --depth 1 -b OpenSSL_1_1_1q+quic https://github.com/quictls/openssl
|
||||
$ git clone --depth 1 -b OpenSSL_1_1_1s+quic https://github.com/quictls/openssl
|
||||
$ cd openssl
|
||||
$ ./config --prefix=$PWD/build --openssldir=/etc/ssl
|
||||
$ make -j$(nproc)
|
||||
|
@ -363,7 +354,7 @@ Build nghttp3:
|
|||
|
||||
.. code-block:: text
|
||||
|
||||
$ git clone --depth 1 -b v0.7.1 https://github.com/ngtcp2/nghttp3
|
||||
$ git clone --depth 1 -b v0.8.0 https://github.com/ngtcp2/nghttp3
|
||||
$ cd nghttp3
|
||||
$ autoreconf -i
|
||||
$ ./configure --prefix=$PWD/build --enable-lib-only
|
||||
|
@ -375,7 +366,7 @@ Build ngtcp2:
|
|||
|
||||
.. code-block:: text
|
||||
|
||||
$ git clone --depth 1 -b v0.9.0 https://github.com/ngtcp2/ngtcp2
|
||||
$ git clone --depth 1 -b v0.12.0 https://github.com/ngtcp2/ngtcp2
|
||||
$ cd ngtcp2
|
||||
$ autoreconf -i
|
||||
$ ./configure --prefix=$PWD/build --enable-lib-only \
|
||||
|
@ -389,7 +380,7 @@ from source:
|
|||
|
||||
.. code-block:: text
|
||||
|
||||
$ git clone --depth 1 -b v1.0.0 https://github.com/libbpf/libbpf
|
||||
$ git clone --depth 1 -b v1.0.1 https://github.com/libbpf/libbpf
|
||||
$ cd libbpf
|
||||
$ PREFIX=$PWD/build make -C src install
|
||||
$ cd ..
|
||||
|
@ -403,8 +394,7 @@ Build nghttp2:
|
|||
$ git submodule update --init
|
||||
$ autoreconf -i
|
||||
$ ./configure --with-mruby --with-neverbleed --enable-http3 --with-libbpf \
|
||||
--disable-python-bindings \
|
||||
CC=clang-12 CXX=clang++-12 \
|
||||
CC=clang-14 CXX=clang++-14 \
|
||||
PKG_CONFIG_PATH="$PWD/../openssl/build/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"
|
||||
$ make -j$(nproc)
|
||||
|
@ -1428,224 +1418,6 @@ associated value includes the state of the dynamic header table after the
|
|||
corresponding header set was processed. The format is the same as
|
||||
``deflatehd``.
|
||||
|
||||
libnghttp2_asio: High level HTTP/2 C++ library
|
||||
----------------------------------------------
|
||||
|
||||
libnghttp2_asio has been deprecated, and moved to
|
||||
https://github.com/nghttp2/nghttp2-asio.
|
||||
|
||||
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
|
||||
high level abstraction API to build HTTP/2 applications. It depends
|
||||
on the Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
|
||||
provides both client and server APIs.
|
||||
|
||||
libnghttp2_asio is not built by default. Use the ``--enable-asio-lib``
|
||||
configure flag to build libnghttp2_asio. The required Boost libraries
|
||||
are:
|
||||
|
||||
* Boost::Asio
|
||||
* Boost::System
|
||||
* Boost::Thread
|
||||
|
||||
The server API is designed to build an HTTP/2 server very easily to utilize
|
||||
C++14 anonymous functions and closures. The bare minimum example of
|
||||
an HTTP/2 server looks like this:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
boost::system::error_code ec;
|
||||
http2 server;
|
||||
|
||||
server.handle("/", [](const request &req, const response &res) {
|
||||
res.write_head(200);
|
||||
res.end("hello, world\n");
|
||||
});
|
||||
|
||||
if (server.listen_and_serve(ec, "localhost", "3000")) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Here is sample code to use the client API:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::client;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
boost::system::error_code ec;
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
// connect to localhost:3000
|
||||
session sess(io_service, "localhost", "3000");
|
||||
|
||||
sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
|
||||
boost::system::error_code ec;
|
||||
|
||||
auto req = sess.submit(ec, "GET", "http://localhost:3000/");
|
||||
|
||||
req->on_response([](const response &res) {
|
||||
// print status code and response header fields.
|
||||
std::cerr << "HTTP/2 " << res.status_code() << std::endl;
|
||||
for (auto &kv : res.header()) {
|
||||
std::cerr << kv.first << ": " << kv.second.value << "\n";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
res.on_data([](const uint8_t *data, std::size_t len) {
|
||||
std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
std::cerr << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
req->on_close([&sess](uint32_t error_code) {
|
||||
// shutdown session after first request was done.
|
||||
sess.shutdown();
|
||||
});
|
||||
});
|
||||
|
||||
sess.on_error([](const boost::system::error_code &ec) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
});
|
||||
|
||||
io_service.run();
|
||||
}
|
||||
|
||||
For more details, see the documentation of libnghttp2_asio.
|
||||
|
||||
Python bindings
|
||||
---------------
|
||||
|
||||
Python bindings have been deprecated.
|
||||
|
||||
The ``python`` directory contains nghttp2 Python bindings. The
|
||||
bindings currently provide HPACK compressor and decompressor classes
|
||||
and an HTTP/2 server.
|
||||
|
||||
The extension module is called ``nghttp2``.
|
||||
|
||||
``make`` will build the bindings and target Python version is
|
||||
determined by the ``configure`` script. If the detected Python version is not
|
||||
what you expect, specify a path to Python executable in a ``PYTHON``
|
||||
variable as an argument to configure script (e.g., ``./configure
|
||||
PYTHON=/usr/bin/python3.8``).
|
||||
|
||||
The following example code illustrates basic usage of the HPACK compressor
|
||||
and decompressor in Python:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import binascii
|
||||
import nghttp2
|
||||
|
||||
deflater = nghttp2.HDDeflater()
|
||||
inflater = nghttp2.HDInflater()
|
||||
|
||||
data = deflater.deflate([(b'foo', b'bar'),
|
||||
(b'baz', b'buz')])
|
||||
print(binascii.b2a_hex(data))
|
||||
|
||||
hdrs = inflater.inflate(data)
|
||||
print(hdrs)
|
||||
|
||||
The ``nghttp2.HTTP2Server`` class builds on top of the asyncio event
|
||||
loop. On construction, *RequestHandlerClass* must be given, which
|
||||
must be a subclass of ``nghttp2.BaseRequestHandler`` class.
|
||||
|
||||
The ``BaseRequestHandler`` class is used to handle the HTTP/2 stream.
|
||||
By default, it does nothing. It must be subclassed to handle each
|
||||
event callback method.
|
||||
|
||||
The first callback method invoked is ``on_headers()``. It is called
|
||||
when HEADERS frame, which includes the request header fields, has arrived.
|
||||
|
||||
If the request has a request body, ``on_data(data)`` is invoked for each
|
||||
chunk of received data.
|
||||
|
||||
Once the entire request is received, ``on_request_done()`` is invoked.
|
||||
|
||||
When the stream is closed, ``on_close(error_code)`` is called.
|
||||
|
||||
The application can send a response using ``send_response()`` method.
|
||||
It can be used in ``on_headers()``, ``on_data()`` or
|
||||
``on_request_done()``.
|
||||
|
||||
The application can push resources using the ``push()`` method. It must be
|
||||
used before the ``send_response()`` call.
|
||||
|
||||
The following instance variables are available:
|
||||
|
||||
client_address
|
||||
Contains a tuple of the form (host, port) referring to the
|
||||
client's address.
|
||||
|
||||
stream_id
|
||||
Stream ID of this stream.
|
||||
|
||||
scheme
|
||||
Scheme of the request URI. This is a value of :scheme header
|
||||
field.
|
||||
|
||||
method
|
||||
Method of this stream. This is a value of :method header field.
|
||||
|
||||
host
|
||||
This is a value of :authority or host header field.
|
||||
|
||||
path
|
||||
This is a value of :path header field.
|
||||
|
||||
The following example illustrates the HTTP2Server and
|
||||
BaseRequestHandler usage:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import io, ssl
|
||||
import nghttp2
|
||||
|
||||
class Handler(nghttp2.BaseRequestHandler):
|
||||
|
||||
def on_headers(self):
|
||||
self.push(path='/css/bootstrap.css',
|
||||
request_headers = [('content-length', '3')],
|
||||
status=200,
|
||||
body='foo')
|
||||
|
||||
self.push(path='/js/bootstrap.js',
|
||||
method='GET',
|
||||
request_headers = [('content-length', '10')],
|
||||
status=200,
|
||||
body='foobarbuzz')
|
||||
|
||||
self.send_response(status=200,
|
||||
headers = [('content-type', 'text/plain')],
|
||||
body=io.BytesIO(b'nghttp2-python FTW'))
|
||||
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2
|
||||
ctx.load_cert_chain('server.crt', 'server.key')
|
||||
|
||||
# give None to ssl to make the server non-SSL/TLS
|
||||
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
|
||||
server.serve_forever()
|
||||
|
||||
Contribution
|
||||
------------
|
||||
|
||||
|
|
|
@ -23,25 +23,15 @@
|
|||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
echo 'No $ANDROID_HOME specified.'
|
||||
exit 1
|
||||
fi
|
||||
PREFIX="$ANDROID_HOME"/usr/local
|
||||
TOOLCHAIN="$ANDROID_HOME"/toolchain
|
||||
PATH="$TOOLCHAIN"/bin:"$PATH"
|
||||
. ./android-env
|
||||
|
||||
./configure \
|
||||
--disable-shared \
|
||||
--host=arm-linux-androideabi \
|
||||
--host=$TARGET \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--with-xml-prefix="$PREFIX" \
|
||||
--without-libxml2 \
|
||||
--disable-python-bindings \
|
||||
--disable-examples \
|
||||
--disable-threads \
|
||||
CC="$TOOLCHAIN"/bin/arm-linux-androideabi-clang \
|
||||
CXX="$TOOLCHAIN"/bin/arm-linux-androideabi-clang++ \
|
||||
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||
LDFLAGS="-fPIE -pie -L$PREFIX/lib"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# nghttp2 - HTTP/2 C Library
|
||||
#
|
||||
# Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||
# Copyright (c) 2022 nghttp2 contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -23,11 +23,18 @@
|
|||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
echo 'No $ANDROID_HOME specified.'
|
||||
if [ -z "$NDK" ]; then
|
||||
echo 'No $NDK specified.'
|
||||
exit 1
|
||||
fi
|
||||
TOOLCHAIN=$ANDROID_HOME/toolchain
|
||||
PATH=$TOOLCHAIN/bin:$PATH
|
||||
|
||||
make "$@"
|
||||
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
|
||||
export TARGET=aarch64-linux-android
|
||||
export API=33
|
||||
export AR=$TOOLCHAIN/bin/llvm-ar
|
||||
export CC=$TOOLCHAIN/bin/$TARGET$API-clang
|
||||
export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++
|
||||
export LD=$TOOLCHAIN/bin/ld
|
||||
export RANDLIB=$TOOLCHAIN/bin/llvm-ranlib
|
||||
export STRIP=$TOOLCHAIN/bin/llvm-strip
|
||||
export PREFIX=$NDK/usr/local
|
|
@ -1,44 +0,0 @@
|
|||
# Find the Cython compiler.
|
||||
#
|
||||
# This code sets the following variables:
|
||||
#
|
||||
# CYTHON_EXECUTABLE
|
||||
#
|
||||
# See also UseCython.cmake
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 Kitware, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#=============================================================================
|
||||
|
||||
# Use the Cython executable that lives next to the Python executable
|
||||
# if it is a local installation.
|
||||
find_package( PythonInterp )
|
||||
if( PYTHONINTERP_FOUND )
|
||||
get_filename_component( _python_path ${PYTHON_EXECUTABLE} PATH )
|
||||
find_program( CYTHON_EXECUTABLE
|
||||
NAMES cython cython.bat cython3
|
||||
HINTS ${_python_path}
|
||||
)
|
||||
else()
|
||||
find_program( CYTHON_EXECUTABLE
|
||||
NAMES cython cython.bat cython3
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
include( FindPackageHandleStandardArgs )
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS( Cython REQUIRED_VARS CYTHON_EXECUTABLE )
|
||||
|
||||
mark_as_advanced( CYTHON_EXECUTABLE )
|
123
configure.ac
123
configure.ac
|
@ -25,7 +25,7 @@ dnl Do not change user variables!
|
|||
dnl https://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([nghttp2], [1.50.0], [t-tujikawa@users.sourceforge.net])
|
||||
AC_INIT([nghttp2], [1.52.0-DEV], [t-tujikawa@users.sourceforge.net])
|
||||
AC_CONFIG_AUX_DIR([.])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
@ -45,7 +45,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
|||
dnl See versioning rule:
|
||||
dnl https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
AC_SUBST(LT_CURRENT, 38)
|
||||
AC_SUBST(LT_REVISION, 0)
|
||||
AC_SUBST(LT_REVISION, 1)
|
||||
AC_SUBST(LT_AGE, 24)
|
||||
|
||||
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
|
||||
|
@ -82,21 +82,11 @@ AC_ARG_ENABLE([hpack-tools],
|
|||
[Build HPACK tools [default=check]])],
|
||||
[request_hpack_tools=$enableval], [request_hpack_tools=check])
|
||||
|
||||
AC_ARG_ENABLE([asio-lib],
|
||||
[AS_HELP_STRING([--enable-asio-lib],
|
||||
[Build C++ libnghttp2_asio library [default=no]])],
|
||||
[request_asio_lib=$enableval], [request_asio_lib=no])
|
||||
|
||||
AC_ARG_ENABLE([examples],
|
||||
[AS_HELP_STRING([--enable-examples],
|
||||
[Build examples [default=check]])],
|
||||
[request_examples=$enableval], [request_examples=check])
|
||||
|
||||
AC_ARG_ENABLE([python-bindings],
|
||||
[AS_HELP_STRING([--enable-python-bindings],
|
||||
[Build Python bindings [default=check]])],
|
||||
[request_python_bindings=$enableval], [request_python_bindings=check])
|
||||
|
||||
AC_ARG_ENABLE([failmalloc],
|
||||
[AS_HELP_STRING([--disable-failmalloc],
|
||||
[Do not build failmalloc test program])],
|
||||
|
@ -104,7 +94,7 @@ AC_ARG_ENABLE([failmalloc],
|
|||
|
||||
AC_ARG_ENABLE([lib-only],
|
||||
[AS_HELP_STRING([--enable-lib-only],
|
||||
[Build libnghttp2 only. This is a short hand for --disable-app --disable-examples --disable-hpack-tools --disable-python-bindings])],
|
||||
[Build libnghttp2 only. This is a short hand for --disable-app --disable-examples --disable-hpack-tools])],
|
||||
[request_lib_only=$enableval], [request_lib_only=no])
|
||||
|
||||
AC_ARG_ENABLE([http3],
|
||||
|
@ -172,11 +162,6 @@ AC_ARG_WITH([neverbleed],
|
|||
[Use neverbleed [default=no]])],
|
||||
[request_neverbleed=$withval], [request_neverbleed=no])
|
||||
|
||||
AC_ARG_WITH([cython],
|
||||
[AS_HELP_STRING([--with-cython=PATH],
|
||||
[Use cython in given PATH])],
|
||||
[cython_path=$withval], [])
|
||||
|
||||
AC_ARG_WITH([libngtcp2],
|
||||
[AS_HELP_STRING([--with-libngtcp2],
|
||||
[Use libngtcp2 [default=check]])],
|
||||
|
@ -193,8 +178,6 @@ AC_ARG_WITH([libbpf],
|
|||
[request_libbpf=$withval], [request_libbpf=no])
|
||||
|
||||
dnl Define variables
|
||||
AC_ARG_VAR([CYTHON], [the Cython executable])
|
||||
|
||||
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])
|
||||
|
||||
|
@ -220,16 +203,10 @@ PKG_PROG_PKG_CONFIG([0.20])
|
|||
|
||||
AM_PATH_PYTHON([3.8],, [:])
|
||||
|
||||
if test "x$request_python_bindings" = "xyes" &&
|
||||
test "x$PYTHON" = "x:"; then
|
||||
AC_MSG_ERROR([python was requested (enable-python-bindings) but not found])
|
||||
fi
|
||||
|
||||
if [test "x$request_lib_only" = "xyes"]; then
|
||||
request_app=no
|
||||
request_hpack_tools=no
|
||||
request_examples=no
|
||||
request_python_bindings=no
|
||||
request_http3=no
|
||||
request_libxml2=no
|
||||
request_jansson=no
|
||||
|
@ -247,19 +224,6 @@ if [test "x$request_lib_only" = "xyes"]; then
|
|||
request_libbpf=no
|
||||
fi
|
||||
|
||||
if test "x$request_python_bindings" != "xno" &&
|
||||
test "x$PYTHON" != "x:"; then
|
||||
# version check is broken
|
||||
AX_PYTHON_DEVEL()
|
||||
fi
|
||||
|
||||
if test "x${cython_path}" = "x"; then
|
||||
AC_CHECK_PROGS([CYTHON], [cython.py cython])
|
||||
else
|
||||
CYTHON=${cython_path}
|
||||
AC_SUBST([CYTHON])
|
||||
fi
|
||||
|
||||
if test "x$GCC" = "xyes" -o "x$CC" = "xclang" ; then
|
||||
AC_DEFINE([NGHTTP2_NORETURN], [__attribute__((noreturn))], [Hint to the compiler that a function never return])
|
||||
else
|
||||
|
@ -364,8 +328,8 @@ APPLDFLAGS=
|
|||
case "$host_os" in
|
||||
*android*)
|
||||
android_build=yes
|
||||
# android does not need -pthread, but needs following 3 libs for C++
|
||||
APPLDFLAGS="$APPLDFLAGS -lstdc++ -latomic -lsupc++"
|
||||
# android does not need -pthread, but needs following 2 libs for C++
|
||||
APPLDFLAGS="$APPLDFLAGS -lstdc++ -latomic"
|
||||
;;
|
||||
*)
|
||||
PTHREAD_LDFLAGS="-pthread"
|
||||
|
@ -540,7 +504,7 @@ fi
|
|||
# ngtcp2 (for src)
|
||||
have_libngtcp2=no
|
||||
if test "x${request_libngtcp2}" != "xno"; then
|
||||
PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.9.0], [have_libngtcp2=yes],
|
||||
PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.10.0], [have_libngtcp2=yes],
|
||||
[have_libngtcp2=no])
|
||||
if test "x${have_libngtcp2}" = "xno"; then
|
||||
AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS)
|
||||
|
@ -557,7 +521,7 @@ have_libngtcp2_crypto_openssl=no
|
|||
if test "x${have_ssl_is_quic}" = "xyes" &&
|
||||
test "x${request_libngtcp2}" != "xno"; then
|
||||
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL],
|
||||
[libngtcp2_crypto_openssl >= 0.9.0],
|
||||
[libngtcp2_crypto_openssl >= 0.10.0],
|
||||
[have_libngtcp2_crypto_openssl=yes],
|
||||
[have_libngtcp2_crypto_openssl=no])
|
||||
if test "x${have_libngtcp2_crypto_openssl}" = "xno"; then
|
||||
|
@ -763,25 +727,6 @@ if test "x${request_jemalloc}" = "xyes" &&
|
|||
AC_MSG_ERROR([jemalloc was requested (--with-jemalloc) but not found])
|
||||
fi
|
||||
|
||||
# Check Boost Asio library
|
||||
have_asio_lib=no
|
||||
|
||||
if test "x${request_asio_lib}" = "xyes"; then
|
||||
AX_BOOST_BASE([1.54.0], [have_boost_base=yes], [have_boost_base=no])
|
||||
|
||||
if test "x${have_boost_base}" = "xyes"; then
|
||||
AX_BOOST_ASIO()
|
||||
AX_BOOST_SYSTEM()
|
||||
AX_BOOST_THREAD()
|
||||
|
||||
if test "x${ax_cv_boost_asio}" = "xyes" &&
|
||||
test "x${ax_cv_boost_system}" = "xyes" &&
|
||||
test "x${ax_cv_boost_thread}" = "xyes"; then
|
||||
have_asio_lib=yes
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL,
|
||||
# libev, and libc-ares.
|
||||
enable_app=no
|
||||
|
@ -834,16 +779,6 @@ fi
|
|||
|
||||
AM_CONDITIONAL([ENABLE_HPACK_TOOLS], [ test "x${enable_hpack_tools}" = "xyes" ])
|
||||
|
||||
# C++ library libnghttp2_asio
|
||||
|
||||
enable_asio_lib=no
|
||||
if test "x${request_asio_lib}" != "xno" &&
|
||||
test "x${have_asio_lib}" = "xyes"; then
|
||||
enable_asio_lib=yes
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_ASIO_LIB], [ test "x${enable_asio_lib}" = "xyes" ])
|
||||
|
||||
# The example programs depend on OpenSSL and libevent_openssl
|
||||
enable_examples=no
|
||||
if test "x${request_examples}" != "xno" &&
|
||||
|
@ -866,8 +801,7 @@ have_mruby=no
|
|||
have_neverbleed=no
|
||||
if test "x${enable_examples}" = "xyes" ||
|
||||
test "x${enable_app}" = "xyes" ||
|
||||
test "x${enable_hpack_tools}" = "xyes" ||
|
||||
test "x${enable_asio_lib}" = "xyes"; then
|
||||
test "x${enable_hpack_tools}" = "xyes"; then
|
||||
enable_third_party=yes
|
||||
|
||||
# mruby (for src/nghttpx)
|
||||
|
@ -892,27 +826,6 @@ AM_CONDITIONAL([ENABLE_THIRD_PARTY], [ test "x${enable_third_party}" = "xyes" ])
|
|||
AM_CONDITIONAL([HAVE_MRUBY], [test "x${have_mruby}" = "xyes"])
|
||||
AM_CONDITIONAL([HAVE_NEVERBLEED], [test "x${have_neverbleed}" = "xyes"])
|
||||
|
||||
# Python bindings
|
||||
enable_python_bindings=no
|
||||
if test "x${request_python_bindings}" != "xno" &&
|
||||
test "x${CYTHON}" != "x" &&
|
||||
test "x${PYTHON}" != "x:" &&
|
||||
test "x${PYTHON_VERSION}" != "x"; then
|
||||
enable_python_bindings=yes
|
||||
fi
|
||||
|
||||
if test "x${request_python_bindings}" = "xyes" &&
|
||||
test "x${enable_python_bindings}" != "xyes"; then
|
||||
AC_MSG_ERROR([python bindings were requested (--enable-python-bindings) but dependencies are not met.])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_PYTHON_BINDINGS],
|
||||
[test "x${enable_python_bindings}" = "xyes"])
|
||||
|
||||
# Produce cython conditional, so that we can distribute generated C
|
||||
# source
|
||||
AM_CONDITIONAL([HAVE_CYTHON], [test "x${CYTHON}" != "x"])
|
||||
|
||||
# failmalloc tests
|
||||
enable_failmalloc=no
|
||||
if test "x${request_failmalloc}" = "xyes"; then
|
||||
|
@ -1159,12 +1072,8 @@ AC_CONFIG_FILES([
|
|||
tests/testdata/Makefile
|
||||
third-party/Makefile
|
||||
src/Makefile
|
||||
src/includes/Makefile
|
||||
src/libnghttp2_asio.pc
|
||||
bpf/Makefile
|
||||
examples/Makefile
|
||||
python/Makefile
|
||||
python/setup.py
|
||||
integration-tests/Makefile
|
||||
integration-tests/config.go
|
||||
integration-tests/setenv
|
||||
|
@ -1177,14 +1086,9 @@ AC_CONFIG_FILES([
|
|||
doc/tutorial-hpack.rst
|
||||
doc/nghttpx-howto.rst
|
||||
doc/h2load-howto.rst
|
||||
doc/libnghttp2_asio.rst
|
||||
doc/python-apiref.rst
|
||||
doc/building-android-binary.rst
|
||||
doc/nghttp2.h.rst
|
||||
doc/nghttp2ver.h.rst
|
||||
doc/asio_http2.h.rst
|
||||
doc/asio_http2_server.h.rst
|
||||
doc/asio_http2_client.h.rst
|
||||
doc/contribute.rst
|
||||
contrib/Makefile
|
||||
script/Makefile
|
||||
|
@ -1226,10 +1130,6 @@ AC_MSG_NOTICE([summary of build options:
|
|||
Python:
|
||||
Python: ${PYTHON}
|
||||
PYTHON_VERSION: ${PYTHON_VERSION}
|
||||
pyexecdir: ${pyexecdir}
|
||||
PYTHON_CPPFLAGS:${PYTHON_CPPFLAGS}
|
||||
PYTHON_LIBS: ${PYTHON_LIBS}
|
||||
Cython: ${CYTHON}
|
||||
Test:
|
||||
CUnit: ${have_cunit} (CFLAGS='${CUNIT_CFLAGS}' LIBS='${CUNIT_LIBS}')
|
||||
Failmalloc: ${enable_failmalloc}
|
||||
|
@ -1248,11 +1148,6 @@ AC_MSG_NOTICE([summary of build options:
|
|||
Jemalloc: ${have_jemalloc} (CFLAGS='${JEMALLOC_CFLAGS}' LIBS='${JEMALLOC_LIBS}')
|
||||
Zlib: ${have_zlib} (CFLAGS='${ZLIB_CFLAGS}' LIBS='${ZLIB_LIBS}')
|
||||
Systemd: ${have_libsystemd} (CFLAGS='${SYSTEMD_CFLAGS}' LIBS='${SYSTEMD_LIBS}')
|
||||
Boost CPPFLAGS: ${BOOST_CPPFLAGS}
|
||||
Boost LDFLAGS: ${BOOST_LDFLAGS}
|
||||
Boost::ASIO: ${BOOST_ASIO_LIB}
|
||||
Boost::System: ${BOOST_SYSTEM_LIB}
|
||||
Boost::Thread: ${BOOST_THREAD_LIB}
|
||||
Third-party:
|
||||
http-parser: ${enable_third_party}
|
||||
MRuby: ${have_mruby} (CFLAGS='${LIBMRUBY_CFLAGS}' LIBS='${LIBMRUBY_LIBS}')
|
||||
|
@ -1260,9 +1155,7 @@ AC_MSG_NOTICE([summary of build options:
|
|||
Features:
|
||||
Applications: ${enable_app}
|
||||
HPACK tools: ${enable_hpack_tools}
|
||||
Libnghttp2_asio:${enable_asio_lib}
|
||||
Examples: ${enable_examples}
|
||||
Python bindings:${enable_python_bindings}
|
||||
Threading: ${enable_threads}
|
||||
HTTP/3 (EXPERIMENTAL): ${enable_http3}
|
||||
])
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
# generated files
|
||||
apiref.rst
|
||||
asio_http2.h.rst
|
||||
asio_http2_client.h.rst
|
||||
asio_http2_server.h.rst
|
||||
building-android-binary.rst
|
||||
conf.py
|
||||
contribute.rst
|
||||
enums.rst
|
||||
h2load-howto.rst
|
||||
index.rst
|
||||
libnghttp2_asio.rst
|
||||
macros.rst
|
||||
manual/
|
||||
nghttp2.h.rst
|
||||
|
@ -17,7 +13,6 @@ nghttp2_*.rst
|
|||
nghttp2ver.h.rst
|
||||
nghttpx-howto.rst
|
||||
package_README.rst
|
||||
python-apiref.rst
|
||||
tutorial-client.rst
|
||||
tutorial-hpack.rst
|
||||
tutorial-server.rst
|
||||
|
|
|
@ -180,8 +180,6 @@ set(EXTRA_DIST
|
|||
sources/tutorial-hpack.rst
|
||||
sources/nghttpx-howto.rst
|
||||
sources/h2load-howto.rst
|
||||
sources/libnghttp2_asio.rst
|
||||
sources/python-apiref.rst
|
||||
sources/building-android-binary.rst
|
||||
sources/contribute.rst
|
||||
_exts/rubydomain/LICENSE.rubydomain
|
||||
|
@ -269,7 +267,7 @@ add_custom_command(
|
|||
apiref.rst
|
||||
${APIDOCS}
|
||||
COMMAND
|
||||
"${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkapiref.py"
|
||||
"${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkapiref.py"
|
||||
apiref.rst macros.rst enums.rst types.rst .
|
||||
${apiref_SOURCES}
|
||||
DEPENDS
|
||||
|
|
|
@ -206,8 +206,6 @@ EXTRA_DIST = \
|
|||
sources/tutorial-hpack.rst \
|
||||
sources/nghttpx-howto.rst \
|
||||
sources/h2load-howto.rst \
|
||||
sources/libnghttp2_asio.rst \
|
||||
sources/python-apiref.rst \
|
||||
sources/building-android-binary.rst \
|
||||
sources/contribute.rst \
|
||||
sources/security.rst \
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
asio_http2.h
|
||||
============
|
||||
|
||||
.. literalinclude:: @top_srcdir@/src/includes/nghttp2/asio_http2.h
|
||||
:language: cpp
|
|
@ -1,5 +0,0 @@
|
|||
asio_http2_client.h
|
||||
===================
|
||||
|
||||
.. literalinclude:: @top_srcdir@/src/includes/nghttp2/asio_http2_client.h
|
||||
:language: cpp
|
|
@ -1,5 +0,0 @@
|
|||
asio_http2_server.h
|
||||
===================
|
||||
|
||||
.. literalinclude:: @top_srcdir@/src/includes/nghttp2/asio_http2_server.h
|
||||
:language: cpp
|
|
@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "H2LOAD" "1" "Sep 21, 2022" "1.50.0" "nghttp2"
|
||||
.TH "H2LOAD" "1" "Nov 13, 2022" "1.51.0" "nghttp2"
|
||||
.SH NAME
|
||||
h2load \- HTTP/2 benchmarking tool
|
||||
.SH SYNOPSIS
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
.. include:: @top_srcdir@/doc/sources/libnghttp2_asio.rst
|
|
@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "NGHTTP" "1" "Sep 21, 2022" "1.50.0" "nghttp2"
|
||||
.TH "NGHTTP" "1" "Nov 13, 2022" "1.51.0" "nghttp2"
|
||||
.SH NAME
|
||||
nghttp \- HTTP/2 client
|
||||
.SH SYNOPSIS
|
||||
|
|
|
@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "NGHTTPD" "1" "Sep 21, 2022" "1.50.0" "nghttp2"
|
||||
.TH "NGHTTPD" "1" "Nov 13, 2022" "1.51.0" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpd \- HTTP/2 server
|
||||
.SH SYNOPSIS
|
||||
|
|
|
@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "NGHTTPX" "1" "Sep 21, 2022" "1.50.0" "nghttp2"
|
||||
.TH "NGHTTPX" "1" "Nov 13, 2022" "1.51.0" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpx \- HTTP/2 proxy
|
||||
.SH SYNOPSIS
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
.. include:: @top_srcdir@/doc/sources/python-apiref.rst
|
|
@ -2,49 +2,39 @@ Building Android binary
|
|||
=======================
|
||||
|
||||
In this article, we briefly describe how to build Android binary using
|
||||
`Android NDK <https://developer.android.com/ndk/index.html>`_
|
||||
cross-compiler on Debian Linux.
|
||||
`Android NDK <https://developer.android.com/ndk>`_ cross-compiler on
|
||||
Debian Linux.
|
||||
|
||||
The easiest way to build android binary is use Dockerfile.android.
|
||||
See Dockerfile.android for more details. If you cannot use
|
||||
Dockerfile.android for whatever reason, continue to read the rest of
|
||||
this article.
|
||||
|
||||
We offer ``android-config`` and ``android-make`` scripts to make the
|
||||
build easier. To make these script work, NDK toolchain must be
|
||||
installed in the following way. First, let us introduce
|
||||
``ANDROID_HOME`` environment variable. We need to install toolchain
|
||||
under ``$ANDROID_HOME/toolchain``. An user can freely choose the path
|
||||
for ``ANDROID_HOME``. For example, to install toolchain under
|
||||
``$ANDROID_HOME/toolchain``, do this in the the directory where NDK is
|
||||
unpacked:
|
||||
We offer ``android-config`` script to make the build easier. To make
|
||||
the script work, NDK directory must be set to ``NDK`` environment
|
||||
variable. NDK directory is the directory where NDK is unpacked:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ build/tools/make_standalone_toolchain.py \
|
||||
--arch arm --api 16 --stl gnustl \
|
||||
--install-dir $ANDROID_HOME/toolchain
|
||||
|
||||
The API level (``--api``) is not important here because we don't use
|
||||
Android specific C/C++ API.
|
||||
$ unzip android-ndk-$NDK_VERSION-linux.zip
|
||||
$ cd android-ndk-$NDK_VERSION
|
||||
$ export NDK=$PWD
|
||||
|
||||
The dependent libraries, such as OpenSSL, libev, and c-ares should be
|
||||
built with the toolchain and installed under
|
||||
``$ANDROID_HOME/usr/local``. We recommend to build these libraries as
|
||||
static library to make the deployment easier. libxml2 support is
|
||||
currently disabled.
|
||||
built with the same NDK toolchain and installed under
|
||||
``$NDK/usr/local``. We recommend to build these libraries as static
|
||||
library to make the deployment easier. libxml2 support is currently
|
||||
disabled.
|
||||
|
||||
Although zlib comes with Android NDK, it seems not to be a part of
|
||||
public API, so we have to built it for our own. That also provides us
|
||||
proper .pc file as a bonus.
|
||||
|
||||
Before running ``android-config`` and ``android-make``,
|
||||
``ANDROID_HOME`` environment variable must be set to point to the
|
||||
correct path. Also add ``$ANDROID_HOME/toolchain/bin`` to ``PATH``:
|
||||
Before running ``android-config``, ``NDK`` environment variable must
|
||||
be set to point to the correct path.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ export PATH=$PATH:$ANDROID_HOME/toolchain/bin
|
||||
You need to set ``NGHTTP2`` environment variable to the absolute path
|
||||
to the source directory of nghttp2.
|
||||
|
||||
To configure OpenSSL, use the following script:
|
||||
|
||||
|
@ -52,39 +42,36 @@ To configure OpenSSL, use the following script:
|
|||
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
echo 'No $ANDROID_HOME specified.'
|
||||
exit 1
|
||||
fi
|
||||
PREFIX=$ANDROID_HOME/usr/local
|
||||
TOOLCHAIN=$ANDROID_HOME/toolchain
|
||||
PATH=$TOOLCHAIN/bin:$PATH
|
||||
. $NGHTTP2/android-env
|
||||
|
||||
export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi-
|
||||
./Configure --prefix=$PREFIX android
|
||||
export ANDROID_NDK_HOME=$NDK
|
||||
export PATH=$TOOLCHAIN/bin:$PATH
|
||||
|
||||
And run ``make install_sw`` to build and install without
|
||||
documentation.
|
||||
./Configure no-shared --prefix=$PREFIX android-arm64
|
||||
|
||||
We cannot compile libev without modification. Apply `this patch
|
||||
<https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed>`_ before
|
||||
configuring libev. This patch is for libev-4.19. After applying the
|
||||
patch, to configure libev, use the following script:
|
||||
And run the following script to build and install without
|
||||
documentation:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
echo 'No $ANDROID_HOME specified.'
|
||||
exit 1
|
||||
fi
|
||||
PREFIX=$ANDROID_HOME/usr/local
|
||||
TOOLCHAIN=$ANDROID_HOME/toolchain
|
||||
PATH=$TOOLCHAIN/bin:$PATH
|
||||
. $NGHTTP2/android-env
|
||||
|
||||
export PATH=$TOOLCHAIN/bin:$PATH
|
||||
|
||||
make install_sw
|
||||
|
||||
To configure libev, use the following script:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
. $NGHTTP2/android-env
|
||||
|
||||
./configure \
|
||||
--host=arm-linux-androideabi \
|
||||
--host=$TARGET \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
--disable-shared \
|
||||
|
@ -100,41 +87,26 @@ To configure c-ares, use the following script:
|
|||
|
||||
#!/bin/sh -e
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
echo 'No $ANDROID_HOME specified.'
|
||||
exit 1
|
||||
fi
|
||||
PREFIX=$ANDROID_HOME/usr/local
|
||||
TOOLCHAIN=$ANDROID_HOME/toolchain
|
||||
PATH=$TOOLCHAIN/bin:$PATH
|
||||
. $NGHTTP2/android-env
|
||||
|
||||
./configure \
|
||||
--host=arm-linux-androideabi \
|
||||
--host=$TARGET \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--prefix=$PREFIX \
|
||||
--disable-shared
|
||||
|
||||
And run ``make install`` to build and install.
|
||||
|
||||
To configure zlib, use the following script:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh -e
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
echo 'No $ANDROID_HOME specified.'
|
||||
exit 1
|
||||
fi
|
||||
PREFIX=$ANDROID_HOME/usr/local
|
||||
TOOLCHAIN=$ANDROID_HOME/toolchain
|
||||
PATH=$TOOLCHAIN/bin:$PATH
|
||||
. $NGHTTP2/android-env
|
||||
|
||||
HOST=arm-linux-androideabi
|
||||
export HOST=$TARGET
|
||||
|
||||
CC=$HOST-gcc \
|
||||
AR=$HOST-ar \
|
||||
LD=$HOST-ld \
|
||||
RANLIB=$HOST-ranlib \
|
||||
STRIP=$HOST-strip \
|
||||
./configure \
|
||||
--prefix=$PREFIX \
|
||||
--libdir=$PREFIX/lib \
|
||||
|
@ -144,7 +116,7 @@ To configure zlib, use the following script:
|
|||
And run ``make install`` to build and install.
|
||||
|
||||
After prerequisite libraries are prepared, run ``android-config`` and
|
||||
then ``android-make`` to compile nghttp2 source files.
|
||||
then ``make`` to compile nghttp2 source files.
|
||||
|
||||
If all went well, application binaries, such as nghttpx, are created
|
||||
under src directory. Strip debugging information from the binary
|
||||
|
@ -152,4 +124,4 @@ using the following command:
|
|||
|
||||
.. code-block:: text
|
||||
|
||||
$ arm-linux-androideabi-strip src/nghttpx
|
||||
$ $NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip src/nghttpx
|
||||
|
|
|
@ -31,13 +31,8 @@ Contents:
|
|||
h2load-howto
|
||||
programmers-guide
|
||||
apiref
|
||||
libnghttp2_asio
|
||||
python-apiref
|
||||
nghttp2.h
|
||||
nghttp2ver.h
|
||||
asio_http2_server.h
|
||||
asio_http2_client.h
|
||||
asio_http2.h
|
||||
Source <https://github.com/nghttp2/nghttp2>
|
||||
Issues <https://github.com/nghttp2/nghttp2/issues>
|
||||
nghttp2.org <https://nghttp2.org/>
|
||||
|
|
|
@ -1,439 +0,0 @@
|
|||
libnghttp2_asio: High level HTTP/2 C++ library
|
||||
==============================================
|
||||
|
||||
.. warning::
|
||||
|
||||
libnghttp2_asio has been deprecated in this repository due to
|
||||
maintenance issue and will be removed at the end of 2022. It has
|
||||
moved to https://github.com/nghttp2/nghttp2-asio.
|
||||
|
||||
libnghttp2_asio is C++ library built on top of libnghttp2 and provides
|
||||
high level abstraction API to build HTTP/2 applications. It depends
|
||||
on Boost::ASIO library and OpenSSL. Currently libnghttp2_asio
|
||||
provides server and client side API.
|
||||
|
||||
libnghttp2_asio is not built by default. Use ``--enable-asio-lib``
|
||||
configure flag to build libnghttp2_asio. The required Boost libraries
|
||||
are:
|
||||
|
||||
* Boost::Asio
|
||||
* Boost::System
|
||||
* Boost::Thread
|
||||
|
||||
We have 3 header files for this library:
|
||||
|
||||
* :doc:`asio_http2_server.h`
|
||||
* :doc:`asio_http2_client.h`
|
||||
* :doc:`asio_http2.h`
|
||||
|
||||
asio_http2.h is included from the other two files.
|
||||
|
||||
To build a program with libnghttp2_asio, link to the following
|
||||
libraries::
|
||||
|
||||
-lnghttp2_asio -lboost_system
|
||||
|
||||
If ``boost::asio::ssl`` is used in application code, OpenSSL is also
|
||||
required in link line::
|
||||
|
||||
-lnghttp2_asio -lboost_system -lssl -lcrypto
|
||||
|
||||
Server API
|
||||
----------
|
||||
|
||||
To use server API, first include following header file:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
Also take a look at that header file :doc:`asio_http2_server.h`.
|
||||
|
||||
Server API is designed to build HTTP/2 server very easily to utilize
|
||||
C++11 anonymous function and closure. The bare minimum example of
|
||||
HTTP/2 server looks like this:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
boost::system::error_code ec;
|
||||
http2 server;
|
||||
|
||||
server.handle("/", [](const request &req, const response &res) {
|
||||
res.write_head(200);
|
||||
res.end("hello, world\n");
|
||||
});
|
||||
|
||||
if (server.listen_and_serve(ec, "localhost", "3000")) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
First we instantiate ``nghttp2::asio_http2::server::http2`` object.
|
||||
``nghttp2::asio_http2::server::http2::handle`` function registers
|
||||
pattern and its handler function. In this example, we register "/" as
|
||||
pattern, which matches all requests. Then call
|
||||
``nghttp2::asio_http2::server::http2::listen_and_serve`` function with
|
||||
address and port to listen to.
|
||||
|
||||
The ``req`` and ``res`` represent HTTP request and response
|
||||
respectively. ``nghttp2::asio_http2_::server::response::write_head``
|
||||
constructs HTTP response header fields. The first argument is HTTP
|
||||
status code, in the above example, which is 200. The second argument,
|
||||
which is omitted in the above example, is additional header fields to
|
||||
send.
|
||||
|
||||
``nghttp2::asio_http2::server::response::end`` sends response body.
|
||||
In the above example, we send string "hello, world".
|
||||
|
||||
The life time of req and res object ends after the callback set by
|
||||
``nghttp2::asio_http2::server::response::on_close`` function.
|
||||
Application must not use those objects after this call.
|
||||
|
||||
Serving static files and enabling SSL/TLS
|
||||
+++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
In this example, we serve a couple of static files and also enable
|
||||
SSL/TLS.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
boost::system::error_code ec;
|
||||
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
|
||||
|
||||
tls.use_private_key_file("server.key", boost::asio::ssl::context::pem);
|
||||
tls.use_certificate_chain_file("server.crt");
|
||||
|
||||
configure_tls_context_easy(ec, tls);
|
||||
|
||||
http2 server;
|
||||
|
||||
server.handle("/index.html", [](const request &req, const response &res) {
|
||||
res.write_head(200);
|
||||
res.end(file_generator("index.html"));
|
||||
});
|
||||
|
||||
if (server.listen_and_serve(ec, tls, "localhost", "3000")) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
We first create ``boost::asio::ssl::context`` object and set path to
|
||||
private key file and certificate file.
|
||||
``nghttp2::asio_http2::server::configure_tls_context_easy`` function
|
||||
configures SSL/TLS context object for HTTP/2 server use, including NPN
|
||||
callbacks.
|
||||
|
||||
In the above example, if request path is "/index.html", we serve
|
||||
index.html file in the current working directory.
|
||||
``nghttp2::asio_http2::server::response::end`` has overload to take
|
||||
function of type ``nghttp2::asio_http2::generator_cb`` and application
|
||||
pass its implementation to generate response body. For the
|
||||
convenience, libnghttp2_asio library provides
|
||||
``nghttp2::asio_http2::file_generator`` function to generate function
|
||||
to server static file. If other resource is requested, server
|
||||
automatically responds with 404 status code.
|
||||
|
||||
Server push
|
||||
+++++++++++
|
||||
|
||||
Server push is also supported.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
boost::system::error_code ec;
|
||||
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
|
||||
|
||||
tls.use_private_key_file("server.key", boost::asio::ssl::context::pem);
|
||||
tls.use_certificate_chain_file("server.crt");
|
||||
|
||||
configure_tls_context_easy(ec, tls);
|
||||
|
||||
http2 server;
|
||||
|
||||
std::string style_css = "h1 { color: green; }";
|
||||
|
||||
server.handle("/", [&style_css](const request &req, const response &res) {
|
||||
boost::system::error_code ec;
|
||||
auto push = res.push(ec, "GET", "/style.css");
|
||||
push->write_head(200);
|
||||
push->end(style_css);
|
||||
|
||||
res.write_head(200);
|
||||
res.end(R"(
|
||||
<!DOCTYPE html><html lang="en">
|
||||
<title>HTTP/2 FTW</title><body>
|
||||
<link href="/style.css" rel="stylesheet" type="text/css">
|
||||
<h1>This should be green</h1>
|
||||
</body></html>
|
||||
)");
|
||||
});
|
||||
|
||||
server.handle("/style.css",
|
||||
[&style_css](const request &req, const response &res) {
|
||||
res.write_head(200);
|
||||
res.end(style_css);
|
||||
});
|
||||
|
||||
if (server.listen_and_serve(ec, tls, "localhost", "3000")) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
When client requested any resource other than "/style.css", we push
|
||||
"/style.css". To push resource, call
|
||||
``nghttp2::asio_http2::server::response::push`` function with desired
|
||||
method and path. It returns another response object and use its
|
||||
functions to send push response.
|
||||
|
||||
Enable multi-threading
|
||||
++++++++++++++++++++++
|
||||
|
||||
Enabling multi-threading is very easy. Just call
|
||||
``nghttp2::asio_http2::server::http2::num_threads`` function with the
|
||||
desired number of threads:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
http2 server;
|
||||
|
||||
// Use 4 native threads
|
||||
server.num_threads(4);
|
||||
|
||||
Client API
|
||||
----------
|
||||
|
||||
To use client API, first include following header file:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
Also take a look at that header file :doc:`asio_http2_client.h`.
|
||||
|
||||
Here is the sample client code to access HTTP/2 server and print out
|
||||
response header fields and response body to the console screen:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::client;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
boost::system::error_code ec;
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
// connect to localhost:3000
|
||||
session sess(io_service, "localhost", "3000");
|
||||
|
||||
sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
|
||||
boost::system::error_code ec;
|
||||
|
||||
auto req = sess.submit(ec, "GET", "http://localhost:3000/");
|
||||
|
||||
req->on_response([](const response &res) {
|
||||
// print status code and response header fields.
|
||||
std::cerr << "HTTP/2 " << res.status_code() << std::endl;
|
||||
for (auto &kv : res.header()) {
|
||||
std::cerr << kv.first << ": " << kv.second.value << "\n";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
res.on_data([](const uint8_t *data, std::size_t len) {
|
||||
std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
std::cerr << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
req->on_close([&sess](uint32_t error_code) {
|
||||
// shutdown session after first request was done.
|
||||
sess.shutdown();
|
||||
});
|
||||
});
|
||||
|
||||
sess.on_error([](const boost::system::error_code &ec) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
});
|
||||
|
||||
io_service.run();
|
||||
}
|
||||
|
||||
``nghttp2::asio_http2::client::session`` object takes
|
||||
``boost::asio::io_service`` object and remote server address. When
|
||||
connection is made, the callback function passed to
|
||||
``nghttp2::asio_http2::client::on_connect`` is invoked with connected
|
||||
address as its parameter. After this callback call, use
|
||||
``nghttp2::asio_http2::session::submit`` to send request to the
|
||||
server. You can submit multiple requests at once without waiting for
|
||||
the completion of previous request.
|
||||
|
||||
The life time of req and res object ends after the callback set by
|
||||
``nghttp2::asio_http2::server::request::on_close`` function.
|
||||
Application must not use those objects after this call.
|
||||
|
||||
Normally, client does not stop even after all requests are done unless
|
||||
connection is lost. To stop client, call
|
||||
``nghttp2::asio_http2::server::session::shutdown()``.
|
||||
|
||||
Receive server push and enable SSL/TLS
|
||||
++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::client;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
boost::system::error_code ec;
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
|
||||
tls.set_default_verify_paths();
|
||||
// disabled to make development easier...
|
||||
// tls_ctx.set_verify_mode(boost::asio::ssl::verify_peer);
|
||||
configure_tls_context(ec, tls);
|
||||
|
||||
// connect to localhost:3000
|
||||
session sess(io_service, tls, "localhost", "3000");
|
||||
|
||||
sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
|
||||
boost::system::error_code ec;
|
||||
|
||||
auto req = sess.submit(ec, "GET", "http://localhost:3000/");
|
||||
|
||||
req->on_response([&sess](const response &res) {
|
||||
std::cerr << "response received!" << std::endl;
|
||||
res.on_data([&sess](const uint8_t *data, std::size_t len) {
|
||||
std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
std::cerr << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
req->on_push([](const request &push) {
|
||||
std::cerr << "push request received!" << std::endl;
|
||||
push.on_response([](const response &res) {
|
||||
std::cerr << "push response received!" << std::endl;
|
||||
res.on_data([](const uint8_t *data, std::size_t len) {
|
||||
std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
std::cerr << std::endl;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
sess.on_error([](const boost::system::error_code &ec) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
});
|
||||
|
||||
io_service.run();
|
||||
}
|
||||
|
||||
The above sample code demonstrates how to enable SSL/TLS and receive
|
||||
server push. Currently,
|
||||
``nghttp2::asio_http2::client::configure_tls_context`` function setups
|
||||
NPN callbacks for SSL/TLS context for HTTP/2 use.
|
||||
|
||||
To receive server push, use
|
||||
``nghttp2::asio_http2::client::request::on_push`` function to set
|
||||
callback function which is invoked when server push request is
|
||||
arrived. The callback function takes
|
||||
``nghttp2::asio_http2::client::request`` object, which contains the
|
||||
pushed request. To get server push response, set callback using
|
||||
``nghttp2::asio_http2::client::request::on_response``.
|
||||
|
||||
As stated in the previous section, client does not stop automatically
|
||||
as long as HTTP/2 session is fine and connection is alive. We don't
|
||||
call ``nghttp2::asio_http2::client::session::shutdown`` in this
|
||||
example, so the program does not terminate after all responses are
|
||||
received. Hit Ctrl-C to terminate the program.
|
||||
|
||||
Multiple concurrent requests
|
||||
++++++++++++++++++++++++++++
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::client;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
boost::system::error_code ec;
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
// connect to localhost:3000
|
||||
session sess(io_service, "localhost", "3000");
|
||||
|
||||
sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
|
||||
boost::system::error_code ec;
|
||||
|
||||
auto printer = [](const response &res) {
|
||||
res.on_data([](const uint8_t *data, std::size_t len) {
|
||||
std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
std::cerr << std::endl;
|
||||
});
|
||||
};
|
||||
|
||||
std::size_t num = 3;
|
||||
auto count = std::make_shared<int>(num);
|
||||
|
||||
for (std::size_t i = 0; i < num; ++i) {
|
||||
auto req = sess.submit(ec, "GET",
|
||||
"http://localhost:3000/" + std::to_string(i + 1));
|
||||
|
||||
req->on_response(printer);
|
||||
req->on_close([&sess, count](uint32_t error_code) {
|
||||
if (--*count == 0) {
|
||||
// shutdown session after |num| requests were done.
|
||||
sess.shutdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
sess.on_error([](const boost::system::error_code &ec) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
});
|
||||
|
||||
io_service.run();
|
||||
}
|
||||
|
||||
Here is the sample to send 3 requests at once. Depending on the
|
||||
server settings, these requests are processed out-of-order. In this
|
||||
example, we have a trick to shutdown session after all requests were
|
||||
done. We made ``count`` object which is shared pointer to int and is
|
||||
initialized to 3. On each request closure (the invocation of the
|
||||
callback set by ``nghttp2::asio_http2::client::request::on_close``),
|
||||
we decrement the count. If count becomes 0, we are sure that all
|
||||
requests have been done and initiate shutdown.
|
|
@ -1,444 +0,0 @@
|
|||
Python API Reference
|
||||
====================
|
||||
|
||||
.. warning::
|
||||
|
||||
Python bindings have been deprecated due to maintenance issue. It
|
||||
will not get any updates. It will be removed at the end of 2022.
|
||||
|
||||
.. py:module:: nghttp2
|
||||
|
||||
nghttp2 offers some high level Python API to C library. The bindings
|
||||
currently provide HPACK compressor and decompressor classes and HTTP/2
|
||||
server class.
|
||||
|
||||
The extension module is called ``nghttp2``.
|
||||
|
||||
``make`` will build the bindings. The target Python version is
|
||||
determined by configure script. If the detected Python version is not
|
||||
what you expect, specify a path to Python executable in ``PYTHON``
|
||||
variable as an argument to configure script (e.g., ``./configure
|
||||
PYTHON=/usr/bin/python3.8``).
|
||||
|
||||
HPACK API
|
||||
---------
|
||||
|
||||
.. py:class:: HDDeflater(hd_table_bufsize_max=DEFLATE_MAX_HEADER_TABLE_SIZE)
|
||||
|
||||
This class is used to perform header compression. The
|
||||
*hd_table_bufsize_max* limits the usage of header table in the
|
||||
given amount of bytes. The default value is
|
||||
:py:data:`DEFLATE_MAX_HEADER_TABLE_SIZE`. This is necessary
|
||||
because the deflater and inflater share the same amount of header
|
||||
table and the inflater decides that number. The deflater may not
|
||||
want to use all header table size because of limited memory
|
||||
availability. In that case, *hd_table_bufsize_max* can be used to
|
||||
cap the upper limit of table size whatever the header table size is
|
||||
chosen by the inflater.
|
||||
|
||||
.. py:method:: deflate(headers)
|
||||
|
||||
Deflates the *headers*. The *headers* must be sequence of tuple
|
||||
of name/value pair, which are byte strings (not unicode string).
|
||||
|
||||
This method returns the deflated header block in byte string.
|
||||
Raises the exception if any error occurs.
|
||||
|
||||
.. py:method:: set_no_refset(no_refset)
|
||||
|
||||
Tells the deflater not to use reference set if *no_refset* is
|
||||
evaluated to ``True``. If that happens, on each subsequent
|
||||
invocation of :py:meth:`deflate()`, deflater will clear up
|
||||
refersent set.
|
||||
|
||||
.. py:method:: change_table_size(hd_table_bufsize_max)
|
||||
|
||||
Changes header table size to *hd_table_bufsize_max* byte. if
|
||||
*hd_table_bufsize_max* is strictly larger than
|
||||
``hd_table_bufsize_max`` given in constructor,
|
||||
``hd_table_bufsize_max`` is used as header table size instead.
|
||||
|
||||
Raises the exception if any error occurs.
|
||||
|
||||
.. py:method:: get_hd_table()
|
||||
|
||||
Returns copy of current dynamic header table.
|
||||
|
||||
The following example shows how to deflate header name/value pairs:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import binascii, nghttp2
|
||||
|
||||
deflater = nghttp2.HDDeflater()
|
||||
|
||||
res = deflater.deflate([(b'foo', b'bar'),
|
||||
(b'baz', b'buz')])
|
||||
|
||||
print(binascii.b2a_hex(res))
|
||||
|
||||
|
||||
.. py:class:: HDInflater()
|
||||
|
||||
This class is used to perform header decompression.
|
||||
|
||||
.. py:method:: inflate(data)
|
||||
|
||||
Inflates the deflated header block *data*. The *data* must be
|
||||
byte string.
|
||||
|
||||
Raises the exception if any error occurs.
|
||||
|
||||
.. py:method:: change_table_size(hd_table_bufsize_max)
|
||||
|
||||
Changes header table size to *hd_table_bufsize_max* byte.
|
||||
|
||||
Raises the exception if any error occurs.
|
||||
|
||||
.. py:method:: get_hd_table()
|
||||
|
||||
Returns copy of current dynamic header table.
|
||||
|
||||
The following example shows how to inflate deflated header block:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
deflater = nghttp2.HDDeflater()
|
||||
|
||||
data = deflater.deflate([(b'foo', b'bar'),
|
||||
(b'baz', b'buz')])
|
||||
|
||||
inflater = nghttp2.HDInflater()
|
||||
|
||||
hdrs = inflater.inflate(data)
|
||||
|
||||
print(hdrs)
|
||||
|
||||
|
||||
.. py:function:: print_hd_table(hdtable)
|
||||
|
||||
Convenient function to print *hdtable* to the standard output. The
|
||||
*hdtable* is the one retrieved by
|
||||
:py:meth:`HDDeflater.get_hd_table()` or
|
||||
:py:meth:`HDInflater.get_hd_table()`. This function does not work
|
||||
if header name/value cannot be decoded using UTF-8 encoding.
|
||||
|
||||
In output, ``s=N`` means the entry occupies ``N`` bytes in header
|
||||
table. If ``r=y``, then the entry is in the reference set.
|
||||
|
||||
.. py:data:: DEFAULT_HEADER_TABLE_SIZE
|
||||
|
||||
The default header table size, which is 4096 as per HTTP/2
|
||||
specification.
|
||||
|
||||
.. py:data:: DEFLATE_MAX_HEADER_TABLE_SIZE
|
||||
|
||||
The default header table size for deflater. The initial value
|
||||
is 4096.
|
||||
|
||||
HTTP/2 servers
|
||||
--------------
|
||||
|
||||
.. note::
|
||||
|
||||
We use :py:mod:`asyncio` for HTTP/2 server classes, and ALPN.
|
||||
Therefore, Python 3.8 or later is required to use these objects.
|
||||
To explicitly configure nghttp2 build to use Python 3.8, specify
|
||||
the ``PYTHON`` variable to the path to Python 3.8 executable when
|
||||
invoking configure script like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ ./configure PYTHON=/usr/bin/python3.8
|
||||
|
||||
.. py:class:: HTTP2Server(address, RequestHandlerClass, ssl=None)
|
||||
|
||||
This class builds on top of the :py:mod:`asyncio` event loop. On
|
||||
construction, *RequestHandlerClass* must be given, which must be a
|
||||
subclass of :py:class:`BaseRequestHandler` class.
|
||||
|
||||
The *address* must be a tuple of hostname/IP address and port to
|
||||
bind. If hostname/IP address is ``None``, all interfaces are
|
||||
assumed.
|
||||
|
||||
To enable SSL/TLS, specify instance of :py:class:`ssl.SSLContext`
|
||||
in *ssl*. Before passing *ssl* to
|
||||
:py:func:`BaseEventLoop.create_server`, ALPN protocol identifiers
|
||||
are set using :py:meth:`ssl.SSLContext.set_npn_protocols`.
|
||||
|
||||
To disable SSL/TLS, omit *ssl* or specify ``None``.
|
||||
|
||||
.. py:method:: serve_forever()
|
||||
|
||||
Runs server and processes incoming requests forever.
|
||||
|
||||
.. py:class:: BaseRequestHandler(http2, stream_id)
|
||||
|
||||
The class is used to handle the single HTTP/2 stream. By default,
|
||||
it does not nothing. It must be subclassed to handle each event
|
||||
callback method.
|
||||
|
||||
The first callback method invoked is :py:meth:`on_headers()`. It is
|
||||
called when HEADERS frame, which includes request header fields, is
|
||||
arrived.
|
||||
|
||||
If request has request body, :py:meth:`on_data()` is invoked for
|
||||
each chunk of received data chunk.
|
||||
|
||||
When whole request is received, :py:meth:`on_request_done()` is
|
||||
invoked.
|
||||
|
||||
When stream is closed, :py:meth:`on_close()` is called.
|
||||
|
||||
The application can send response using :py:meth:`send_response()`
|
||||
method. It can be used in :py:meth:`on_headers()`,
|
||||
:py:meth:`on_data()` or :py:meth:`on_request_done()`.
|
||||
|
||||
The application can push resource using :py:meth:`push()` method.
|
||||
It must be used before :py:meth:`send_response()` call.
|
||||
|
||||
A :py:class:`BaseRequestHandler` has the following instance
|
||||
variables:
|
||||
|
||||
.. py:attribute:: client_address
|
||||
|
||||
Contains a tuple of the form ``(host, port)`` referring to the
|
||||
client's address.
|
||||
|
||||
.. py:attribute:: stream_id
|
||||
|
||||
Stream ID of this stream
|
||||
|
||||
.. py:attribute:: scheme
|
||||
|
||||
Scheme of the request URI. This is a value of ``:scheme``
|
||||
header field.
|
||||
|
||||
.. py:attribute:: method
|
||||
|
||||
Method of this stream. This is a value of ``:method`` header
|
||||
field.
|
||||
|
||||
.. py:attribute:: host
|
||||
|
||||
This is a value of ``:authority`` or ``host`` header field.
|
||||
|
||||
.. py:attribute:: path
|
||||
|
||||
This is a value of ``:path`` header field.
|
||||
|
||||
.. py:attribute:: headers
|
||||
|
||||
Request header fields.
|
||||
|
||||
A :py:class:`BaseRequestHandler` has the following methods:
|
||||
|
||||
.. py:method:: on_headers()
|
||||
|
||||
Called when request HEADERS is arrived. By default, this method
|
||||
does nothing.
|
||||
|
||||
.. py:method:: on_data(data)
|
||||
|
||||
Called when a chunk of request body *data* is arrived. This
|
||||
method will be called multiple times until all data are
|
||||
received. By default, this method does nothing.
|
||||
|
||||
.. py:method:: on_request_done()
|
||||
|
||||
Called when whole request was received. By default, this method
|
||||
does nothing.
|
||||
|
||||
.. py:method:: on_close(error_code)
|
||||
|
||||
Called when stream is about to close. The *error_code*
|
||||
indicates the reason of closure. If it is ``0``, the stream is
|
||||
going to close without error.
|
||||
|
||||
.. py:method:: send_response(status=200, headers=None, body=None)
|
||||
|
||||
Send response. The *status* is HTTP status code. The *headers*
|
||||
is additional response headers. The *:status* header field will
|
||||
be appended by the library. The *body* is the response body.
|
||||
It could be ``None`` if response body is empty. Or it must be
|
||||
instance of either ``str``, ``bytes``, :py:class:`io.IOBase` or
|
||||
callable, called body generator, which takes one parameter,
|
||||
size. The body generator generates response body. It can pause
|
||||
generation of response so that it can wait for slow backend data
|
||||
generation. When invoked, it should return tuple, byte string
|
||||
at most size length and flag. The flag is either
|
||||
:py:data:`DATA_OK`, :py:data:`DATA_EOF` or
|
||||
:py:data:`DATA_DEFERRED`. For non-empty byte string and it is
|
||||
not the last chunk of response, :py:data:`DATA_OK` must be
|
||||
returned as flag. If this is the last chunk of the response
|
||||
(byte string could be ``None``), :py:data:`DATA_EOF` must be
|
||||
returned as flag. If there is no data available right now, but
|
||||
additional data are anticipated, return tuple (``None``,
|
||||
:py:data:`DATA_DEFERRED`). When data arrived, call
|
||||
:py:meth:`resume()` and restart response body transmission.
|
||||
|
||||
Only the body generator can pause response body generation;
|
||||
instance of :py:class:`io.IOBase` must not block.
|
||||
|
||||
If instance of ``str`` is specified as *body*, it will be
|
||||
encoded using UTF-8.
|
||||
|
||||
The *headers* is a list of tuple of the form ``(name,
|
||||
value)``. The ``name`` and ``value`` can be either byte string
|
||||
or unicode string. In the latter case, they will be encoded
|
||||
using UTF-8.
|
||||
|
||||
Raises the exception if any error occurs.
|
||||
|
||||
.. py:method:: push(path, method='GET', request_headers=None, status=200, headers=None, body=None)
|
||||
|
||||
Push a specified resource. The *path* is a path portion of
|
||||
request URI for this resource. The *method* is a method to
|
||||
access this resource. The *request_headers* is additional
|
||||
request headers to access this resource. The ``:scheme``,
|
||||
``:method``, ``:authority`` and ``:path`` are appended by the
|
||||
library. The ``:scheme`` and ``:authority`` are inherited from
|
||||
request header fields of the associated stream.
|
||||
|
||||
The *status* is HTTP status code. The *headers* is additional
|
||||
response headers. The ``:status`` header field is appended by
|
||||
the library. The *body* is the response body. It has the same
|
||||
semantics of *body* parameter of :py:meth:`send_response()`.
|
||||
|
||||
The headers and request_headers are a list of tuple of the form
|
||||
``(name, value)``. The ``name`` and ``value`` can be either byte
|
||||
string or unicode string. In the latter case, they will be
|
||||
encoded using UTF-8.
|
||||
|
||||
Returns an instance of ``RequestHandlerClass`` specified in
|
||||
:py:class:`HTTP2Server` constructor for the pushed resource.
|
||||
|
||||
Raises the exception if any error occurs.
|
||||
|
||||
.. py:method:: resume()
|
||||
|
||||
Signals the restarting of response body transmission paused by
|
||||
``DATA_DEFERRED`` from the body generator (see
|
||||
:py:meth:`send_response()` about the body generator). It is not
|
||||
an error calling this method while response body transmission is
|
||||
not paused.
|
||||
|
||||
.. py:data:: DATA_OK
|
||||
|
||||
``DATA_OK`` indicates non empty data is generated from body generator.
|
||||
|
||||
.. py:data:: DATA_EOF
|
||||
|
||||
``DATA_EOF`` indicates the end of response body.
|
||||
|
||||
.. py:data:: DATA_DEFERRED
|
||||
|
||||
``DATA_DEFERRED`` indicates that data are not available right now
|
||||
and response should be paused.
|
||||
|
||||
The following example illustrates :py:class:`HTTP2Server` and
|
||||
:py:class:`BaseRequestHandler` usage:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import io, ssl
|
||||
|
||||
import nghttp2
|
||||
|
||||
class Handler(nghttp2.BaseRequestHandler):
|
||||
|
||||
def on_headers(self):
|
||||
self.push(path='/css/style.css',
|
||||
request_headers = [('content-type', 'text/css')],
|
||||
status=200,
|
||||
body='body{margin:0;}')
|
||||
|
||||
self.send_response(status=200,
|
||||
headers = [('content-type', 'text/plain')],
|
||||
body=io.BytesIO(b'nghttp2-python FTW'))
|
||||
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
|
||||
ctx.load_cert_chain('server.crt', 'server.key')
|
||||
|
||||
# give None to ssl to make the server non-SSL/TLS
|
||||
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
|
||||
server.serve_forever()
|
||||
|
||||
The following example illustrates HTTP/2 server using asynchronous
|
||||
response body generation. This is simplified reverse proxy:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import ssl
|
||||
import os
|
||||
import urllib
|
||||
import asyncio
|
||||
import io
|
||||
|
||||
import nghttp2
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_http_header(handler, url):
|
||||
url = urllib.parse.urlsplit(url)
|
||||
ssl = url.scheme == 'https'
|
||||
if url.port == None:
|
||||
if url.scheme == 'https':
|
||||
port = 443
|
||||
else:
|
||||
port = 80
|
||||
else:
|
||||
port = url.port
|
||||
|
||||
connect = asyncio.open_connection(url.hostname, port, ssl=ssl)
|
||||
reader, writer = yield from connect
|
||||
req = 'GET {path} HTTP/1.0\r\n\r\n'.format(path=url.path or '/')
|
||||
writer.write(req.encode('utf-8'))
|
||||
# skip response header fields
|
||||
while True:
|
||||
line = yield from reader.readline()
|
||||
line = line.rstrip()
|
||||
if not line:
|
||||
break
|
||||
# read body
|
||||
while True:
|
||||
b = yield from reader.read(4096)
|
||||
if not b:
|
||||
break
|
||||
handler.buf.write(b)
|
||||
writer.close()
|
||||
handler.buf.seek(0)
|
||||
handler.eof = True
|
||||
handler.resume()
|
||||
|
||||
class Body:
|
||||
def __init__(self, handler):
|
||||
self.handler = handler
|
||||
self.handler.eof = False
|
||||
self.handler.buf = io.BytesIO()
|
||||
|
||||
def generate(self, n):
|
||||
buf = self.handler.buf
|
||||
data = buf.read1(n)
|
||||
if not data and not self.handler.eof:
|
||||
return None, nghttp2.DATA_DEFERRED
|
||||
return data, nghttp2.DATA_EOF if self.handler.eof else nghttp2.DATA_OK
|
||||
|
||||
class Handler(nghttp2.BaseRequestHandler):
|
||||
|
||||
def on_headers(self):
|
||||
body = Body(self)
|
||||
asyncio.async(get_http_header(
|
||||
self, 'http://localhost' + self.path.decode('utf-8')))
|
||||
self.send_response(status=200, body=body.generate)
|
||||
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
|
||||
ctx.load_cert_chain('server.crt', 'server.key')
|
||||
|
||||
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
|
||||
server.serve_forever()
|
|
@ -7,7 +7,7 @@ RUN apt-get update && \
|
|||
zlib1g-dev libev-dev libjemalloc-dev ruby-dev libc-ares-dev bison \
|
||||
libelf-dev
|
||||
|
||||
RUN git clone --depth 1 -b OpenSSL_1_1_1q+quic https://github.com/quictls/openssl && \
|
||||
RUN git clone --depth 1 -b OpenSSL_1_1_1s+quic https://github.com/quictls/openssl && \
|
||||
cd openssl && \
|
||||
./config --openssldir=/etc/ssl && \
|
||||
make -j$(nproc) && \
|
||||
|
@ -15,7 +15,7 @@ RUN git clone --depth 1 -b OpenSSL_1_1_1q+quic https://github.com/quictls/openss
|
|||
cd .. && \
|
||||
rm -rf openssl
|
||||
|
||||
RUN git clone --depth 1 -b v0.7.1 https://github.com/ngtcp2/nghttp3 && \
|
||||
RUN git clone --depth 1 -b v0.8.0 https://github.com/ngtcp2/nghttp3 && \
|
||||
cd nghttp3 && \
|
||||
autoreconf -i && \
|
||||
./configure --enable-lib-only && \
|
||||
|
@ -24,7 +24,7 @@ RUN git clone --depth 1 -b v0.7.1 https://github.com/ngtcp2/nghttp3 && \
|
|||
cd .. && \
|
||||
rm -rf nghttp3
|
||||
|
||||
RUN git clone --depth 1 -b v0.9.0 https://github.com/ngtcp2/ngtcp2 && \
|
||||
RUN git clone --depth 1 -b v0.12.0 https://github.com/ngtcp2/ngtcp2 && \
|
||||
cd ngtcp2 && \
|
||||
autoreconf -i && \
|
||||
./configure --enable-lib-only \
|
||||
|
@ -36,7 +36,7 @@ RUN git clone --depth 1 -b v0.9.0 https://github.com/ngtcp2/ngtcp2 && \
|
|||
cd .. && \
|
||||
rm -rf ngtcp2
|
||||
|
||||
RUN git clone --depth 1 -b v1.0.0 https://github.com/libbpf/libbpf && \
|
||||
RUN git clone --depth 1 -b v1.0.1 https://github.com/libbpf/libbpf && \
|
||||
cd libbpf && \
|
||||
PREFIX=/usr/local make -C src install && \
|
||||
cd .. && \
|
||||
|
@ -47,7 +47,7 @@ RUN git clone --depth 1 https://github.com/nghttp2/nghttp2.git && \
|
|||
git submodule update --init && \
|
||||
autoreconf -i && \
|
||||
./configure --disable-examples --disable-hpack-tools \
|
||||
--disable-python-bindings --with-mruby --with-neverbleed \
|
||||
--with-mruby --with-neverbleed \
|
||||
--enable-http3 --with-libbpf \
|
||||
CC=clang CXX=clang++ \
|
||||
LIBTOOL_LDFLAGS="-static-libtool-libs" \
|
||||
|
|
|
@ -3,7 +3,3 @@ libevent-client
|
|||
libevent-server
|
||||
deflate
|
||||
tiny-nghttpd
|
||||
asio-sv
|
||||
asio-sv2
|
||||
asio-cl
|
||||
asio-cl2
|
||||
|
|
|
@ -34,24 +34,4 @@ if(ENABLE_EXAMPLES)
|
|||
add_executable(deflate deflate.c $<TARGET_OBJECTS:llhttp>
|
||||
$<TARGET_OBJECTS:url-parser>
|
||||
)
|
||||
|
||||
if(ENABLE_ASIO_LIB)
|
||||
foreach(name asio-sv asio-sv2 asio-cl asio-cl2)
|
||||
add_executable(${name} ${name}.cc $<TARGET_OBJECTS:llhttp>
|
||||
$<TARGET_OBJECTS:url-parser>
|
||||
)
|
||||
target_include_directories(${name} PRIVATE
|
||||
${OPENSSL_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(${name}
|
||||
nghttp2
|
||||
nghttp2_asio
|
||||
${JEMALLOC_LIBRARIES}
|
||||
${OPENSSL_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
${APP_LIBRARIES}
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -30,7 +30,6 @@ AM_CXXFLAGS = $(WARNCXXFLAGS) $(CXX1XCXXFLAGS)
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/lib/includes \
|
||||
-I$(top_builddir)/lib/includes \
|
||||
-I$(top_srcdir)/src/includes \
|
||||
-I$(top_srcdir)/third-party \
|
||||
@LIBEVENT_OPENSSL_CFLAGS@ \
|
||||
@OPENSSL_CFLAGS@ \
|
||||
|
@ -52,40 +51,4 @@ libevent_server_SOURCES = libevent-server.c
|
|||
|
||||
deflate_SOURCES = deflate.c
|
||||
|
||||
if ENABLE_ASIO_LIB
|
||||
|
||||
noinst_PROGRAMS += asio-sv asio-sv2 asio-cl asio-cl2
|
||||
|
||||
# AM_CPPFLAGS must be placed first, so that header file (e.g.,
|
||||
# nghttp2/nghttp2.h) in this package is used rather than installed
|
||||
# one.
|
||||
ASIOCPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
|
||||
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
|
||||
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
|
||||
$(top_builddir)/third-party/liburl-parser.la \
|
||||
@OPENSSL_LIBS@ \
|
||||
${BOOST_LDFLAGS} \
|
||||
${BOOST_ASIO_LIB} \
|
||||
${BOOST_THREAD_LIB} \
|
||||
${BOOST_SYSTEM_LIB} \
|
||||
@APPLDFLAGS@
|
||||
|
||||
asio_sv_SOURCES = asio-sv.cc
|
||||
asio_sv_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
asio_sv_LDADD = ${ASIOLDADD}
|
||||
|
||||
asio_sv2_SOURCES = asio-sv2.cc
|
||||
asio_sv2_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
asio_sv2_LDADD = ${ASIOLDADD}
|
||||
|
||||
asio_cl_SOURCES = asio-cl.cc
|
||||
asio_cl_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
asio_cl_LDADD = ${ASIOLDADD}
|
||||
|
||||
asio_cl2_SOURCES = asio-cl2.cc
|
||||
asio_cl2_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
asio_cl2_LDADD = ${ASIOLDADD}
|
||||
|
||||
endif # ENABLE_ASIO_LIB
|
||||
|
||||
endif # ENABLE_EXAMPLES
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::client;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
try {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: asio-cl URI" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
boost::system::error_code ec;
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
std::string uri = argv[1];
|
||||
std::string scheme, host, service;
|
||||
|
||||
if (host_service_from_uri(ec, scheme, host, service, uri)) {
|
||||
std::cerr << "error: bad URI: " << ec.message() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
boost::asio::ssl::context tls_ctx(boost::asio::ssl::context::sslv23);
|
||||
tls_ctx.set_default_verify_paths();
|
||||
// disabled to make development easier...
|
||||
// tls_ctx.set_verify_mode(boost::asio::ssl::verify_peer);
|
||||
configure_tls_context(ec, tls_ctx);
|
||||
|
||||
auto sess = scheme == "https" ? session(io_service, tls_ctx, host, service)
|
||||
: session(io_service, host, service);
|
||||
|
||||
sess.on_connect([&sess, &uri](tcp::resolver::iterator endpoint_it) {
|
||||
boost::system::error_code ec;
|
||||
auto req = sess.submit(ec, "GET", uri);
|
||||
|
||||
if (ec) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
req->on_response([](const response &res) {
|
||||
std::cerr << "HTTP/2 " << res.status_code() << std::endl;
|
||||
for (auto &kv : res.header()) {
|
||||
std::cerr << kv.first << ": " << kv.second.value << "\n";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
res.on_data([](const uint8_t *data, std::size_t len) {
|
||||
std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
std::cerr << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
req->on_close([&sess](uint32_t error_code) { sess.shutdown(); });
|
||||
});
|
||||
|
||||
sess.on_error([](const boost::system::error_code &ec) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
});
|
||||
|
||||
io_service.run();
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::client;
|
||||
|
||||
void print_header(const header_map &h) {
|
||||
for (auto &kv : h) {
|
||||
std::cerr << kv.first << ": " << kv.second.value << "\n";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
void print_header(const response &res) {
|
||||
std::cerr << "HTTP/2 " << res.status_code() << "\n";
|
||||
print_header(res.header());
|
||||
}
|
||||
|
||||
void print_header(const request &req) {
|
||||
auto &uri = req.uri();
|
||||
std::cerr << req.method() << " " << uri.scheme << "://" << uri.host
|
||||
<< uri.path;
|
||||
if (!uri.raw_query.empty()) {
|
||||
std::cerr << "?" << uri.raw_query;
|
||||
}
|
||||
std::cerr << " HTTP/2\n";
|
||||
print_header(req.header());
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
try {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: asio-cl URI" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
boost::system::error_code ec;
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
std::string uri = argv[1];
|
||||
std::string scheme, host, service;
|
||||
|
||||
if (host_service_from_uri(ec, scheme, host, service, uri)) {
|
||||
std::cerr << "error: bad URI: " << ec.message() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
boost::asio::ssl::context tls_ctx(boost::asio::ssl::context::sslv23);
|
||||
tls_ctx.set_default_verify_paths();
|
||||
// disabled to make development easier...
|
||||
// tls_ctx.set_verify_mode(boost::asio::ssl::verify_peer);
|
||||
configure_tls_context(ec, tls_ctx);
|
||||
|
||||
auto sess = scheme == "https" ? session(io_service, tls_ctx, host, service)
|
||||
: session(io_service, host, service);
|
||||
|
||||
sess.on_connect([&sess, &uri](tcp::resolver::iterator endpoint_it) {
|
||||
std::cerr << "connected to " << (*endpoint_it).endpoint() << std::endl;
|
||||
boost::system::error_code ec;
|
||||
auto req = sess.submit(ec, "GET", uri, {{"cookie", {"foo=bar", true}}});
|
||||
if (ec) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
req->on_response([](const response &res) {
|
||||
std::cerr << "response header was received" << std::endl;
|
||||
print_header(res);
|
||||
|
||||
res.on_data([](const uint8_t *data, std::size_t len) {
|
||||
std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
std::cerr << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
req->on_close([](uint32_t error_code) {
|
||||
std::cerr << "request done with error_code=" << error_code << std::endl;
|
||||
});
|
||||
|
||||
req->on_push([](const request &push_req) {
|
||||
std::cerr << "push request was received" << std::endl;
|
||||
|
||||
print_header(push_req);
|
||||
|
||||
push_req.on_response([](const response &res) {
|
||||
std::cerr << "push response header was received" << std::endl;
|
||||
|
||||
res.on_data([](const uint8_t *data, std::size_t len) {
|
||||
std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
std::cerr << std::endl;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
sess.on_error([](const boost::system::error_code &ec) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
});
|
||||
|
||||
io_service.run();
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,149 +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.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// main.cpp
|
||||
// ~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
try {
|
||||
// Check command line arguments.
|
||||
if (argc < 4) {
|
||||
std::cerr
|
||||
<< "Usage: asio-sv <address> <port> <threads> [<private-key-file> "
|
||||
<< "<cert-file>]\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
|
||||
std::string addr = argv[1];
|
||||
std::string port = argv[2];
|
||||
std::size_t num_threads = std::stoi(argv[3]);
|
||||
|
||||
http2 server;
|
||||
|
||||
server.num_threads(num_threads);
|
||||
|
||||
server.handle("/", [](const request &req, const response &res) {
|
||||
res.write_head(200, {{"foo", {"bar"}}});
|
||||
res.end("hello, world\n");
|
||||
});
|
||||
server.handle("/secret/", [](const request &req, const response &res) {
|
||||
res.write_head(200);
|
||||
res.end("under construction!\n");
|
||||
});
|
||||
server.handle("/push", [](const request &req, const response &res) {
|
||||
boost::system::error_code ec;
|
||||
auto push = res.push(ec, "GET", "/push/1");
|
||||
if (!ec) {
|
||||
push->write_head(200);
|
||||
push->end("server push FTW!\n");
|
||||
}
|
||||
|
||||
res.write_head(200);
|
||||
res.end("you'll receive server push!\n");
|
||||
});
|
||||
server.handle("/delay", [](const request &req, const response &res) {
|
||||
res.write_head(200);
|
||||
|
||||
auto timer = std::make_shared<boost::asio::deadline_timer>(
|
||||
res.io_service(), boost::posix_time::seconds(3));
|
||||
auto closed = std::make_shared<bool>();
|
||||
|
||||
res.on_close([timer, closed](uint32_t error_code) {
|
||||
timer->cancel();
|
||||
*closed = true;
|
||||
});
|
||||
|
||||
timer->async_wait([&res, closed](const boost::system::error_code &ec) {
|
||||
if (ec || *closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
res.end("finally!\n");
|
||||
});
|
||||
});
|
||||
server.handle("/trailer", [](const request &req, const response &res) {
|
||||
// send trailer part.
|
||||
res.write_head(200, {{"trailers", {"digest"}}});
|
||||
|
||||
std::string body = "nghttp2 FTW!\n";
|
||||
auto left = std::make_shared<size_t>(body.size());
|
||||
|
||||
res.end([&res, body, left](uint8_t *dst, std::size_t len,
|
||||
uint32_t *data_flags) {
|
||||
auto n = std::min(len, *left);
|
||||
std::copy_n(body.c_str() + (body.size() - *left), n, dst);
|
||||
*left -= n;
|
||||
if (*left == 0) {
|
||||
*data_flags |=
|
||||
NGHTTP2_DATA_FLAG_EOF | NGHTTP2_DATA_FLAG_NO_END_STREAM;
|
||||
// RFC 3230 Instance Digests in HTTP. The digest value is
|
||||
// SHA-256 message digest of body.
|
||||
res.write_trailer(
|
||||
{{"digest",
|
||||
{"SHA-256=qqXqskW7F3ueBSvmZRCiSwl2ym4HRO0M/pvQCBlSDis="}}});
|
||||
}
|
||||
return n;
|
||||
});
|
||||
});
|
||||
|
||||
if (argc >= 6) {
|
||||
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
|
||||
tls.use_private_key_file(argv[4], boost::asio::ssl::context::pem);
|
||||
tls.use_certificate_chain_file(argv[5]);
|
||||
|
||||
configure_tls_context_easy(ec, tls);
|
||||
|
||||
if (server.listen_and_serve(ec, tls, addr, port)) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
}
|
||||
} else {
|
||||
if (server.listen_and_serve(ec, addr, port)) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,125 +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.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// main.cpp
|
||||
// ~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif // HAVE_UNISTD_H
|
||||
#ifdef HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
#endif // HAVE_FCNTL_H
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
try {
|
||||
// Check command line arguments.
|
||||
if (argc < 5) {
|
||||
std::cerr << "Usage: asio-sv2 <address> <port> <threads> <doc-root> "
|
||||
<< "[<private-key-file> <cert-file>]\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
|
||||
std::string addr = argv[1];
|
||||
std::string port = argv[2];
|
||||
std::size_t num_threads = std::stoi(argv[3]);
|
||||
std::string docroot = argv[4];
|
||||
|
||||
http2 server;
|
||||
|
||||
server.num_threads(num_threads);
|
||||
|
||||
server.handle("/", [&docroot](const request &req, const response &res) {
|
||||
auto path = percent_decode(req.uri().path);
|
||||
if (!check_path(path)) {
|
||||
res.write_head(404);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (path == "/") {
|
||||
path = "/index.html";
|
||||
}
|
||||
|
||||
path = docroot + path;
|
||||
auto fd = open(path.c_str(), O_RDONLY);
|
||||
if (fd == -1) {
|
||||
res.write_head(404);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
auto header = header_map();
|
||||
|
||||
struct stat stbuf;
|
||||
if (stat(path.c_str(), &stbuf) == 0) {
|
||||
header.emplace("content-length",
|
||||
header_value{std::to_string(stbuf.st_size)});
|
||||
header.emplace("last-modified",
|
||||
header_value{http_date(stbuf.st_mtime)});
|
||||
}
|
||||
res.write_head(200, std::move(header));
|
||||
res.end(file_generator_from_fd(fd));
|
||||
});
|
||||
|
||||
if (argc >= 7) {
|
||||
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
|
||||
tls.use_private_key_file(argv[5], boost::asio::ssl::context::pem);
|
||||
tls.use_certificate_chain_file(argv[6]);
|
||||
|
||||
configure_tls_context_easy(ec, tls);
|
||||
|
||||
if (server.listen_and_serve(ec, tls, addr, port)) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
}
|
||||
} else {
|
||||
if (server.listen_and_serve(ec, addr, port)) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
19
go.mod
19
go.mod
|
@ -4,8 +4,23 @@ go 1.18
|
|||
|
||||
require (
|
||||
github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d
|
||||
github.com/lucas-clemente/quic-go v0.30.0
|
||||
github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20150408091349-4742878d9c90
|
||||
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
|
||||
)
|
||||
|
||||
require golang.org/x/text v0.3.7 // indirect
|
||||
require (
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/marten-seemann/qpack v0.3.0 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
)
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d h1:pVrfxiGfwelyab6n21ZBkbkmbevaf+WvMIiR7sr97hw=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/lucas-clemente/quic-go v0.30.0 h1:nwLW0h8ahVQ5EPTIM7uhl/stHqQDea15oRlYKZmw2O0=
|
||||
github.com/lucas-clemente/quic-go v0.30.0/go.mod h1:ssOrRsOmdxa768Wr78vnh2B8JozgLsMzG/g+0qEC7uk=
|
||||
github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
|
||||
github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20150408091349-4742878d9c90 h1:ccVm9C6f5YMcVv6t9MXahIDkqVvzD6vklkJTIE4D2nY=
|
||||
github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20150408091349-4742878d9c90/go.mod h1:YZhsh86DfZgAShPKeg1eBLVrmuQxWcR9H4TdpgNvSnw=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
@ -24,6 +24,7 @@
|
|||
GO_FILES = \
|
||||
nghttpx_http1_test.go \
|
||||
nghttpx_http2_test.go \
|
||||
nghttpx_http3_test.go \
|
||||
server_tester.go
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
@ -39,6 +40,12 @@ EXTRA_DIST = \
|
|||
req-return.rb \
|
||||
resp-return.rb
|
||||
|
||||
GO_TEST_TAGS =
|
||||
|
||||
if ENABLE_HTTP3
|
||||
GO_TEST_TAGS += quic
|
||||
endif # ENABLE_HTTP3
|
||||
|
||||
it:
|
||||
for i in $(GO_FILES); do [ -e $(builddir)/$$i ] || cp $(srcdir)/$$i $(builddir); done
|
||||
sh setenv go test -v
|
||||
sh setenv go test -v --tags=${GO_TEST_TAGS}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package nghttp2
|
||||
|
||||
const (
|
||||
buildDir = "@top_builddir@"
|
||||
buildDir = "@top_builddir@"
|
||||
sourceDir = "@top_srcdir@"
|
||||
)
|
||||
|
|
|
@ -28,8 +28,7 @@ func TestH1H1PlainGET(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
want := 200
|
||||
if got := res.status; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +49,7 @@ func TestH1H1PlainGETClose(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
want := 200
|
||||
if got := res.status; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +73,7 @@ func TestH1H1InvalidMethod(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 501; got != want {
|
||||
if got, want := res.status, http.StatusNotImplemented; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -101,8 +99,9 @@ func TestH1H1MultipleRequestCL(t *testing.T) {
|
|||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
|
||||
want := 400
|
||||
if got := resp.StatusCode; got != want {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusBadRequest; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +143,7 @@ func TestH1H1AffinityCookie(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -172,7 +171,7 @@ func TestH1H1AffinityCookieTLS(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -195,11 +194,14 @@ func TestH1H1GracefulShutdown(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
|
||||
st.cmd.Process.Signal(syscall.SIGQUIT)
|
||||
if err := st.cmd.Process.Signal(syscall.SIGQUIT); err != nil {
|
||||
t.Fatalf("Error st.cmd.Process.Signal() = %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
res, err = st.http1(requestParam{
|
||||
|
@ -209,7 +211,7 @@ func TestH1H1GracefulShutdown(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -241,7 +243,7 @@ func TestH1H1HostRewrite(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
if got, want := res.header.Get("request-host"), st.backendHost; got != want {
|
||||
|
@ -267,7 +269,10 @@ func TestH1H1BadHost(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
if got, want := resp.StatusCode, 400; got != want {
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusBadRequest; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -290,7 +295,10 @@ func TestH1H1BadAuthority(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
if got, want := resp.StatusCode, 400; got != want {
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusBadRequest; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -313,7 +321,10 @@ func TestH1H1BadScheme(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
if got, want := resp.StatusCode, 400; got != want {
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusBadRequest; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +349,9 @@ func TestH1H1HTTP10(t *testing.T) {
|
|||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := resp.StatusCode, 200; got != want {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusOK; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
|
||||
|
@ -367,7 +380,9 @@ func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
|
|||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := resp.StatusCode, 200; got != want {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusOK; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
|
||||
|
@ -408,7 +423,7 @@ func TestH1H1RequestTrailer(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -435,7 +450,7 @@ func TestH1H1HeaderFieldBufferPath(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 431; got != want {
|
||||
if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -458,7 +473,7 @@ func TestH1H1HeaderFieldBuffer(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 431; got != want {
|
||||
if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -486,7 +501,7 @@ func TestH1H1HeaderFields(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 431; got != want {
|
||||
if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -495,20 +510,19 @@ func TestH1H1HeaderFields(t *testing.T) {
|
|||
func TestH1H1Websocket(t *testing.T) {
|
||||
opts := options{
|
||||
handler: websocket.Handler(func(ws *websocket.Conn) {
|
||||
io.Copy(ws, ws)
|
||||
if _, err := io.Copy(ws, ws); err != nil {
|
||||
t.Fatalf("Error io.Copy() = %v", err)
|
||||
}
|
||||
}).ServeHTTP,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
content := []byte("hello world")
|
||||
res, err := st.websocket(requestParam{
|
||||
res := st.websocket(requestParam{
|
||||
name: "TestH1H1Websocket",
|
||||
body: content,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.websocket() = %v", err)
|
||||
}
|
||||
if got, want := res.body, content; !bytes.Equal(got, want) {
|
||||
t.Errorf("echo: %q; want %q", got, want)
|
||||
}
|
||||
|
@ -535,7 +549,7 @@ func TestH1H1ReqPhaseSetHeader(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -559,7 +573,7 @@ func TestH1H1ReqPhaseReturn(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 404; got != want {
|
||||
if got, want := res.status, http.StatusNotFound; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -596,7 +610,7 @@ func TestH1H1RespPhaseSetHeader(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -621,7 +635,7 @@ func TestH1H1RespPhaseReturn(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 404; got != want {
|
||||
if got, want := res.status, http.StatusNotFound; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -658,7 +672,7 @@ func TestH1H1HTTPSRedirect(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 308; got != want {
|
||||
if got, want := res.status, http.StatusPermanentRedirect; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want {
|
||||
|
@ -686,7 +700,7 @@ func TestH1H1HTTPSRedirectPort(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 308; got != want {
|
||||
if got, want := res.status, http.StatusPermanentRedirect; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
if got, want := res.header.Get("location"), "https://127.0.0.1:8443/foo?bar"; got != want {
|
||||
|
@ -707,7 +721,7 @@ func TestH1H1POSTRequests(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -718,7 +732,7 @@ func TestH1H1POSTRequests(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -769,8 +783,9 @@ func TestH1H2NoHost(t *testing.T) {
|
|||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
|
||||
want := 400
|
||||
if got := resp.StatusCode; got != want {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusBadRequest; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -796,7 +811,9 @@ func TestH1H2HTTP10(t *testing.T) {
|
|||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := resp.StatusCode, 200; got != want {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusOK; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
|
||||
|
@ -826,7 +843,9 @@ func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
|
|||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := resp.StatusCode, 200; got != want {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusOK; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
|
||||
|
@ -859,7 +878,7 @@ func TestH1H2CrumbleCookie(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -969,7 +988,7 @@ func TestH1H2ReqPhaseReturn(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 404; got != want {
|
||||
if got, want := res.status, http.StatusNotFound; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -1009,7 +1028,7 @@ func TestH1H2RespPhaseReturn(t *testing.T) {
|
|||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, 404; got != want {
|
||||
if got, want := res.status, http.StatusNotFound; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -1053,7 +1072,7 @@ func TestH1H2TE(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -1083,7 +1102,7 @@ backend=127.0.0.1,3011
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -1125,7 +1144,7 @@ backend=127.0.0.1,3011
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -1167,7 +1186,7 @@ backend=127.0.0.1,3011
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 405; got != want {
|
||||
if got, want := res.status, http.StatusMethodNotAllowed; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -1204,7 +1223,7 @@ func TestH1APIConfigrevision(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("res.status: %v; want = %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -1251,7 +1270,7 @@ backend=127.0.0.1,3011
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 404; got != want {
|
||||
if got, want := res.status, http.StatusNotFound; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
|
||||
|
@ -1287,7 +1306,7 @@ func TestH1Healthmon(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, 200; got != want {
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -1314,7 +1333,9 @@ func TestH1ResponseBeforeRequestEnd(t *testing.T) {
|
|||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := resp.StatusCode, 404; got != want {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusNotFound; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -1335,7 +1356,9 @@ func TestH1H1ChunkedEndsPrematurely(t *testing.T) {
|
|||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n")
|
||||
if _, err := bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n"); err != nil {
|
||||
t.Fatalf("Error bufrw.WriteString() = %v", err)
|
||||
}
|
||||
bufrw.Flush()
|
||||
},
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,393 @@
|
|||
//go:build quic
|
||||
|
||||
package nghttp2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/http2/hpack"
|
||||
)
|
||||
|
||||
// TestH3H1PlainGET tests whether simple HTTP/3 GET request works.
|
||||
func TestH3H1PlainGET(t *testing.T) {
|
||||
st := newServerTester(t, options{
|
||||
quic: true,
|
||||
})
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3H1PlainGET",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H1RequestBody tests HTTP/3 request with body works.
|
||||
func TestH3H1RequestBody(t *testing.T) {
|
||||
body := make([]byte, 3333)
|
||||
_, err := rand.Read(body)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create request body: %v", err)
|
||||
}
|
||||
|
||||
opts := options{
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
buf := make([]byte, 4096)
|
||||
buflen := 0
|
||||
p := buf
|
||||
|
||||
for {
|
||||
if len(p) == 0 {
|
||||
t.Fatal("Request body is too large")
|
||||
}
|
||||
|
||||
n, err := r.Body.Read(p)
|
||||
|
||||
p = p[n:]
|
||||
buflen += n
|
||||
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
t.Fatalf("r.Body.Read() = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
buf = buf[:buflen]
|
||||
|
||||
if got, want := buf, body; !bytes.Equal(got, want) {
|
||||
t.Fatalf("buf = %v; want %v", got, want)
|
||||
}
|
||||
},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3H1RequestBody",
|
||||
body: body,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H1GenerateVia tests that server generates Via header field to
|
||||
// and from backend server.
|
||||
func TestH3H1GenerateVia(t *testing.T) {
|
||||
opts := options{
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if got, want := r.Header.Get("Via"), "3 nghttpx"; got != want {
|
||||
t.Errorf("Via: %v; want %v", got, want)
|
||||
}
|
||||
},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3H1GenerateVia",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want {
|
||||
t.Errorf("Via: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H1AppendVia tests that server adds value to existing Via
|
||||
// header field to and from backend server.
|
||||
func TestH3H1AppendVia(t *testing.T) {
|
||||
opts := options{
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if got, want := r.Header.Get("Via"), "foo, 3 nghttpx"; got != want {
|
||||
t.Errorf("Via: %v; want %v", got, want)
|
||||
}
|
||||
w.Header().Add("Via", "bar")
|
||||
},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3H1AppendVia",
|
||||
header: []hpack.HeaderField{
|
||||
pair("via", "foo"),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want {
|
||||
t.Errorf("Via: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H1NoVia tests that server does not add value to existing Via
|
||||
// header field to and from backend server.
|
||||
func TestH3H1NoVia(t *testing.T) {
|
||||
opts := options{
|
||||
args: []string{"--no-via"},
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if got, want := r.Header.Get("Via"), "foo"; got != want {
|
||||
t.Errorf("Via: %v; want %v", got, want)
|
||||
}
|
||||
w.Header().Add("Via", "bar")
|
||||
},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3H1NoVia",
|
||||
header: []hpack.HeaderField{
|
||||
pair("via", "foo"),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
if got, want := res.header.Get("Via"), "bar"; got != want {
|
||||
t.Errorf("Via: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H1BadResponseCL tests that server returns error when
|
||||
// content-length response header field value does not match its
|
||||
// response body size.
|
||||
func TestH3H1BadResponseCL(t *testing.T) {
|
||||
opts := options{
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
// we set content-length: 1024, but only send 3 bytes.
|
||||
w.Header().Add("Content-Length", "1024")
|
||||
if _, err := w.Write([]byte("foo")); err != nil {
|
||||
t.Fatalf("Error w.Write() = %v", err)
|
||||
}
|
||||
},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
_, err := st.http3(requestParam{
|
||||
name: "TestH3H1BadResponseCL",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("st.http3() should fail")
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H1HTTPSRedirect tests that HTTPS redirect should not happen
|
||||
// with HTTP/3.
|
||||
func TestH3H1HTTPSRedirect(t *testing.T) {
|
||||
opts := options{
|
||||
args: []string{"--redirect-if-not-tls"},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3H1HTTPSRedirect",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H1AffinityCookieTLS tests that affinity cookie is sent back
|
||||
// in https.
|
||||
func TestH3H1AffinityCookieTLS(t *testing.T) {
|
||||
opts := options{
|
||||
args: []string{"--affinity-cookie"},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3H1AffinityCookieTLS",
|
||||
scheme: "https",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, http.StatusOK; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure`
|
||||
validCookie := regexp.MustCompile(pattern)
|
||||
if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
|
||||
t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H2ReqPhaseReturn tests mruby request phase hook returns
|
||||
// custom response.
|
||||
func TestH3H2ReqPhaseReturn(t *testing.T) {
|
||||
opts := options{
|
||||
args: []string{
|
||||
"--http2-bridge",
|
||||
"--mruby-file=" + testDir + "/req-return.rb",
|
||||
},
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Fatalf("request should not be forwarded")
|
||||
},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3H2ReqPhaseReturn",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, http.StatusNotFound; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
hdtests := []struct {
|
||||
k, v string
|
||||
}{
|
||||
{"content-length", "20"},
|
||||
{"from", "mruby"},
|
||||
}
|
||||
for _, tt := range hdtests {
|
||||
if got, want := res.header.Get(tt.k), tt.v; got != want {
|
||||
t.Errorf("%v = %v; want %v", tt.k, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
if got, want := string(res.body), "Hello World from req"; got != want {
|
||||
t.Errorf("body = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H2RespPhaseReturn tests mruby response phase hook returns
|
||||
// custom response.
|
||||
func TestH3H2RespPhaseReturn(t *testing.T) {
|
||||
opts := options{
|
||||
args: []string{
|
||||
"--http2-bridge",
|
||||
"--mruby-file=" + testDir + "/resp-return.rb",
|
||||
},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3H2RespPhaseReturn",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
|
||||
if got, want := res.status, http.StatusNotFound; got != want {
|
||||
t.Errorf("status = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
hdtests := []struct {
|
||||
k, v string
|
||||
}{
|
||||
{"content-length", "21"},
|
||||
{"from", "mruby"},
|
||||
}
|
||||
for _, tt := range hdtests {
|
||||
if got, want := res.header.Get(tt.k), tt.v; got != want {
|
||||
t.Errorf("%v = %v; want %v", tt.k, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
if got, want := string(res.body), "Hello World from resp"; got != want {
|
||||
t.Errorf("body = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3ResponseBeforeRequestEnd tests the situation where response
|
||||
// ends before request body finishes.
|
||||
func TestH3ResponseBeforeRequestEnd(t *testing.T) {
|
||||
opts := options{
|
||||
args: []string{"--mruby-file=" + testDir + "/req-return.rb"},
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Fatal("request should not be forwarded")
|
||||
},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http3(requestParam{
|
||||
name: "TestH3ResponseBeforeRequestEnd",
|
||||
noEndStream: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http3() = %v", err)
|
||||
}
|
||||
if got, want := res.status, http.StatusNotFound; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH3H1ChunkedEndsPrematurely tests that a stream is reset if the
|
||||
// backend chunked encoded response ends prematurely.
|
||||
func TestH3H1ChunkedEndsPrematurely(t *testing.T) {
|
||||
opts := options{
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
hj, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
conn, bufrw, err := hj.Hijack()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
if _, err := bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n"); err != nil {
|
||||
t.Fatalf("Error bufrw.WriteString() = %v", err)
|
||||
}
|
||||
bufrw.Flush()
|
||||
},
|
||||
quic: true,
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
_, err := st.http3(requestParam{
|
||||
name: "TestH3H1ChunkedEndsPrematurely",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("st.http3() should fail")
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package nghttp2
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
|
@ -21,6 +22,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/http3"
|
||||
"github.com/tatsuhiro-t/go-nghttp2"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
|
@ -42,7 +44,6 @@ func pair(name, value string) hpack.HeaderField {
|
|||
}
|
||||
|
||||
type serverTester struct {
|
||||
args []string // command-line arguments
|
||||
cmd *exec.Cmd // test frontend server process, which is test subject
|
||||
url string // test frontend server URL
|
||||
t *testing.T
|
||||
|
@ -80,10 +81,17 @@ type options struct {
|
|||
// before TLS handshake starts. This field is ignored if tls
|
||||
// is false.
|
||||
tcpData []byte
|
||||
// quic, if set to true, sets up QUIC frontend connection.
|
||||
// quic implies tls = true.
|
||||
quic bool
|
||||
}
|
||||
|
||||
// newServerTester creates test context.
|
||||
func newServerTester(t *testing.T, opts options) *serverTester {
|
||||
if opts.quic {
|
||||
opts.tls = true
|
||||
}
|
||||
|
||||
if opts.handler == nil {
|
||||
opts.handler = noopHandler
|
||||
}
|
||||
|
@ -182,6 +190,12 @@ func newServerTester(t *testing.T, opts options) *serverTester {
|
|||
args = append(args, fmt.Sprintf("-f127.0.0.1,%v%v%v", serverPort, noTLS, proxyProto), b,
|
||||
"--errorlog-file="+logDir+"/log.txt", "-LINFO")
|
||||
|
||||
if opts.quic {
|
||||
args = append(args,
|
||||
fmt.Sprintf("-f127.0.0.1,%v;quic", serverPort),
|
||||
"--no-quic-bpf")
|
||||
}
|
||||
|
||||
authority := fmt.Sprintf("127.0.0.1:%v", opts.connectPort)
|
||||
|
||||
st := &serverTester{
|
||||
|
@ -232,16 +246,11 @@ func newServerTester(t *testing.T, opts options) *serverTester {
|
|||
tlsConn := tls.Client(conn, tlsConfig)
|
||||
err = tlsConn.Handshake()
|
||||
if err == nil {
|
||||
cs := tlsConn.ConnectionState()
|
||||
if !cs.NegotiatedProtocolIsMutual {
|
||||
st.Close()
|
||||
st.t.Fatalf("Error negotiated next protocol is not mutual")
|
||||
}
|
||||
conn = tlsConn
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
retry += 1
|
||||
retry++
|
||||
if retry >= 100 {
|
||||
st.Close()
|
||||
st.t.Fatalf("Error server is not responding too long; server command-line arguments may be invalid")
|
||||
|
@ -268,16 +277,22 @@ func (st *serverTester) Close() {
|
|||
if st.cmd != nil {
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
st.cmd.Wait()
|
||||
if err := st.cmd.Wait(); err != nil {
|
||||
st.t.Errorf("Error st.cmd.Wait() = %v", err)
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
|
||||
st.cmd.Process.Signal(syscall.SIGQUIT)
|
||||
if err := st.cmd.Process.Signal(syscall.SIGQUIT); err != nil {
|
||||
st.t.Errorf("Error st.cmd.Process.Signal() = %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(10 * time.Second):
|
||||
st.cmd.Process.Kill()
|
||||
if err := st.cmd.Process.Kill(); err != nil {
|
||||
st.t.Errorf("Error st.cmd.Process.Kill() = %v", err)
|
||||
}
|
||||
<-done
|
||||
}
|
||||
}
|
||||
|
@ -340,7 +355,7 @@ func (cbr *chunkedBodyReader) Read(p []byte) (n int, err error) {
|
|||
return cbr.body.Read(p)
|
||||
}
|
||||
|
||||
func (st *serverTester) websocket(rp requestParam) (*serverResponse, error) {
|
||||
func (st *serverTester) websocket(rp requestParam) *serverResponse {
|
||||
urlstring := st.url + "/echo"
|
||||
|
||||
config, err := websocket.NewConfig(urlstring, st.url)
|
||||
|
@ -372,6 +387,81 @@ func (st *serverTester) websocket(rp requestParam) (*serverResponse, error) {
|
|||
body: msg[:n],
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (st *serverTester) http3(rp requestParam) (*serverResponse, error) {
|
||||
rt := &http3.RoundTripper{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
|
||||
defer rt.Close()
|
||||
|
||||
c := &http.Client{
|
||||
Transport: rt,
|
||||
}
|
||||
|
||||
method := "GET"
|
||||
if rp.method != "" {
|
||||
method = rp.method
|
||||
}
|
||||
|
||||
var body io.Reader
|
||||
|
||||
if rp.body != nil {
|
||||
body = bytes.NewBuffer(rp.body)
|
||||
}
|
||||
|
||||
reqURL := st.url
|
||||
|
||||
if rp.path != "" {
|
||||
u, err := url.Parse(st.url)
|
||||
if err != nil {
|
||||
st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err)
|
||||
}
|
||||
u.Path = ""
|
||||
u.RawQuery = ""
|
||||
reqURL = u.String() + rp.path
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, method, reqURL, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, h := range rp.header {
|
||||
req.Header.Add(h.Name, h.Value)
|
||||
}
|
||||
|
||||
req.Header.Add("Test-Case", rp.name)
|
||||
|
||||
// TODO http3 package does not support trailer at the time of
|
||||
// this writing.
|
||||
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := &serverResponse{
|
||||
status: resp.StatusCode,
|
||||
header: resp.Header,
|
||||
body: respBody,
|
||||
connClose: resp.Close,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
@ -406,7 +496,10 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
|
|||
reqURL = u.String() + rp.path
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, reqURL, body)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, method, reqURL, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -664,7 +757,9 @@ func cloneHeader(h http.Header) http.Header {
|
|||
}
|
||||
|
||||
func noopHandler(w http.ResponseWriter, r *http.Request) {
|
||||
io.ReadAll(r.Body)
|
||||
if _, err := io.ReadAll(r.Body); err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error io.ReadAll() = %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
type APIResponse struct {
|
||||
|
@ -704,9 +799,13 @@ const (
|
|||
proxyProtocolV2ProtocolDgram proxyProtocolV2Protocol = 0x2
|
||||
)
|
||||
|
||||
func writeProxyProtocolV2(w io.Writer, hdr proxyProtocolV2) {
|
||||
w.Write([]byte{0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A})
|
||||
w.Write([]byte{byte(0x20 | hdr.command)})
|
||||
func writeProxyProtocolV2(w io.Writer, hdr proxyProtocolV2) error {
|
||||
if _, err := w.Write([]byte{0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A}); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte{byte(0x20 | hdr.command)}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch srcAddr := hdr.sourceAddress.(type) {
|
||||
case *net.TCPAddr:
|
||||
|
@ -721,13 +820,25 @@ func writeProxyProtocolV2(w io.Writer, hdr proxyProtocolV2) {
|
|||
fam = byte(proxyProtocolV2FamilyInet6 << 4)
|
||||
}
|
||||
fam |= byte(proxyProtocolV2ProtocolStream)
|
||||
w.Write([]byte{fam})
|
||||
if _, err := w.Write([]byte{fam}); err != nil {
|
||||
return err
|
||||
}
|
||||
length := uint16(len(srcAddr.IP)*2 + 4 + len(hdr.additionalData))
|
||||
binary.Write(w, binary.BigEndian, length)
|
||||
w.Write(srcAddr.IP)
|
||||
w.Write(dstAddr.IP)
|
||||
binary.Write(w, binary.BigEndian, uint16(srcAddr.Port))
|
||||
binary.Write(w, binary.BigEndian, uint16(dstAddr.Port))
|
||||
if err := binary.Write(w, binary.BigEndian, length); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(srcAddr.IP); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(dstAddr.IP); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.BigEndian, uint16(srcAddr.Port)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.BigEndian, uint16(dstAddr.Port)); err != nil {
|
||||
return err
|
||||
}
|
||||
case *net.UnixAddr:
|
||||
dstAddr := hdr.destinationAddress.(*net.UnixAddr)
|
||||
if len(srcAddr.Name) > 108 {
|
||||
|
@ -745,20 +856,40 @@ func writeProxyProtocolV2(w io.Writer, hdr proxyProtocolV2) {
|
|||
default:
|
||||
fam |= byte(proxyProtocolV2ProtocolUnspec)
|
||||
}
|
||||
w.Write([]byte{fam})
|
||||
if _, err := w.Write([]byte{fam}); err != nil {
|
||||
return err
|
||||
}
|
||||
length := uint16(216 + len(hdr.additionalData))
|
||||
binary.Write(w, binary.BigEndian, length)
|
||||
if err := binary.Write(w, binary.BigEndian, length); err != nil {
|
||||
return err
|
||||
}
|
||||
zeros := make([]byte, 108)
|
||||
w.Write([]byte(srcAddr.Name))
|
||||
w.Write(zeros[:108-len(srcAddr.Name)])
|
||||
w.Write([]byte(dstAddr.Name))
|
||||
w.Write(zeros[:108-len(dstAddr.Name)])
|
||||
if _, err := w.Write([]byte(srcAddr.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(zeros[:108-len(srcAddr.Name)]); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte(dstAddr.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(zeros[:108-len(dstAddr.Name)]); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
fam := byte(proxyProtocolV2FamilyUnspec<<4) | byte(proxyProtocolV2ProtocolUnspec)
|
||||
w.Write([]byte{fam})
|
||||
if _, err := w.Write([]byte{fam}); err != nil {
|
||||
return err
|
||||
}
|
||||
length := uint16(len(hdr.additionalData))
|
||||
binary.Write(w, binary.BigEndian, length)
|
||||
if err := binary.Write(w, binary.BigEndian, length); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
w.Write(hdr.additionalData)
|
||||
if _, err := w.Write(hdr.additionalData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,15 +6,8 @@
|
|||
# The MIT License apply.
|
||||
#
|
||||
|
||||
#
|
||||
# Choose your weapons:
|
||||
# Set 'USE_CYTHON=1' to build and install the 'nghttp2.pyd' Python extension.
|
||||
#
|
||||
THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||
|
||||
USE_CYTHON := 0
|
||||
#USE_CYTHON := 1
|
||||
|
||||
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV//g' -e 's/], //g')
|
||||
_VERSION := $(subst ., ,$(_VERSION))
|
||||
VER_MAJOR := $(word 1,$(_VERSION))
|
||||
|
@ -102,7 +95,7 @@ NGHTTP2_OBJ_D := $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
|||
clean_nghttp2_pyd_0 clean_nghttp2_pyd_1
|
||||
|
||||
|
||||
all: intro includes/nghttp2/nghttp2ver.h $(OBJ_DIR) $(TARGETS) build_nghttp2_pyd_$(USE_CYTHON)
|
||||
all: intro includes/nghttp2/nghttp2ver.h $(OBJ_DIR) $(TARGETS)
|
||||
@echo 'Welcome to NgHTTP2 (release + debug).'
|
||||
@echo 'Do a "make -f Makefile.MSVC install" at own risk!'
|
||||
|
||||
|
@ -121,7 +114,7 @@ $(OBJ_DIR):
|
|||
|
||||
install: includes/nghttp2/nghttp2.h includes/nghttp2/nghttp2ver.h \
|
||||
$(TARGETS) \
|
||||
copy_headers_and_libs install_nghttp2_pyd_$(USE_CYTHON)
|
||||
copy_headers_and_libs
|
||||
|
||||
#
|
||||
# This MUST be done before using the 'install_nghttp2_pyd_1' rule.
|
||||
|
@ -160,31 +153,6 @@ $(DLL_D): $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res
|
|||
WIN_OBJDIR:=$(shell cygpath -w $(abspath $(OBJ_DIR)))
|
||||
WIN_OBJDIR:=$(subst \,/,$(WIN_OBJDIR))
|
||||
|
||||
../python/setup.py: ../python/setup.py.in $(THIS_MAKEFILE)
|
||||
cd ../python ; \
|
||||
echo '# $(GENERATED). DO NOT EDIT.' > setup.py ; \
|
||||
sed -e 's/@top_srcdir@/../' \
|
||||
-e 's%@top_builddir@%$(WIN_OBJDIR)%' \
|
||||
-e 's/@PACKAGE_VERSION@/$(VERSION)/' setup.py.in >> setup.py ;
|
||||
|
||||
build_nghttp2_pyd_0: ;
|
||||
|
||||
build_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx)
|
||||
cd ../python ; \
|
||||
python setup.py build_ext -i -f bdist_wininst
|
||||
|
||||
install_nghttp2_pyd_0: ;
|
||||
|
||||
install_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx)
|
||||
cd ../python ; \
|
||||
pip install .
|
||||
|
||||
clean_nghttp2_pyd_0: ;
|
||||
|
||||
clean_nghttp2_pyd_1:
|
||||
cd ../python ; \
|
||||
rm -fR build dist
|
||||
|
||||
$(OBJ_DIR)/r_%.obj: %.c $(THIS_MAKEFILE)
|
||||
$(CC) $(CFLAGS_R) $(CFLAGS) -Fo$@ -c $<
|
||||
@echo
|
||||
|
@ -262,7 +230,7 @@ clean:
|
|||
rm -f $(OBJ_DIR)/* includes/nghttp2/nghttp2ver.h
|
||||
@echo
|
||||
|
||||
vclean realclean: clean clean_nghttp2_pyd_$(USE_CYTHON)
|
||||
vclean realclean: clean
|
||||
- rm -rf $(OBJ_DIR)
|
||||
- rm -f .depend.MSVC
|
||||
|
||||
|
|
|
@ -1430,12 +1430,6 @@ typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf,
|
|||
* respectively. The header name/value pairs are emitted via
|
||||
* :type:`nghttp2_on_header_callback`.
|
||||
*
|
||||
* For HEADERS, PUSH_PROMISE and DATA frames, this callback may be
|
||||
* called after stream is closed (see
|
||||
* :type:`nghttp2_on_stream_close_callback`). The application should
|
||||
* check that stream is still alive using its own stream management or
|
||||
* :func:`nghttp2_session_get_stream_user_data()`.
|
||||
*
|
||||
* Only HEADERS and DATA frame can signal the end of incoming data.
|
||||
* If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the
|
||||
* |frame| is the last frame from the remote peer in this stream.
|
||||
|
|
|
@ -71,9 +71,9 @@ STIN uint16_t htons(uint16_t hostshort) {
|
|||
STIN uint32_t ntohl(uint32_t netlong) {
|
||||
uint32_t res;
|
||||
unsigned char *p = (unsigned char *)&netlong;
|
||||
res = *p++ << 24;
|
||||
res += *p++ << 16;
|
||||
res += *p++ << 8;
|
||||
res = (uint32_t)(*p++ << 24);
|
||||
res += (uint32_t)(*p++ << 16);
|
||||
res += (uint32_t)(*p++ << 8);
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ STIN uint32_t ntohl(uint32_t netlong) {
|
|||
STIN uint16_t ntohs(uint16_t netshort) {
|
||||
uint16_t res;
|
||||
unsigned char *p = (unsigned char *)&netshort;
|
||||
res = *p++ << 8;
|
||||
res = (uint16_t)(*p++ << 8);
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_boost_asio.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_ASIO
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for Asio library from the Boost C++ libraries. The macro requires a
|
||||
# preceding call to AX_BOOST_BASE. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_ASIO_LIB)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST_ASIO
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2008 Pete Greenwell <pete@mu.org>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 16
|
||||
|
||||
AC_DEFUN([AX_BOOST_ASIO],
|
||||
[
|
||||
AC_ARG_WITH([boost-asio],
|
||||
AS_HELP_STRING([--with-boost-asio@<:@=special-lib@:>@],
|
||||
[use the ASIO library from boost - it is possible to specify a certain library for the linker
|
||||
e.g. --with-boost-asio=boost_system-gcc41-mt-1_34 ]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ax_boost_user_asio_lib=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ax_boost_user_asio_lib="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_CACHE_CHECK(whether the Boost::ASIO library is available,
|
||||
ax_cv_boost_asio,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @%:@include <boost/asio.hpp>
|
||||
]],
|
||||
[[
|
||||
|
||||
boost::asio::io_service io;
|
||||
boost::system::error_code timer_result;
|
||||
boost::asio::deadline_timer t(io);
|
||||
t.cancel();
|
||||
io.run_one();
|
||||
return 0;
|
||||
]])],
|
||||
ax_cv_boost_asio=yes, ax_cv_boost_asio=no)
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
if test "x$ax_cv_boost_asio" = "xyes"; then
|
||||
AC_DEFINE(HAVE_BOOST_ASIO,,[define if the Boost::ASIO library is available])
|
||||
BN=boost_system
|
||||
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
|
||||
if test "x$ax_boost_user_asio_lib" = "x"; then
|
||||
for ax_lib in `ls $BOOSTLIBDIR/libboost_system*.so* $BOOSTLIBDIR/libboost_system*.dylib* $BOOSTLIBDIR/libboost_system*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_system.*\)\.so.*$;\1;' -e 's;^lib\(boost_system.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_system.*\)\.a.*$;\1;' ` ; do
|
||||
AC_CHECK_LIB($ax_lib, main, [BOOST_ASIO_LIB="-l$ax_lib" AC_SUBST(BOOST_ASIO_LIB) link_thread="yes" break],
|
||||
[link_thread="no"])
|
||||
done
|
||||
else
|
||||
for ax_lib in $ax_boost_user_asio_lib $BN-$ax_boost_user_asio_lib; do
|
||||
AC_CHECK_LIB($ax_lib, main,
|
||||
[BOOST_ASIO_LIB="-l$ax_lib" AC_SUBST(BOOST_ASIO_LIB) link_asio="yes" break],
|
||||
[link_asio="no"])
|
||||
done
|
||||
|
||||
fi
|
||||
if test "x$ax_lib" = "x"; then
|
||||
AC_MSG_ERROR(Could not find a version of the library!)
|
||||
fi
|
||||
if test "x$link_asio" = "xno"; then
|
||||
AC_MSG_ERROR(Could not link against $ax_lib !)
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
])
|
|
@ -1,275 +0,0 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_boost_base.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for the Boost C++ libraries of a particular version (or newer)
|
||||
#
|
||||
# If no path to the installed boost library is given the macro searchs
|
||||
# under /usr, /usr/local, /opt and /opt/local and evaluates the
|
||||
# $BOOST_ROOT environment variable. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2009 Peter Adolphs
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 25
|
||||
|
||||
AC_DEFUN([AX_BOOST_BASE],
|
||||
[
|
||||
AC_ARG_WITH([boost],
|
||||
[AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
|
||||
[use Boost library from a standard location (ARG=yes),
|
||||
from the specified location (ARG=<path>),
|
||||
or disable it (ARG=no)
|
||||
@<:@ARG=yes@:>@ ])],
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ac_boost_path=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ac_boost_path="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"])
|
||||
|
||||
|
||||
AC_ARG_WITH([boost-libdir],
|
||||
AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
|
||||
[Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]),
|
||||
[
|
||||
if test -d "$withval"
|
||||
then
|
||||
ac_boost_lib_path="$withval"
|
||||
else
|
||||
AC_MSG_ERROR(--with-boost-libdir expected directory name)
|
||||
fi
|
||||
],
|
||||
[ac_boost_lib_path=""]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
boost_lib_version_req=ifelse([$1], ,1.20.0,$1)
|
||||
boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'`
|
||||
boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'`
|
||||
boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
|
||||
boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
|
||||
if test "x$boost_lib_version_req_sub_minor" = "x" ; then
|
||||
boost_lib_version_req_sub_minor="0"
|
||||
fi
|
||||
WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor`
|
||||
AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req)
|
||||
succeeded=no
|
||||
|
||||
dnl On 64-bit systems check for system libraries in both lib64 and lib.
|
||||
dnl The former is specified by FHS, but e.g. Debian does not adhere to
|
||||
dnl this (as it rises problems for generic multi-arch support).
|
||||
dnl The last entry in the list is chosen by default when no libraries
|
||||
dnl are found, e.g. when only header-only libraries are installed!
|
||||
libsubdirs="lib"
|
||||
ax_arch=`uname -m`
|
||||
case $ax_arch in
|
||||
x86_64)
|
||||
libsubdirs="lib64 libx32 lib lib64"
|
||||
;;
|
||||
ppc64|s390x|sparc64|aarch64|ppc64le)
|
||||
libsubdirs="lib64 lib lib64 ppc64le"
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
|
||||
dnl them priority over the other paths since, if libs are found there, they
|
||||
dnl are almost assuredly the ones desired.
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
libsubdirs="lib/${host_cpu}-${host_os} $libsubdirs"
|
||||
|
||||
case ${host_cpu} in
|
||||
i?86)
|
||||
libsubdirs="lib/i386-${host_os} $libsubdirs"
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl first we check the system location for boost libraries
|
||||
dnl this location ist chosen if boost libraries are installed with the --layout=system option
|
||||
dnl or if you install boost with RPM
|
||||
if test "$ac_boost_path" != ""; then
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path/include"
|
||||
for ac_boost_path_tmp in $libsubdirs; do
|
||||
if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then
|
||||
BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp"
|
||||
break
|
||||
fi
|
||||
done
|
||||
elif test "$cross_compiling" != yes; then
|
||||
for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
|
||||
if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then
|
||||
for libsubdir in $libsubdirs ; do
|
||||
if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir"
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
dnl overwrite ld flags if we have required special directory with
|
||||
dnl --with-boost-libdir parameter
|
||||
if test "$ac_boost_lib_path" != ""; then
|
||||
BOOST_LDFLAGS="-L$ac_boost_lib_path"
|
||||
fi
|
||||
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_REQUIRE([AC_PROG_CXX])
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <boost/version.hpp>
|
||||
]], [[
|
||||
#if BOOST_VERSION >= $WANT_BOOST_VERSION
|
||||
// Everything is okay
|
||||
#else
|
||||
# error Boost version is too old
|
||||
#endif
|
||||
]])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
succeeded=yes
|
||||
found_system=yes
|
||||
],[
|
||||
])
|
||||
AC_LANG_POP([C++])
|
||||
|
||||
|
||||
|
||||
dnl if we found no boost with system layout we search for boost libraries
|
||||
dnl built and installed without the --layout=system option or for a staged(not installed) version
|
||||
if test "x$succeeded" != "xyes"; then
|
||||
_version=0
|
||||
if test "$ac_boost_path" != ""; then
|
||||
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
|
||||
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
|
||||
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
|
||||
V_CHECK=`expr $_version_tmp \> $_version`
|
||||
if test "$V_CHECK" = "1" ; then
|
||||
_version=$_version_tmp
|
||||
fi
|
||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
|
||||
done
|
||||
fi
|
||||
else
|
||||
if test "$cross_compiling" != yes; then
|
||||
for ac_boost_path in /usr /usr/local /opt /opt/local ; do
|
||||
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
|
||||
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
|
||||
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
|
||||
V_CHECK=`expr $_version_tmp \> $_version`
|
||||
if test "$V_CHECK" = "1" ; then
|
||||
_version=$_version_tmp
|
||||
best_path=$ac_boost_path
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
||||
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
|
||||
if test "$ac_boost_lib_path" = ""; then
|
||||
for libsubdir in $libsubdirs ; do
|
||||
if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
BOOST_LDFLAGS="-L$best_path/$libsubdir"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$BOOST_ROOT" != "x"; then
|
||||
for libsubdir in $libsubdirs ; do
|
||||
if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then
|
||||
version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
|
||||
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
|
||||
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
|
||||
V_CHECK=`expr $stage_version_shorten \>\= $_version`
|
||||
if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then
|
||||
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
|
||||
BOOST_CPPFLAGS="-I$BOOST_ROOT"
|
||||
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <boost/version.hpp>
|
||||
]], [[
|
||||
#if BOOST_VERSION >= $WANT_BOOST_VERSION
|
||||
// Everything is okay
|
||||
#else
|
||||
# error Boost version is too old
|
||||
#endif
|
||||
]])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
succeeded=yes
|
||||
found_system=yes
|
||||
],[
|
||||
])
|
||||
AC_LANG_POP([C++])
|
||||
fi
|
||||
|
||||
if test "$succeeded" != "yes" ; then
|
||||
if test "$_version" = "0" ; then
|
||||
AC_MSG_NOTICE([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
|
||||
else
|
||||
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
|
||||
fi
|
||||
# execute ACTION-IF-NOT-FOUND (if present):
|
||||
ifelse([$3], , :, [$3])
|
||||
else
|
||||
AC_SUBST(BOOST_CPPFLAGS)
|
||||
AC_SUBST(BOOST_LDFLAGS)
|
||||
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
|
||||
# execute ACTION-IF-FOUND (if present):
|
||||
ifelse([$2], , :, [$2])
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
|
||||
])
|
|
@ -1,120 +0,0 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_boost_system.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_SYSTEM
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for System library from the Boost C++ libraries. The macro requires
|
||||
# a preceding call to AX_BOOST_BASE. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_SYSTEM_LIB)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST_SYSTEM
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2008 Michael Tindal
|
||||
# Copyright (c) 2008 Daniel Casimiro <dan.casimiro@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 17
|
||||
|
||||
AC_DEFUN([AX_BOOST_SYSTEM],
|
||||
[
|
||||
AC_ARG_WITH([boost-system],
|
||||
AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@],
|
||||
[use the System library from boost - it is possible to specify a certain library for the linker
|
||||
e.g. --with-boost-system=boost_system-gcc-mt ]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ax_boost_user_system_lib=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ax_boost_user_system_lib="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_CANONICAL_BUILD])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_CACHE_CHECK(whether the Boost::System library is available,
|
||||
ax_cv_boost_system,
|
||||
[AC_LANG_PUSH([C++])
|
||||
CXXFLAGS_SAVE=$CXXFLAGS
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/system/error_code.hpp>]],
|
||||
[[boost::system::system_category]])],
|
||||
ax_cv_boost_system=yes, ax_cv_boost_system=no)
|
||||
CXXFLAGS=$CXXFLAGS_SAVE
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
if test "x$ax_cv_boost_system" = "xyes"; then
|
||||
AC_SUBST(BOOST_CPPFLAGS)
|
||||
|
||||
AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available])
|
||||
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
|
||||
|
||||
LDFLAGS_SAVE=$LDFLAGS
|
||||
if test "x$ax_boost_user_system_lib" = "x"; then
|
||||
for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
|
||||
[link_system="no"])
|
||||
done
|
||||
if test "x$link_system" != "xyes"; then
|
||||
for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
|
||||
[link_system="no"])
|
||||
done
|
||||
fi
|
||||
|
||||
else
|
||||
for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
|
||||
[link_system="no"])
|
||||
done
|
||||
|
||||
fi
|
||||
if test "x$ax_lib" = "x"; then
|
||||
AC_MSG_ERROR(Could not find a version of the library!)
|
||||
fi
|
||||
if test "x$link_system" = "xno"; then
|
||||
AC_MSG_ERROR(Could not link against $ax_lib !)
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
])
|
|
@ -1,149 +0,0 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_boost_thread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_THREAD
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for Thread library from the Boost C++ libraries. The macro requires
|
||||
# a preceding call to AX_BOOST_BASE. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_THREAD_LIB)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST_THREAD
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2009 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2009 Michael Tindal
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 27
|
||||
|
||||
AC_DEFUN([AX_BOOST_THREAD],
|
||||
[
|
||||
AC_ARG_WITH([boost-thread],
|
||||
AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@],
|
||||
[use the Thread library from boost - it is possible to specify a certain library for the linker
|
||||
e.g. --with-boost-thread=boost_thread-gcc-mt ]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ax_boost_user_thread_lib=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ax_boost_user_thread_lib="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_CANONICAL_BUILD])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_CACHE_CHECK(whether the Boost::Thread library is available,
|
||||
ax_cv_boost_thread,
|
||||
[AC_LANG_PUSH([C++])
|
||||
CXXFLAGS_SAVE=$CXXFLAGS
|
||||
|
||||
if test "x$host_os" = "xsolaris" ; then
|
||||
CXXFLAGS="-pthreads $CXXFLAGS"
|
||||
elif test "x$host_os" = "xmingw32" ; then
|
||||
CXXFLAGS="-mthreads $CXXFLAGS"
|
||||
else
|
||||
CXXFLAGS="-pthread $CXXFLAGS"
|
||||
fi
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/thread/thread.hpp>]],
|
||||
[[boost::thread_group thrds;
|
||||
return 0;]])],
|
||||
ax_cv_boost_thread=yes, ax_cv_boost_thread=no)
|
||||
CXXFLAGS=$CXXFLAGS_SAVE
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
if test "x$ax_cv_boost_thread" = "xyes"; then
|
||||
if test "x$host_os" = "xsolaris" ; then
|
||||
BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS"
|
||||
elif test "x$host_os" = "xmingw32" ; then
|
||||
BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS"
|
||||
else
|
||||
BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS"
|
||||
fi
|
||||
|
||||
AC_SUBST(BOOST_CPPFLAGS)
|
||||
|
||||
AC_DEFINE(HAVE_BOOST_THREAD,,[define if the Boost::Thread library is available])
|
||||
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
|
||||
|
||||
LDFLAGS_SAVE=$LDFLAGS
|
||||
case "x$host_os" in
|
||||
*bsd* )
|
||||
LDFLAGS="-pthread $LDFLAGS"
|
||||
break;
|
||||
;;
|
||||
esac
|
||||
if test "x$ax_boost_user_thread_lib" = "x"; then
|
||||
for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
|
||||
[link_thread="no"])
|
||||
done
|
||||
if test "x$link_thread" != "xyes"; then
|
||||
for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
|
||||
[link_thread="no"])
|
||||
done
|
||||
fi
|
||||
|
||||
else
|
||||
for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
|
||||
[link_thread="no"])
|
||||
done
|
||||
|
||||
fi
|
||||
if test "x$ax_lib" = "x"; then
|
||||
AC_MSG_ERROR(Could not find a version of the library!)
|
||||
fi
|
||||
if test "x$link_thread" = "xno"; then
|
||||
AC_MSG_ERROR(Could not link against $ax_lib !)
|
||||
else
|
||||
case "x$host_os" in
|
||||
*bsd* )
|
||||
BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS"
|
||||
break;
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
])
|
|
@ -1,368 +0,0 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_python_devel.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PYTHON_DEVEL([version])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
|
||||
# in your configure.ac.
|
||||
#
|
||||
# This macro checks for Python and tries to get the include path to
|
||||
# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LIBS) output
|
||||
# variables. It also exports $(PYTHON_EXTRA_LIBS) and
|
||||
# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
|
||||
#
|
||||
# You can search for some particular version of Python by passing a
|
||||
# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
|
||||
# note that you *have* to pass also an operator along with the version to
|
||||
# match, and pay special attention to the single quotes surrounding the
|
||||
# version number. Don't use "PYTHON_VERSION" for this: that environment
|
||||
# variable is declared as precious and thus reserved for the end-user.
|
||||
#
|
||||
# This macro should work for all versions of Python >= 2.1.0. As an end
|
||||
# user, you can disable the check for the python version by setting the
|
||||
# PYTHON_NOVERSIONCHECK environment variable to something else than the
|
||||
# empty string.
|
||||
#
|
||||
# If you need to use this macro for an older Python version, please
|
||||
# contact the authors. We're always open for feedback.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2009 Sebastian Huber <sebastian-huber@web.de>
|
||||
# Copyright (c) 2009 Alan W. Irwin
|
||||
# Copyright (c) 2009 Rafael Laboissiere <rafael@laboissiere.net>
|
||||
# Copyright (c) 2009 Andrew Collier
|
||||
# Copyright (c) 2009 Matteo Settenvini <matteo@member.fsf.org>
|
||||
# Copyright (c) 2009 Horst Knorr <hk_classes@knoda.org>
|
||||
# Copyright (c) 2013 Daniel Mullner <muellner@math.stanford.edu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 23
|
||||
|
||||
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
|
||||
AC_DEFUN([AX_PYTHON_DEVEL],[
|
||||
#
|
||||
# Allow the use of a (user set) custom python version
|
||||
#
|
||||
AC_ARG_VAR([PYTHON_VERSION],[The installed Python
|
||||
version to use, for example '2.3'. This string
|
||||
will be appended to the Python interpreter
|
||||
canonical name.])
|
||||
|
||||
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
|
||||
if test -z "$PYTHON"; then
|
||||
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for a version of Python >= 2.1.0
|
||||
#
|
||||
AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
|
||||
ac_supports_python_ver=`$PYTHON -c "import sys; \
|
||||
ver = sys.version.split ()[[0]]; \
|
||||
print (ver >= '2.1.0')"`
|
||||
if test "$ac_supports_python_ver" != "True"; then
|
||||
if test -z "$PYTHON_NOVERSIONCHECK"; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_FAILURE([
|
||||
This version of the AC@&t@_PYTHON_DEVEL macro
|
||||
doesn't work properly with versions of Python before
|
||||
2.1.0. You may need to re-run configure, setting the
|
||||
variables PYTHON_CPPFLAGS, PYTHON_LIBS, PYTHON_SITE_PKG,
|
||||
PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
|
||||
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
|
||||
to something else than an empty string.
|
||||
])
|
||||
else
|
||||
AC_MSG_RESULT([skip at user request])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
|
||||
#
|
||||
# if the macro parameter ``version'' is set, honour it
|
||||
#
|
||||
if test -n "$1"; then
|
||||
AC_MSG_CHECKING([for a version of Python $1])
|
||||
ac_supports_python_ver=`$PYTHON -c "import sys; \
|
||||
ver = sys.version.split ()[[0]]; \
|
||||
print (ver $1)"`
|
||||
if test "$ac_supports_python_ver" = "True"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([this package requires Python $1.
|
||||
If you have it installed, but it isn't the default Python
|
||||
interpreter in your system path, please pass the PYTHON_VERSION
|
||||
variable to configure. See ``configure --help'' for reference.
|
||||
])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Check if you have distutils, else fail
|
||||
#
|
||||
AC_MSG_CHECKING([for the sysconfig Python package])
|
||||
ac_sysconfig_result=`$PYTHON -c "import sysconfig" 2>&1`
|
||||
if test $? -eq 0; then
|
||||
AC_MSG_RESULT([yes])
|
||||
IMPORT_SYSCONFIG="import sysconfig"
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
|
||||
AC_MSG_CHECKING([for the distutils Python package])
|
||||
ac_sysconfig_result=`$PYTHON -c "from distutils import sysconfig" 2>&1`
|
||||
if test $? -eq 0; then
|
||||
AC_MSG_RESULT([yes])
|
||||
IMPORT_SYSCONFIG="from distutils import sysconfig"
|
||||
else
|
||||
AC_MSG_ERROR([cannot import Python module "distutils".
|
||||
Please check your Python installation. The error was:
|
||||
$ac_sysconfig_result])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for Python include path
|
||||
#
|
||||
AC_MSG_CHECKING([for Python include path])
|
||||
if test -z "$PYTHON_CPPFLAGS"; then
|
||||
if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
|
||||
# sysconfig module has different functions
|
||||
python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
print (sysconfig.get_path ('include'));"`
|
||||
plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
print (sysconfig.get_path ('platinclude'));"`
|
||||
else
|
||||
# old distutils way
|
||||
python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
print (sysconfig.get_python_inc ());"`
|
||||
plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
print (sysconfig.get_python_inc (plat_specific=1));"`
|
||||
fi
|
||||
if test -n "${python_path}"; then
|
||||
if test "${plat_python_path}" != "${python_path}"; then
|
||||
python_path="-I$python_path -I$plat_python_path"
|
||||
else
|
||||
python_path="-I$python_path"
|
||||
fi
|
||||
fi
|
||||
PYTHON_CPPFLAGS=$python_path
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_CPPFLAGS])
|
||||
AC_SUBST([PYTHON_CPPFLAGS])
|
||||
|
||||
#
|
||||
# Check for Python library path
|
||||
#
|
||||
AC_MSG_CHECKING([for Python library path])
|
||||
if test -z "$PYTHON_LIBS"; then
|
||||
# (makes two attempts to ensure we've got a version number
|
||||
# from the interpreter)
|
||||
ac_python_version=`cat<<EOD | $PYTHON -
|
||||
|
||||
# join all versioning strings, on some systems
|
||||
# major/minor numbers could be in different list elements
|
||||
from sysconfig import *
|
||||
e = get_config_var('VERSION')
|
||||
if e is not None:
|
||||
print(e)
|
||||
EOD`
|
||||
|
||||
if test -z "$ac_python_version"; then
|
||||
if test -n "$PYTHON_VERSION"; then
|
||||
ac_python_version=$PYTHON_VERSION
|
||||
else
|
||||
ac_python_version=`$PYTHON -c "import sys; \
|
||||
print (sys.version[[:3]])"`
|
||||
fi
|
||||
fi
|
||||
|
||||
# Make the versioning information available to the compiler
|
||||
AC_DEFINE_UNQUOTED([HAVE_PYTHON], ["$ac_python_version"],
|
||||
[If available, contains the Python version number currently in use.])
|
||||
|
||||
# First, the library directory:
|
||||
ac_python_libdir=`cat<<EOD | $PYTHON -
|
||||
|
||||
# There should be only one
|
||||
$IMPORT_SYSCONFIG
|
||||
e = sysconfig.get_config_var('LIBDIR')
|
||||
if e is not None:
|
||||
print (e)
|
||||
EOD`
|
||||
|
||||
# Now, for the library:
|
||||
ac_python_library=`cat<<EOD | $PYTHON -
|
||||
|
||||
$IMPORT_SYSCONFIG
|
||||
c = sysconfig.get_config_vars()
|
||||
if 'LDVERSION' in c:
|
||||
print ('python'+c[['LDVERSION']])
|
||||
else:
|
||||
print ('python'+c[['VERSION']])
|
||||
EOD`
|
||||
|
||||
# This small piece shamelessly adapted from PostgreSQL python macro;
|
||||
# credits goes to momjian, I think. I'd like to put the right name
|
||||
# in the credits, if someone can point me in the right direction... ?
|
||||
#
|
||||
if test -n "$ac_python_libdir" -a -n "$ac_python_library"
|
||||
then
|
||||
# use the official shared library
|
||||
ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
|
||||
PYTHON_LIBS="-L$ac_python_libdir -l$ac_python_library"
|
||||
else
|
||||
# old way: use libpython from python_configdir
|
||||
ac_python_libdir=`$PYTHON -c \
|
||||
"from sysconfig import get_python_lib as f; \
|
||||
import os; \
|
||||
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
|
||||
PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
|
||||
fi
|
||||
|
||||
if test -z "PYTHON_LIBS"; then
|
||||
AC_MSG_ERROR([
|
||||
Cannot determine location of your Python DSO. Please check it was installed with
|
||||
dynamic libraries enabled, or try setting PYTHON_LIBS by hand.
|
||||
])
|
||||
fi
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_LIBS])
|
||||
AC_SUBST([PYTHON_LIBS])
|
||||
|
||||
#
|
||||
# Check for site packages
|
||||
#
|
||||
AC_MSG_CHECKING([for Python site-packages path])
|
||||
if test -z "$PYTHON_SITE_PKG"; then
|
||||
if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
print (sysconfig.get_path('purelib'));"`
|
||||
else
|
||||
# distutils.sysconfig way
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
print (sysconfig.get_python_lib(0,0));"`
|
||||
fi
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
||||
AC_SUBST([PYTHON_SITE_PKG])
|
||||
|
||||
#
|
||||
# Check for platform-specific site packages
|
||||
#
|
||||
AC_MSG_CHECKING([for Python platform specific site-packages path])
|
||||
if test -z "$PYTHON_SITE_PKG"; then
|
||||
if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
|
||||
PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
print (sysconfig.get_path('platlib'));"`
|
||||
else
|
||||
# distutils.sysconfig way
|
||||
PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
print (sysconfig.get_python_lib(1,0));"`
|
||||
fi
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_PLATFORM_SITE_PKG])
|
||||
AC_SUBST([PYTHON_PLATFORM_SITE_PKG])
|
||||
|
||||
#
|
||||
# libraries which must be linked in when embedding
|
||||
#
|
||||
AC_MSG_CHECKING(python extra libraries)
|
||||
if test -z "$PYTHON_EXTRA_LIBS"; then
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
conf = sysconfig.get_config_var; \
|
||||
print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
|
||||
AC_SUBST(PYTHON_EXTRA_LIBS)
|
||||
|
||||
#
|
||||
# linking flags needed when embedding
|
||||
#
|
||||
AC_MSG_CHECKING(python extra linking flags)
|
||||
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
|
||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||
conf = sysconfig.get_config_var; \
|
||||
print (conf('LINKFORSHARED'))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
||||
AC_SUBST(PYTHON_EXTRA_LDFLAGS)
|
||||
|
||||
#
|
||||
# final check to see if everything compiles alright
|
||||
#
|
||||
AC_MSG_CHECKING([consistency of all components of python development environment])
|
||||
# save current global flags
|
||||
ac_save_LIBS="$LIBS"
|
||||
ac_save_LDFLAGS="$LDFLAGS"
|
||||
ac_save_CPPFLAGS="$CPPFLAGS"
|
||||
LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS $PYTHON_EXTRA_LIBS"
|
||||
LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
|
||||
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
|
||||
AC_LANG_PUSH([C])
|
||||
AC_LINK_IFELSE([
|
||||
AC_LANG_PROGRAM([[#include <Python.h>]],
|
||||
[[Py_Initialize();]])
|
||||
],[pythonexists=yes],[pythonexists=no])
|
||||
AC_LANG_POP([C])
|
||||
# turn back to default flags
|
||||
CPPFLAGS="$ac_save_CPPFLAGS"
|
||||
LIBS="$ac_save_LIBS"
|
||||
LDFLAGS="$ac_save_LDFLAGS"
|
||||
|
||||
AC_MSG_RESULT([$pythonexists])
|
||||
|
||||
if test ! "x$pythonexists" = "xyes"; then
|
||||
AC_MSG_FAILURE([
|
||||
Could not link test program to Python. Maybe the main Python library has been
|
||||
installed in some non-standard library path. If so, pass it to configure,
|
||||
via the LIBS environment variable.
|
||||
Example: ./configure LIBS="-L/usr/non-standard-path/python/lib"
|
||||
============================================================================
|
||||
ERROR!
|
||||
You probably have to install the development version of the Python package
|
||||
for your distribution. The exact name of this package varies among them.
|
||||
============================================================================
|
||||
])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
#
|
||||
# all done!
|
||||
#
|
||||
])
|
|
@ -1,4 +0,0 @@
|
|||
# generated files
|
||||
MANIFEST
|
||||
dist/
|
||||
setup.py
|
|
@ -1,39 +0,0 @@
|
|||
# EXTRA_DIST = cnghttp2.pxd nghttp2.pyx
|
||||
|
||||
if(ENABLE_PYTHON_BINDINGS)
|
||||
add_custom_target(python ALL
|
||||
COMMAND "${PYTHON_EXECUTABLE}" setup.py build
|
||||
VERBATIM
|
||||
DEPENDS nghttp2.c nghttp2
|
||||
)
|
||||
|
||||
configure_file(install-python.cmake.in install-python.cmake ESCAPE_QUOTES @ONLY)
|
||||
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install-python.cmake")
|
||||
|
||||
add_custom_command(OUTPUT nghttp2.c
|
||||
COMMAND "${CYTHON_EXECUTABLE}" -o nghttp2.c
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/nghttp2.pyx"
|
||||
VERBATIM
|
||||
DEPENDS nghttp2.pyx
|
||||
)
|
||||
|
||||
# Instead of calling "setup.py clean --all", this should do...
|
||||
set_directory_properties(PROPERTIES
|
||||
ADDITIONAL_MAKE_CLEAN_FILES "build;python_nghttp2.egg-info"
|
||||
)
|
||||
|
||||
## This works also, except that the installation target is missing...
|
||||
# include(UseCython)
|
||||
# cython_add_module(python_nghttp2 nghttp2.pyx)
|
||||
# set_target_properties(python_nghttp2 PROPERTIES
|
||||
# OUTPUT_NAME nghttp2
|
||||
# )
|
||||
# target_include_directories(python_nghttp2 PRIVATE
|
||||
# "${CMAKE_SOURCE_DIR}/lib"
|
||||
# "${CMAKE_SOURCE_DIR}/lib/includes"
|
||||
# "${CMAKE_BINARY_DIR}/lib/includes"
|
||||
# )
|
||||
# target_link_libraries(python_nghttp2
|
||||
# nghttp2
|
||||
# )
|
||||
endif()
|
|
@ -1,49 +0,0 @@
|
|||
# nghttp2 - HTTP/2 C Library
|
||||
|
||||
# Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# This will avoid that setup.py gets deleted before it is executed in
|
||||
# clean-local in parallel build.
|
||||
.NOTPARALLEL:
|
||||
|
||||
EXTRA_DIST = cnghttp2.pxd nghttp2.pyx CMakeLists.txt install-python.cmake.in
|
||||
|
||||
if ENABLE_PYTHON_BINDINGS
|
||||
|
||||
all-local: nghttp2.c
|
||||
$(PYTHON) setup.py build
|
||||
|
||||
install-exec-local:
|
||||
$(PYTHON) setup.py install --prefix=$(DESTDIR)$(prefix)
|
||||
|
||||
uninstall-local:
|
||||
rm -f $(DESTDIR)$(libdir)/python*/site-packages/nghttp2.so
|
||||
rm -f $(DESTDIR)$(libdir)/python*/site-packages/python_nghttp2-*.egg
|
||||
|
||||
clean-local:
|
||||
$(PYTHON) setup.py clean --all
|
||||
-rm -f $(builddir)/nghttp2.c
|
||||
|
||||
.pyx.c:
|
||||
$(CYTHON) -3 -o $@ $<
|
||||
|
||||
endif # ENABLE_PYTHON_BINDINGS
|
|
@ -1,109 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# This script takes directories which contain the hpack-test-case json
|
||||
# files, and calculates the compression ratio in each file and outputs
|
||||
# the result in table formatted in rst.
|
||||
#
|
||||
# The each directory contains the result of various HPACK compressor.
|
||||
#
|
||||
# The table is laid out so that we can see that how input header set
|
||||
# in one json file is compressed in each compressor.
|
||||
#
|
||||
# For hpack-test-case, see https://github.com/Jxck/hpack-test-case
|
||||
#
|
||||
import sys, json, os, re
|
||||
|
||||
class Stat:
|
||||
|
||||
def __init__(self, complen, srclen):
|
||||
self.complen = complen
|
||||
self.srclen = srclen
|
||||
|
||||
def compute_stat(jsdata):
|
||||
complen = 0
|
||||
srclen = 0
|
||||
for item in jsdata['cases']:
|
||||
complen += len(item['wire']) // 2
|
||||
srclen += \
|
||||
sum([len(list(x.keys())[0]) + len(list(x.values())[0]) \
|
||||
for x in item['headers']])
|
||||
return Stat(complen, srclen)
|
||||
|
||||
def format_result(r):
|
||||
return '{:.02f} ({}/{}) '.format(r.complen/r.srclen, r.complen, r.srclen)
|
||||
|
||||
if __name__ == '__main__':
|
||||
entries = [(os.path.basename(re.sub(r'/+$', '', p)), p) \
|
||||
for p in sys.argv[1:]]
|
||||
maxnamelen = 0
|
||||
maxstorynamelen = 0
|
||||
res = {}
|
||||
|
||||
stories = set()
|
||||
for name, ent in entries:
|
||||
files = [p for p in os.listdir(ent) if p.endswith('.json')]
|
||||
res[name] = {}
|
||||
maxnamelen = max(maxnamelen, len(name))
|
||||
for fn in files:
|
||||
stories.add(fn)
|
||||
maxstorynamelen = max(maxstorynamelen, len(fn))
|
||||
with open(os.path.join(ent, fn)) as f:
|
||||
input = f.read()
|
||||
rv = compute_stat(json.loads(input))
|
||||
res[name][fn] = rv
|
||||
maxnamelen = max(maxnamelen, len(format_result(rv)))
|
||||
stories = list(stories)
|
||||
stories.sort()
|
||||
|
||||
storynameformat = '{{:{}}} '.format(maxstorynamelen)
|
||||
nameformat = '{{:{}}} '.format(maxnamelen)
|
||||
|
||||
|
||||
sys.stdout.write('''\
|
||||
hpack-test-case compression ratio
|
||||
=================================
|
||||
|
||||
The each cell has ``X (Y/Z)`` format:
|
||||
|
||||
X
|
||||
Y / Z
|
||||
Y
|
||||
number of bytes after compression
|
||||
Z
|
||||
number of bytes before compression
|
||||
|
||||
''')
|
||||
|
||||
def write_border():
|
||||
sys.stdout.write('='*maxstorynamelen)
|
||||
sys.stdout.write(' ')
|
||||
for _ in entries:
|
||||
sys.stdout.write('='*maxnamelen)
|
||||
sys.stdout.write(' ')
|
||||
sys.stdout.write('\n')
|
||||
|
||||
write_border()
|
||||
|
||||
sys.stdout.write(storynameformat.format('story'))
|
||||
for name, _ in entries:
|
||||
sys.stdout.write(nameformat.format(name))
|
||||
sys.stdout.write('\n')
|
||||
|
||||
write_border()
|
||||
|
||||
for story in stories:
|
||||
sys.stdout.write(storynameformat.format(story))
|
||||
srclen = -1
|
||||
for name, _ in entries:
|
||||
stats = res[name]
|
||||
if story not in stats:
|
||||
sys.stdout.write(nameformat.format('N/A'))
|
||||
continue
|
||||
if srclen == -1:
|
||||
srclen = stats[story].srclen
|
||||
elif srclen != stats[story].srclen:
|
||||
raise Exception('Bad srclen')
|
||||
sys.stdout.write(nameformat.format(format_result(stats[story])))
|
||||
sys.stdout.write('\n')
|
||||
|
||||
write_border()
|
|
@ -1,340 +0,0 @@
|
|||
# nghttp2 - HTTP/2 C Library
|
||||
|
||||
# Copyright (c) 2013 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.
|
||||
from libc.stdint cimport uint8_t, uint16_t, uint32_t, int32_t
|
||||
|
||||
cdef extern from 'nghttp2/nghttp2.h':
|
||||
|
||||
const char NGHTTP2_PROTO_VERSION_ID[]
|
||||
const char NGHTTP2_CLIENT_CONNECTION_PREFACE[]
|
||||
const size_t NGHTTP2_INITIAL_WINDOW_SIZE
|
||||
const size_t NGHTTP2_DEFAULT_HEADER_TABLE_SIZE
|
||||
|
||||
ctypedef struct nghttp2_session:
|
||||
pass
|
||||
|
||||
ctypedef enum nghttp2_error:
|
||||
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
|
||||
NGHTTP2_ERR_DEFERRED
|
||||
|
||||
ctypedef enum nghttp2_flag:
|
||||
NGHTTP2_FLAG_NONE
|
||||
NGHTTP2_FLAG_END_STREAM
|
||||
NGHTTP2_FLAG_ACK
|
||||
|
||||
ctypedef enum nghttp2_error_code:
|
||||
NGHTTP2_NO_ERROR
|
||||
NGHTTP2_PROTOCOL_ERROR
|
||||
NGHTTP2_INTERNAL_ERROR
|
||||
NGHTTP2_SETTINGS_TIMEOUT
|
||||
|
||||
ctypedef enum nghttp2_frame_type:
|
||||
NGHTTP2_DATA
|
||||
NGHTTP2_HEADERS
|
||||
NGHTTP2_RST_STREAM
|
||||
NGHTTP2_SETTINGS
|
||||
NGHTTP2_PUSH_PROMISE
|
||||
NGHTTP2_GOAWAY
|
||||
|
||||
ctypedef enum nghttp2_nv_flag:
|
||||
NGHTTP2_NV_FLAG_NONE
|
||||
NGHTTP2_NV_FLAG_NO_INDEX
|
||||
|
||||
ctypedef struct nghttp2_nv:
|
||||
uint8_t *name
|
||||
uint8_t *value
|
||||
uint16_t namelen
|
||||
uint16_t valuelen
|
||||
uint8_t flags
|
||||
|
||||
ctypedef enum nghttp2_settings_id:
|
||||
SETTINGS_HEADER_TABLE_SIZE
|
||||
NGHTTP2_SETTINGS_HEADER_TABLE_SIZE
|
||||
NGHTTP2_SETTINGS_ENABLE_PUSH
|
||||
NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS
|
||||
NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE
|
||||
|
||||
ctypedef struct nghttp2_settings_entry:
|
||||
int32_t settings_id
|
||||
uint32_t value
|
||||
|
||||
ctypedef struct nghttp2_frame_hd:
|
||||
size_t length
|
||||
int32_t stream_id
|
||||
uint8_t type
|
||||
uint8_t flags
|
||||
|
||||
ctypedef struct nghttp2_data:
|
||||
nghttp2_frame_hd hd
|
||||
size_t padlen
|
||||
|
||||
ctypedef enum nghttp2_headers_category:
|
||||
NGHTTP2_HCAT_REQUEST
|
||||
NGHTTP2_HCAT_RESPONSE
|
||||
NGHTTP2_HCAT_PUSH_RESPONSE
|
||||
NGHTTP2_HCAT_HEADERS
|
||||
|
||||
ctypedef struct nghttp2_headers:
|
||||
nghttp2_frame_hd hd
|
||||
size_t padlen
|
||||
nghttp2_nv *nva
|
||||
size_t nvlen
|
||||
nghttp2_headers_category cat
|
||||
int32_t pri
|
||||
|
||||
ctypedef struct nghttp2_rst_stream:
|
||||
nghttp2_frame_hd hd
|
||||
uint32_t error_code
|
||||
|
||||
|
||||
ctypedef struct nghttp2_push_promise:
|
||||
nghttp2_frame_hd hd
|
||||
nghttp2_nv *nva
|
||||
size_t nvlen
|
||||
int32_t promised_stream_id
|
||||
|
||||
ctypedef struct nghttp2_goaway:
|
||||
nghttp2_frame_hd hd
|
||||
int32_t last_stream_id
|
||||
uint32_t error_code
|
||||
uint8_t *opaque_data
|
||||
size_t opaque_data_len
|
||||
|
||||
ctypedef union nghttp2_frame:
|
||||
nghttp2_frame_hd hd
|
||||
nghttp2_data data
|
||||
nghttp2_headers headers
|
||||
nghttp2_rst_stream rst_stream
|
||||
nghttp2_push_promise push_promise
|
||||
nghttp2_goaway goaway
|
||||
|
||||
ctypedef ssize_t (*nghttp2_send_callback)\
|
||||
(nghttp2_session *session, const uint8_t *data, size_t length,
|
||||
int flags, void *user_data)
|
||||
|
||||
ctypedef int (*nghttp2_on_frame_recv_callback)\
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
|
||||
ctypedef int (*nghttp2_on_data_chunk_recv_callback)\
|
||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t length, void *user_data)
|
||||
|
||||
ctypedef int (*nghttp2_before_frame_send_callback)\
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
|
||||
ctypedef int (*nghttp2_on_stream_close_callback)\
|
||||
(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code, void *user_data)
|
||||
|
||||
ctypedef int (*nghttp2_on_begin_headers_callback)\
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
|
||||
ctypedef int (*nghttp2_on_header_callback)\
|
||||
(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *user_data)
|
||||
|
||||
ctypedef int (*nghttp2_on_frame_send_callback)\
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
|
||||
ctypedef int (*nghttp2_on_frame_not_send_callback)\
|
||||
(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
int lib_error_code, void *user_data)
|
||||
|
||||
ctypedef struct nghttp2_session_callbacks:
|
||||
pass
|
||||
|
||||
int nghttp2_session_callbacks_new(
|
||||
nghttp2_session_callbacks **callbacks_ptr)
|
||||
|
||||
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks)
|
||||
|
||||
void nghttp2_session_callbacks_set_send_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_before_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback)
|
||||
|
||||
void nghttp2_session_callbacks_set_on_header_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback on_header_callback)
|
||||
|
||||
int nghttp2_session_client_new(nghttp2_session **session_ptr,
|
||||
const nghttp2_session_callbacks *callbacks,
|
||||
void *user_data)
|
||||
|
||||
int nghttp2_session_server_new(nghttp2_session **session_ptr,
|
||||
const nghttp2_session_callbacks *callbacks,
|
||||
void *user_data)
|
||||
|
||||
void nghttp2_session_del(nghttp2_session *session)
|
||||
|
||||
|
||||
ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||
const uint8_t *data, size_t datalen)
|
||||
|
||||
ssize_t nghttp2_session_mem_send(nghttp2_session *session,
|
||||
const uint8_t **data_ptr)
|
||||
|
||||
int nghttp2_session_send(nghttp2_session *session)
|
||||
|
||||
int nghttp2_session_want_read(nghttp2_session *session)
|
||||
|
||||
int nghttp2_session_want_write(nghttp2_session *session)
|
||||
|
||||
ctypedef union nghttp2_data_source:
|
||||
int fd
|
||||
void *ptr
|
||||
|
||||
ctypedef enum nghttp2_data_flag:
|
||||
NGHTTP2_DATA_FLAG_NONE
|
||||
NGHTTP2_DATA_FLAG_EOF
|
||||
|
||||
ctypedef ssize_t (*nghttp2_data_source_read_callback)\
|
||||
(nghttp2_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t length, uint32_t *data_flags,
|
||||
nghttp2_data_source *source, void *user_data)
|
||||
|
||||
ctypedef struct nghttp2_data_provider:
|
||||
nghttp2_data_source source
|
||||
nghttp2_data_source_read_callback read_callback
|
||||
|
||||
ctypedef struct nghttp2_priority_spec:
|
||||
int32_t stream_id
|
||||
int32_t weight
|
||||
uint8_t exclusive
|
||||
|
||||
int 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)
|
||||
|
||||
int nghttp2_submit_response(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd)
|
||||
|
||||
int nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
void *stream_user_data)
|
||||
|
||||
int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_settings_entry *iv, size_t niv)
|
||||
|
||||
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code)
|
||||
|
||||
void* nghttp2_session_get_stream_user_data(nghttp2_session *session,
|
||||
uint32_t stream_id)
|
||||
|
||||
int nghttp2_session_set_stream_user_data(nghttp2_session *session,
|
||||
uint32_t stream_id,
|
||||
void *stream_user_data)
|
||||
|
||||
int nghttp2_session_terminate_session(nghttp2_session *session,
|
||||
uint32_t error_code)
|
||||
|
||||
int nghttp2_session_resume_data(nghttp2_session *session,
|
||||
int32_t stream_id)
|
||||
|
||||
const char* nghttp2_strerror(int lib_error_code)
|
||||
|
||||
int nghttp2_session_check_server_session(nghttp2_session *session)
|
||||
|
||||
int nghttp2_session_get_stream_remote_close(nghttp2_session *session, int32_t stream_id)
|
||||
|
||||
int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
|
||||
size_t deflate_hd_table_bufsize_max)
|
||||
|
||||
void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater)
|
||||
|
||||
int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
|
||||
size_t hd_table_bufsize_max)
|
||||
|
||||
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
|
||||
uint8_t *buf, size_t buflen,
|
||||
const nghttp2_nv *nva, size_t nvlen)
|
||||
|
||||
size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
|
||||
const nghttp2_nv *nva, size_t nvlen)
|
||||
|
||||
int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr)
|
||||
|
||||
void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater)
|
||||
|
||||
int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
|
||||
size_t hd_table_bufsize_max)
|
||||
|
||||
ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_nv *nv_out, int *inflate_flags,
|
||||
const uint8_t *input, size_t inlen,
|
||||
int in_final)
|
||||
|
||||
int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater)
|
||||
|
||||
ctypedef enum nghttp2_hd_inflate_flag:
|
||||
NGHTTP2_HD_INFLATE_EMIT
|
||||
NGHTTP2_HD_INFLATE_FINAL
|
||||
|
||||
ctypedef struct nghttp2_hd_deflater:
|
||||
pass
|
||||
|
||||
ctypedef struct nghttp2_hd_inflater:
|
||||
pass
|
||||
|
||||
size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater)
|
||||
|
||||
const nghttp2_nv * nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx)
|
||||
|
||||
size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater)
|
||||
|
||||
const nghttp2_nv *nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx)
|
|
@ -1,54 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# This script reads json files given in the command-line (each file
|
||||
# must be written in the format described in
|
||||
# https://github.com/Jxck/hpack-test-case). And then it decompresses
|
||||
# the sequence of encoded header blocks (which is the value of 'wire'
|
||||
# key) and checks that decompressed header set is equal to the input
|
||||
# header set (which is the value of 'headers' key). If there is
|
||||
# mismatch, exception will be raised.
|
||||
#
|
||||
import sys, json
|
||||
from binascii import a2b_hex
|
||||
import nghttp2
|
||||
|
||||
def testsuite(testdata):
|
||||
inflater = nghttp2.HDInflater()
|
||||
|
||||
for casenum, item in enumerate(testdata['cases']):
|
||||
if 'header_table_size' in item:
|
||||
hd_table_size = int(item['header_table_size'])
|
||||
inflater.change_table_size(hd_table_size)
|
||||
compressed = a2b_hex(item['wire'])
|
||||
# sys.stderr.write('#{} WIRE:\n{}\n'.format(casenum+1, item['wire']))
|
||||
# TODO decompressed headers are not necessarily UTF-8 strings
|
||||
hdrs = [(k.decode('utf-8'), v.decode('utf-8')) \
|
||||
for k, v in inflater.inflate(compressed)]
|
||||
|
||||
expected_hdrs = [(list(x.keys())[0],
|
||||
list(x.values())[0]) for x in item['headers']]
|
||||
if hdrs != expected_hdrs:
|
||||
if 'seqno' in item:
|
||||
seqno = item['seqno']
|
||||
else:
|
||||
seqno = casenum
|
||||
|
||||
sys.stderr.write('FAIL seqno#{}\n'.format(seqno))
|
||||
sys.stderr.write('expected:\n')
|
||||
for k, v in expected_hdrs:
|
||||
sys.stderr.write('{}: {}\n'.format(k, v))
|
||||
sys.stderr.write(', but got:\n')
|
||||
for k, v in hdrs:
|
||||
sys.stderr.write('{}: {}\n'.format(k, v))
|
||||
raise Exception('test failure')
|
||||
sys.stderr.write('PASS\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
for filename in sys.argv[1:]:
|
||||
sys.stderr.write('{}: '.format(filename))
|
||||
with open(filename) as f:
|
||||
input = f.read()
|
||||
|
||||
testdata = json.loads(input)
|
||||
|
||||
testsuite(json.loads(input))
|
|
@ -1,90 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# This script reads input headers from json file given in the
|
||||
# command-line (each file must be written in the format described in
|
||||
# https://github.com/Jxck/hpack-test-case but we require only
|
||||
# 'headers' data). Then it encodes input header set and write the
|
||||
# encoded header block in the same format. The output files are
|
||||
# created under 'out' directory in the current directory. It must
|
||||
# exist, otherwise the script will fail. The output filename is the
|
||||
# same as the input filename.
|
||||
#
|
||||
import sys, base64, json, os.path, os, argparse, errno
|
||||
from binascii import b2a_hex
|
||||
import nghttp2
|
||||
|
||||
def testsuite(testdata, filename, outdir, table_size, deflate_table_size,
|
||||
simulate_table_size_change):
|
||||
res = {
|
||||
'description': '''\
|
||||
Encoded by nghttp2. The basic encoding strategy is described in \
|
||||
http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html \
|
||||
We use huffman encoding only if it produces strictly shorter byte string than \
|
||||
original. We make some headers not indexing at all, but this does not always \
|
||||
result in less bits on the wire.'''
|
||||
}
|
||||
cases = []
|
||||
deflater = nghttp2.HDDeflater(deflate_table_size)
|
||||
|
||||
if table_size != nghttp2.DEFAULT_HEADER_TABLE_SIZE:
|
||||
deflater.change_table_size(table_size)
|
||||
|
||||
num_item = len(testdata['cases'])
|
||||
|
||||
change_points = {}
|
||||
if simulate_table_size_change and num_item > 1:
|
||||
change_points[num_item * 2 // 3] = table_size * 2 // 3
|
||||
change_points[num_item // 3] = table_size // 3
|
||||
|
||||
for casenum, item in enumerate(testdata['cases']):
|
||||
outitem = {
|
||||
'seqno': casenum,
|
||||
'headers': item['headers']
|
||||
}
|
||||
|
||||
if casenum in change_points:
|
||||
new_table_size = change_points[casenum]
|
||||
deflater.change_table_size(new_table_size)
|
||||
outitem['header_table_size'] = new_table_size
|
||||
|
||||
casenum += 1
|
||||
hdrs = [(list(x.keys())[0].encode('utf-8'),
|
||||
list(x.values())[0].encode('utf-8')) \
|
||||
for x in item['headers']]
|
||||
outitem['wire'] = b2a_hex(deflater.deflate(hdrs)).decode('utf-8')
|
||||
cases.append(outitem)
|
||||
|
||||
if cases and table_size != nghttp2.DEFAULT_HEADER_TABLE_SIZE:
|
||||
cases[0]['header_table_size'] = table_size
|
||||
|
||||
res['cases'] = cases
|
||||
jsonstr = json.dumps(res, indent=2)
|
||||
with open(os.path.join(outdir, filename), 'w') as f:
|
||||
f.write(jsonstr)
|
||||
|
||||
if __name__ == '__main__':
|
||||
ap = argparse.ArgumentParser(description='HPACK test case generator')
|
||||
ap.add_argument('-d', '--dir', help='output directory', default='out')
|
||||
ap.add_argument('-s', '--table-size', help='max header table size',
|
||||
type=int, default=nghttp2.DEFAULT_HEADER_TABLE_SIZE)
|
||||
ap.add_argument('-S', '--deflate-table-size',
|
||||
help='max header table size for deflater',
|
||||
type=int, default=nghttp2.DEFLATE_MAX_HEADER_TABLE_SIZE)
|
||||
ap.add_argument('-c', '--simulate-table-size-change',
|
||||
help='simulate table size change scenario',
|
||||
action='store_true')
|
||||
|
||||
ap.add_argument('file', nargs='*', help='input file')
|
||||
args = ap.parse_args()
|
||||
try:
|
||||
os.mkdir(args.dir)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise e
|
||||
for filename in args.file:
|
||||
sys.stderr.write('{}\n'.format(filename))
|
||||
with open(filename) as f:
|
||||
input = f.read()
|
||||
testsuite(json.loads(input), os.path.basename(filename),
|
||||
args.dir, args.table_size, args.deflate_table_size,
|
||||
args.simulate_table_size_change)
|
|
@ -1,10 +0,0 @@
|
|||
get_filename_component(rootdir "$ENV{DESTDIR}" ABSOLUTE)
|
||||
if(rootdir STREQUAL "")
|
||||
set(rootdir /)
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND "@PYTHON_EXECUTABLE@" setup.py install
|
||||
--skip-build
|
||||
--root=${rootdir} --prefix=${CMAKE_INSTALL_PREFIX}
|
||||
WORKING_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@"
|
||||
)
|
1655
python/nghttp2.pyx
1655
python/nghttp2.pyx
File diff suppressed because it is too large
Load Diff
|
@ -1,46 +0,0 @@
|
|||
# nghttp2 - HTTP/2 C Library
|
||||
|
||||
# Copyright (c) 2013 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.
|
||||
|
||||
from setuptools import setup, Extension
|
||||
|
||||
LIBS = ['nghttp2']
|
||||
|
||||
setup(
|
||||
name = 'python-nghttp2',
|
||||
description = 'Python HTTP/2 library on top of nghttp2',
|
||||
author = 'Tatsuhiro Tsujikawa',
|
||||
version = '@PACKAGE_VERSION@',
|
||||
author_email = 'tatsuhiro.t@gmail.com',
|
||||
url = 'https://nghttp2.org/',
|
||||
keywords = [],
|
||||
ext_modules = [Extension("nghttp2",
|
||||
["nghttp2.c"],
|
||||
include_dirs=['@top_srcdir@/lib',
|
||||
'@top_srcdir@/lib/includes',
|
||||
'@top_builddir@/lib/includes'],
|
||||
library_dirs=['@top_builddir@/lib/.libs',
|
||||
'@top_builddir@/lib',
|
||||
'@top_builddir@'],
|
||||
libraries=LIBS)],
|
||||
long_description='TBD'
|
||||
)
|
119
python/wsgi.py
119
python/wsgi.py
|
@ -1,119 +0,0 @@
|
|||
# nghttp2 - HTTP/2.0 C Library
|
||||
|
||||
# Copyright (c) 2013 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.
|
||||
import io
|
||||
import sys
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import nghttp2
|
||||
|
||||
def _dance_decode(b):
|
||||
# TODO faster than looping through and mod-128'ing all unicode points?
|
||||
return b.decode('utf-8').encode('latin1').decode('latin1')
|
||||
|
||||
class WSGIContainer(nghttp2.BaseRequestHandler):
|
||||
|
||||
_BASE_ENVIRON = {
|
||||
'wsgi.version': (1,0),
|
||||
'wsgi.url_scheme': 'http', # FIXME
|
||||
'wsgi.multithread': True, # TODO I think?
|
||||
'wsgi.multiprocess': False, # TODO no idea
|
||||
'wsgi.run_once': True, # TODO now I'm just guessing
|
||||
'wsgi.errors': sys.stderr, # TODO will work for testing - is this even used by any frameworks?
|
||||
}
|
||||
|
||||
def __init__(self, app, *args, **kwargs):
|
||||
super(WSGIContainer, self).__init__(*args, **kwargs)
|
||||
self.app = app
|
||||
self.chunks = []
|
||||
|
||||
def on_data(self, chunk):
|
||||
self.chunks.append(chunk)
|
||||
|
||||
def on_request_done(self):
|
||||
environ = WSGIContainer._BASE_ENVIRON.copy()
|
||||
parsed = urlparse(self.path)
|
||||
|
||||
environ['wsgi.input'] = io.BytesIO(b''.join(self.chunks))
|
||||
|
||||
for name, value in self.headers:
|
||||
mangled_name = b'HTTP_' + name.replace(b'-', b'_').upper()
|
||||
environ[_dance_decode(mangled_name)] = _dance_decode(value)
|
||||
|
||||
environ.update(dict(
|
||||
REQUEST_METHOD=_dance_decode(self.method),
|
||||
# TODO SCRIPT_NAME? like APPLICATION_ROOT in Flask...
|
||||
PATH_INFO=_dance_decode(parsed.path),
|
||||
QUERY_STRING=_dance_decode(parsed.query),
|
||||
CONTENT_TYPE=environ.get('HTTP_CONTENT_TYPE', ''),
|
||||
CONTENT_LENGTH=environ.get('HTTP_CONTENT_LENGTH', ''),
|
||||
SERVER_NAME=_dance_decode(self.host),
|
||||
SERVER_PORT='', # FIXME probably requires changes in nghttp2
|
||||
SERVER_PROTOCOL='HTTP/2.0',
|
||||
))
|
||||
|
||||
response_status = [None]
|
||||
response_headers = [None]
|
||||
response_chunks = []
|
||||
|
||||
def start_response(status, headers, exc_info=None):
|
||||
if response_status[0] is not None:
|
||||
raise AssertionError('Response already started')
|
||||
exc_info = None # avoid dangling circular ref - TODO is this necessary? borrowed from snippet in WSGI spec
|
||||
|
||||
response_status[0] = status
|
||||
response_headers[0] = headers
|
||||
# TODO handle exc_info
|
||||
|
||||
return lambda chunk: response_chunks.append(chunk)
|
||||
|
||||
# TODO technically, this breaks the WSGI spec by buffering the status,
|
||||
# headers, and body until all are completely output from the app before
|
||||
# writing the response, but it looks like nghttp2 doesn't support any
|
||||
# other way for now
|
||||
|
||||
# TODO disallow yielding/returning before start_response is called
|
||||
response_chunks.extend(self.app(environ, start_response))
|
||||
response_body = b''.join(response_chunks)
|
||||
|
||||
# TODO automatically set content-length if not provided
|
||||
self.send_response(
|
||||
status=response_status[0],
|
||||
headers=response_headers[0],
|
||||
body=response_body,
|
||||
)
|
||||
|
||||
def wsgi_app(app):
|
||||
return lambda *args, **kwargs: WSGIContainer(app, *args, **kwargs)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import ssl
|
||||
from werkzeug.testapp import test_app
|
||||
|
||||
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
ssl_ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2
|
||||
ssl_ctx.load_cert_chain('server.crt', 'server.key')
|
||||
|
||||
server = nghttp2.HTTP2Server(('127.0.0.1', 8443), wsgi_app(test_app),
|
||||
ssl=ssl_ctx)
|
||||
server.serve_forever()
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
autoreconf -i
|
||||
git submodule update --init
|
||||
./configure --with-mruby --with-neverbleed --enable-asio-lib
|
||||
make -j8 distcheck DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --enable-asio-lib --enable-werror"
|
||||
./configure --with-mruby --with-neverbleed
|
||||
make -j8 distcheck DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --enable-werror"
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# generated files
|
||||
libnghttp2_asio.pc
|
||||
|
||||
# programs
|
||||
deflatehd
|
||||
h2load
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
add_subdirectory(includes)
|
||||
|
||||
file(GLOB c_sources *.c)
|
||||
set_source_files_properties(${c_sources} PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCFLAGS}")
|
||||
|
@ -243,65 +241,3 @@ if(ENABLE_HPACK_TOOLS)
|
|||
install(TARGETS inflatehd deflatehd
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
endif()
|
||||
|
||||
if(ENABLE_ASIO_LIB)
|
||||
set(NGHTTP2_ASIO_SOURCES
|
||||
util.cc http2.cc
|
||||
tls.cc
|
||||
timegm.c
|
||||
asio_common.cc
|
||||
asio_io_service_pool.cc
|
||||
asio_server_http2.cc
|
||||
asio_server_http2_impl.cc
|
||||
asio_server.cc
|
||||
asio_server_http2_handler.cc
|
||||
asio_server_request.cc
|
||||
asio_server_request_impl.cc
|
||||
asio_server_response.cc
|
||||
asio_server_response_impl.cc
|
||||
asio_server_stream.cc
|
||||
asio_server_serve_mux.cc
|
||||
asio_server_request_handler.cc
|
||||
asio_server_tls_context.cc
|
||||
asio_client_session.cc
|
||||
asio_client_session_impl.cc
|
||||
asio_client_session_tcp_impl.cc
|
||||
asio_client_session_tls_impl.cc
|
||||
asio_client_response.cc
|
||||
asio_client_response_impl.cc
|
||||
asio_client_request.cc
|
||||
asio_client_request_impl.cc
|
||||
asio_client_stream.cc
|
||||
asio_client_tls_context.cc
|
||||
)
|
||||
|
||||
add_library(nghttp2_asio SHARED
|
||||
${NGHTTP2_ASIO_SOURCES}
|
||||
$<TARGET_OBJECTS:llhttp>
|
||||
$<TARGET_OBJECTS:url-parser>
|
||||
)
|
||||
target_include_directories(nghttp2_asio PRIVATE
|
||||
${OPENSSL_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
)
|
||||
target_include_directories(nghttp2_asio INTERFACE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../lib/includes"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../lib/includes"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
||||
)
|
||||
target_link_libraries(nghttp2_asio
|
||||
nghttp2
|
||||
${OPENSSL_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
)
|
||||
set_target_properties(nghttp2_asio PROPERTIES
|
||||
VERSION 1.0.0 SOVERSION 1)
|
||||
|
||||
install(TARGETS nghttp2_asio
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnghttp2_asio.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
endif()
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
# 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.
|
||||
SUBDIRS = includes
|
||||
|
||||
EXTRA_DIST = \
|
||||
CMakeLists.txt \
|
||||
test.example.com.pem \
|
||||
|
@ -39,7 +37,6 @@ AM_CPPFLAGS = \
|
|||
-I$(top_srcdir)/lib/includes \
|
||||
-I$(top_builddir)/lib/includes \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(top_srcdir)/src/includes \
|
||||
-I$(top_srcdir)/third-party \
|
||||
-I$(top_srcdir)/third-party/llhttp/include \
|
||||
@JEMALLOC_CFLAGS@ \
|
||||
|
@ -95,10 +92,10 @@ endif # HAVE_LIBXML2
|
|||
|
||||
nghttp_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttp.cc nghttp.h \
|
||||
${HTML_PARSER_OBJECTS} ${HTML_PARSER_HFILES} \
|
||||
tls.cc tls.h
|
||||
tls.cc tls.h ssl_compat.h
|
||||
|
||||
nghttpd_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttpd.cc \
|
||||
tls.cc tls.h \
|
||||
tls.cc tls.h ssl_compat.h \
|
||||
HttpServer.cc HttpServer.h
|
||||
|
||||
bin_PROGRAMS += h2load
|
||||
|
@ -106,7 +103,7 @@ bin_PROGRAMS += h2load
|
|||
h2load_SOURCES = util.cc util.h \
|
||||
http2.cc http2.h h2load.cc h2load.h \
|
||||
timegm.c timegm.h \
|
||||
tls.cc tls.h \
|
||||
tls.cc tls.h ssl_compat.h \
|
||||
h2load_session.h \
|
||||
h2load_http2_session.cc h2load_http2_session.h \
|
||||
h2load_http1_session.cc h2load_http1_session.h
|
||||
|
@ -121,7 +118,7 @@ endif # ENABLE_HTTP3
|
|||
NGHTTPX_SRCS = \
|
||||
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \
|
||||
app_helper.cc app_helper.h \
|
||||
tls.cc tls.h \
|
||||
tls.cc tls.h ssl_compat.h \
|
||||
shrpx_config.cc shrpx_config.h \
|
||||
shrpx_error.h \
|
||||
shrpx_accept_handler.cc shrpx_accept_handler.h \
|
||||
|
@ -256,56 +253,3 @@ inflatehd_SOURCES = inflatehd.cc $(HPACK_TOOLS_COMMON_SRCS)
|
|||
deflatehd_SOURCES = deflatehd.cc $(HPACK_TOOLS_COMMON_SRCS)
|
||||
|
||||
endif # ENABLE_HPACK_TOOLS
|
||||
|
||||
if ENABLE_ASIO_LIB
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libnghttp2_asio.pc
|
||||
DISTCLEANFILES = $(pkgconfig_DATA)
|
||||
|
||||
lib_LTLIBRARIES = libnghttp2_asio.la
|
||||
|
||||
libnghttp2_asio_la_SOURCES = \
|
||||
util.cc util.h http2.cc http2.h \
|
||||
tls.cc tls.h \
|
||||
ssl_compat.h \
|
||||
timegm.c timegm.h \
|
||||
asio_common.cc asio_common.h \
|
||||
asio_io_service_pool.cc asio_io_service_pool.h \
|
||||
asio_server_http2.cc \
|
||||
asio_server_http2_impl.cc asio_server_http2_impl.h \
|
||||
asio_server.cc asio_server.h \
|
||||
asio_server_http2_handler.cc asio_server_http2_handler.h \
|
||||
asio_server_connection.h \
|
||||
asio_server_request.cc \
|
||||
asio_server_request_impl.cc asio_server_request_impl.h \
|
||||
asio_server_response.cc \
|
||||
asio_server_response_impl.cc asio_server_response_impl.h \
|
||||
asio_server_stream.cc asio_server_stream.h \
|
||||
asio_server_serve_mux.cc asio_server_serve_mux.h \
|
||||
asio_server_request_handler.cc asio_server_request_handler.h \
|
||||
asio_server_tls_context.cc asio_server_tls_context.h \
|
||||
asio_client_session.cc \
|
||||
asio_client_session_impl.cc asio_client_session_impl.h \
|
||||
asio_client_session_tcp_impl.cc asio_client_session_tcp_impl.h \
|
||||
asio_client_session_tls_impl.cc asio_client_session_tls_impl.h \
|
||||
asio_client_response.cc \
|
||||
asio_client_response_impl.cc asio_client_response_impl.h \
|
||||
asio_client_request.cc \
|
||||
asio_client_request_impl.cc asio_client_request_impl.h \
|
||||
asio_client_stream.cc asio_client_stream.h \
|
||||
asio_client_tls_context.cc asio_client_tls_context.h
|
||||
|
||||
libnghttp2_asio_la_CPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
|
||||
libnghttp2_asio_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0
|
||||
libnghttp2_asio_la_LIBADD = \
|
||||
$(top_builddir)/lib/libnghttp2.la \
|
||||
$(top_builddir)/third-party/liburl-parser.la \
|
||||
$(top_builddir)/third-party/libllhttp.la \
|
||||
@OPENSSL_LIBS@ \
|
||||
${BOOST_LDFLAGS} \
|
||||
${BOOST_ASIO_LIB} \
|
||||
${BOOST_THREAD_LIB} \
|
||||
${BOOST_SYSTEM_LIB}
|
||||
|
||||
endif # ENABLE_ASIO_LIB
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
#include "asio_client_request_impl.h"
|
||||
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
request::request() : impl_(std::make_unique<request_impl>()) {}
|
||||
|
||||
request::~request() {}
|
||||
|
||||
void request::write_trailer(header_map h) const {
|
||||
impl_->write_trailer(std::move(h));
|
||||
}
|
||||
|
||||
void request::cancel(uint32_t error_code) const { impl_->cancel(error_code); }
|
||||
|
||||
void request::on_response(response_cb cb) const {
|
||||
impl_->on_response(std::move(cb));
|
||||
}
|
||||
|
||||
void request::on_push(request_cb cb) const { impl_->on_push(std::move(cb)); }
|
||||
|
||||
void request::on_close(close_cb cb) const { impl_->on_close(std::move(cb)); }
|
||||
|
||||
const uri_ref &request::uri() const { return impl_->uri(); }
|
||||
|
||||
const std::string &request::method() const { return impl_->method(); }
|
||||
|
||||
const header_map &request::header() const { return impl_->header(); }
|
||||
|
||||
void request::resume() const { impl_->resume(); }
|
||||
|
||||
request_impl &request::impl() const { return *impl_; }
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_request_impl.h"
|
||||
|
||||
#include "asio_client_stream.h"
|
||||
#include "asio_client_session_impl.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
request_impl::request_impl() : strm_(nullptr), header_buffer_size_(0) {}
|
||||
|
||||
void request_impl::write_trailer(header_map h) {
|
||||
auto sess = strm_->session();
|
||||
sess->write_trailer(*strm_, std::move(h));
|
||||
}
|
||||
|
||||
void request_impl::cancel(uint32_t error_code) {
|
||||
auto sess = strm_->session();
|
||||
sess->cancel(*strm_, error_code);
|
||||
}
|
||||
|
||||
void request_impl::on_response(response_cb cb) { response_cb_ = std::move(cb); }
|
||||
|
||||
void request_impl::call_on_response(response &res) {
|
||||
if (response_cb_) {
|
||||
response_cb_(res);
|
||||
}
|
||||
}
|
||||
|
||||
void request_impl::on_push(request_cb cb) { push_request_cb_ = std::move(cb); }
|
||||
|
||||
void request_impl::call_on_push(request &push_req) {
|
||||
if (push_request_cb_) {
|
||||
push_request_cb_(push_req);
|
||||
}
|
||||
};
|
||||
|
||||
void request_impl::on_close(close_cb cb) { close_cb_ = std::move(cb); }
|
||||
|
||||
void request_impl::call_on_close(uint32_t error_code) {
|
||||
if (close_cb_) {
|
||||
close_cb_(error_code);
|
||||
}
|
||||
}
|
||||
|
||||
void request_impl::on_read(generator_cb cb) { generator_cb_ = std::move(cb); }
|
||||
|
||||
generator_cb::result_type request_impl::call_on_read(uint8_t *buf,
|
||||
std::size_t len,
|
||||
uint32_t *data_flags) {
|
||||
if (generator_cb_) {
|
||||
return generator_cb_(buf, len, data_flags);
|
||||
}
|
||||
|
||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void request_impl::resume() {
|
||||
auto sess = strm_->session();
|
||||
sess->resume(*strm_);
|
||||
}
|
||||
|
||||
void request_impl::header(header_map h) { header_ = std::move(h); }
|
||||
|
||||
header_map &request_impl::header() { return header_; }
|
||||
|
||||
const header_map &request_impl::header() const { return header_; }
|
||||
|
||||
void request_impl::stream(class stream *strm) { strm_ = strm; }
|
||||
|
||||
void request_impl::uri(uri_ref uri) { uri_ = std::move(uri); }
|
||||
|
||||
const uri_ref &request_impl::uri() const { return uri_; }
|
||||
|
||||
uri_ref &request_impl::uri() { return uri_; }
|
||||
|
||||
void request_impl::method(std::string s) { method_ = std::move(s); }
|
||||
|
||||
const std::string &request_impl::method() const { return method_; }
|
||||
|
||||
size_t request_impl::header_buffer_size() const { return header_buffer_size_; }
|
||||
|
||||
void request_impl::update_header_buffer_size(size_t len) {
|
||||
header_buffer_size_ += len;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_REQUEST_IMPL_H
|
||||
#define ASIO_CLIENT_REQUEST_IMPL_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
class response;
|
||||
class stream;
|
||||
|
||||
class request_impl {
|
||||
public:
|
||||
request_impl();
|
||||
|
||||
request_impl(const request_impl &) = delete;
|
||||
request_impl &operator=(const request_impl &) = delete;
|
||||
|
||||
void write_trailer(header_map h);
|
||||
|
||||
void cancel(uint32_t error_code);
|
||||
|
||||
void on_response(response_cb cb);
|
||||
void call_on_response(response &res);
|
||||
|
||||
void on_push(request_cb cb);
|
||||
void call_on_push(request &push_req);
|
||||
|
||||
void on_close(close_cb cb);
|
||||
void call_on_close(uint32_t error_code);
|
||||
|
||||
void on_read(generator_cb cb);
|
||||
generator_cb::result_type call_on_read(uint8_t *buf, std::size_t len,
|
||||
uint32_t *data_flags);
|
||||
|
||||
void resume();
|
||||
|
||||
void header(header_map h);
|
||||
header_map &header();
|
||||
const header_map &header() const;
|
||||
|
||||
void stream(class stream *strm);
|
||||
|
||||
void uri(uri_ref uri);
|
||||
const uri_ref &uri() const;
|
||||
uri_ref &uri();
|
||||
|
||||
void method(std::string s);
|
||||
const std::string &method() const;
|
||||
|
||||
size_t header_buffer_size() const;
|
||||
void update_header_buffer_size(size_t len);
|
||||
|
||||
private:
|
||||
header_map header_;
|
||||
response_cb response_cb_;
|
||||
request_cb push_request_cb_;
|
||||
close_cb close_cb_;
|
||||
generator_cb generator_cb_;
|
||||
class stream *strm_;
|
||||
uri_ref uri_;
|
||||
std::string method_;
|
||||
size_t header_buffer_size_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_REQUEST_IMPL_H
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
#include "asio_client_response_impl.h"
|
||||
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
response::response() : impl_(std::make_unique<response_impl>()) {}
|
||||
|
||||
response::~response() {}
|
||||
|
||||
void response::on_data(data_cb cb) const { impl_->on_data(std::move(cb)); }
|
||||
|
||||
int response::status_code() const { return impl_->status_code(); }
|
||||
|
||||
int64_t response::content_length() const { return impl_->content_length(); }
|
||||
|
||||
const header_map &response::header() const { return impl_->header(); }
|
||||
|
||||
response_impl &response::impl() const { return *impl_; }
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_response_impl.h"
|
||||
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
response_impl::response_impl()
|
||||
: content_length_(-1), header_buffer_size_(0), status_code_(0) {}
|
||||
|
||||
void response_impl::on_data(data_cb cb) { data_cb_ = std::move(cb); }
|
||||
|
||||
void response_impl::call_on_data(const uint8_t *data, std::size_t len) {
|
||||
if (data_cb_) {
|
||||
data_cb_(data, len);
|
||||
}
|
||||
}
|
||||
|
||||
void response_impl::status_code(int sc) { status_code_ = sc; }
|
||||
|
||||
int response_impl::status_code() const { return status_code_; }
|
||||
|
||||
void response_impl::content_length(int64_t n) { content_length_ = n; }
|
||||
|
||||
int64_t response_impl::content_length() const { return content_length_; }
|
||||
|
||||
header_map &response_impl::header() { return header_; }
|
||||
|
||||
const header_map &response_impl::header() const { return header_; }
|
||||
|
||||
size_t response_impl::header_buffer_size() const { return header_buffer_size_; }
|
||||
|
||||
void response_impl::update_header_buffer_size(size_t len) {
|
||||
header_buffer_size_ += len;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_RESPONSE_IMPL_H
|
||||
#define ASIO_CLIENT_RESPONSE_IMPL_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
class response_impl {
|
||||
public:
|
||||
response_impl();
|
||||
|
||||
response_impl(const response_impl &) = delete;
|
||||
response_impl &operator=(const response_impl &) = delete;
|
||||
|
||||
void on_data(data_cb cb);
|
||||
|
||||
void call_on_data(const uint8_t *data, std::size_t len);
|
||||
|
||||
void status_code(int sc);
|
||||
int status_code() const;
|
||||
|
||||
void content_length(int64_t n);
|
||||
int64_t content_length() const;
|
||||
|
||||
header_map &header();
|
||||
const header_map &header() const;
|
||||
|
||||
size_t header_buffer_size() const;
|
||||
void update_header_buffer_size(size_t len);
|
||||
|
||||
private:
|
||||
data_cb data_cb_;
|
||||
|
||||
header_map header_;
|
||||
|
||||
int64_t content_length_;
|
||||
size_t header_buffer_size_;
|
||||
int status_code_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_RESPONSE_IMPL_H
|
|
@ -1,161 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
#include "asio_client_session_tcp_impl.h"
|
||||
#include "asio_client_session_tls_impl.h"
|
||||
#include "asio_common.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
session::session(boost::asio::io_service &io_service, const std::string &host,
|
||||
const std::string &service)
|
||||
: impl_(std::make_shared<session_tcp_impl>(
|
||||
io_service, host, service, boost::posix_time::seconds(60))) {
|
||||
impl_->start_resolve(host, service);
|
||||
}
|
||||
|
||||
session::session(boost::asio::io_service &io_service,
|
||||
const boost::asio::ip::tcp::endpoint &local_endpoint,
|
||||
const std::string &host, const std::string &service)
|
||||
: impl_(std::make_shared<session_tcp_impl>(
|
||||
io_service, local_endpoint, host, service,
|
||||
boost::posix_time::seconds(60))) {
|
||||
impl_->start_resolve(host, service);
|
||||
}
|
||||
|
||||
session::session(boost::asio::io_service &io_service, const std::string &host,
|
||||
const std::string &service,
|
||||
const boost::posix_time::time_duration &connect_timeout)
|
||||
: impl_(std::make_shared<session_tcp_impl>(io_service, host, service,
|
||||
connect_timeout)) {
|
||||
impl_->start_resolve(host, service);
|
||||
}
|
||||
|
||||
session::session(boost::asio::io_service &io_service,
|
||||
const boost::asio::ip::tcp::endpoint &local_endpoint,
|
||||
const std::string &host, const std::string &service,
|
||||
const boost::posix_time::time_duration &connect_timeout)
|
||||
: impl_(std::make_shared<session_tcp_impl>(io_service, local_endpoint, host,
|
||||
service, connect_timeout)) {
|
||||
impl_->start_resolve(host, service);
|
||||
}
|
||||
|
||||
session::session(boost::asio::io_service &io_service,
|
||||
boost::asio::ssl::context &tls_ctx, const std::string &host,
|
||||
const std::string &service)
|
||||
: impl_(std::make_shared<session_tls_impl>(
|
||||
io_service, tls_ctx, host, service, boost::posix_time::seconds(60))) {
|
||||
impl_->start_resolve(host, service);
|
||||
}
|
||||
|
||||
session::session(boost::asio::io_service &io_service,
|
||||
boost::asio::ssl::context &tls_ctx, const std::string &host,
|
||||
const std::string &service,
|
||||
const boost::posix_time::time_duration &connect_timeout)
|
||||
: impl_(std::make_shared<session_tls_impl>(io_service, tls_ctx, host,
|
||||
service, connect_timeout)) {
|
||||
impl_->start_resolve(host, service);
|
||||
}
|
||||
|
||||
session::~session() {}
|
||||
|
||||
session::session(session &&other) noexcept : impl_(std::move(other.impl_)) {}
|
||||
|
||||
session &session::operator=(session &&other) noexcept {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
impl_ = std::move(other.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void session::on_connect(connect_cb cb) const {
|
||||
impl_->on_connect(std::move(cb));
|
||||
}
|
||||
|
||||
void session::on_error(error_cb cb) const { impl_->on_error(std::move(cb)); }
|
||||
|
||||
void session::shutdown() const { impl_->shutdown(); }
|
||||
|
||||
boost::asio::io_service &session::io_service() const {
|
||||
return impl_->io_service();
|
||||
}
|
||||
|
||||
const request *session::submit(boost::system::error_code &ec,
|
||||
const std::string &method,
|
||||
const std::string &uri, header_map h,
|
||||
priority_spec prio) const {
|
||||
return impl_->submit(ec, method, uri, generator_cb(), std::move(h),
|
||||
std::move(prio));
|
||||
}
|
||||
|
||||
const request *session::submit(boost::system::error_code &ec,
|
||||
const std::string &method,
|
||||
const std::string &uri, std::string data,
|
||||
header_map h, priority_spec prio) const {
|
||||
return impl_->submit(ec, method, uri, string_generator(std::move(data)),
|
||||
std::move(h), std::move(prio));
|
||||
}
|
||||
|
||||
const request *session::submit(boost::system::error_code &ec,
|
||||
const std::string &method,
|
||||
const std::string &uri, generator_cb cb,
|
||||
header_map h, priority_spec prio) const {
|
||||
return impl_->submit(ec, method, uri, std::move(cb), std::move(h),
|
||||
std::move(prio));
|
||||
}
|
||||
|
||||
void session::read_timeout(const boost::posix_time::time_duration &t) {
|
||||
impl_->read_timeout(t);
|
||||
}
|
||||
|
||||
priority_spec::priority_spec(const int32_t stream_id, const int32_t weight,
|
||||
const bool exclusive)
|
||||
: valid_(true) {
|
||||
nghttp2_priority_spec_init(&spec_, stream_id, weight, exclusive);
|
||||
}
|
||||
|
||||
const nghttp2_priority_spec *priority_spec::get() const {
|
||||
if (!valid_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &spec_;
|
||||
}
|
||||
|
||||
bool priority_spec::valid() const { return valid_; }
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,759 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_session_impl.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "asio_client_stream.h"
|
||||
#include "asio_client_request_impl.h"
|
||||
#include "asio_client_response_impl.h"
|
||||
#include "asio_common.h"
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
#include "http2.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
session_impl::session_impl(
|
||||
boost::asio::io_service &io_service,
|
||||
const boost::posix_time::time_duration &connect_timeout)
|
||||
: wblen_(0),
|
||||
io_service_(io_service),
|
||||
resolver_(io_service),
|
||||
deadline_(io_service),
|
||||
connect_timeout_(connect_timeout),
|
||||
read_timeout_(boost::posix_time::seconds(60)),
|
||||
ping_(io_service),
|
||||
session_(nullptr),
|
||||
data_pending_(nullptr),
|
||||
data_pendinglen_(0),
|
||||
writing_(false),
|
||||
inside_callback_(false),
|
||||
stopped_(false) {}
|
||||
|
||||
session_impl::~session_impl() {
|
||||
// finish up all active stream
|
||||
for (auto &p : streams_) {
|
||||
auto &strm = p.second;
|
||||
auto &req = strm->request().impl();
|
||||
req.call_on_close(NGHTTP2_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
nghttp2_session_del(session_);
|
||||
}
|
||||
|
||||
void session_impl::start_resolve(const std::string &host,
|
||||
const std::string &service) {
|
||||
deadline_.expires_from_now(connect_timeout_);
|
||||
|
||||
auto self = shared_from_this();
|
||||
|
||||
resolver_.async_resolve({host, service},
|
||||
[self](const boost::system::error_code &ec,
|
||||
tcp::resolver::iterator endpoint_it) {
|
||||
if (ec) {
|
||||
self->not_connected(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
self->start_connect(endpoint_it);
|
||||
});
|
||||
|
||||
deadline_.async_wait(std::bind(&session_impl::handle_deadline, self));
|
||||
}
|
||||
|
||||
void session_impl::handle_deadline() {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (deadline_.expires_at() <=
|
||||
boost::asio::deadline_timer::traits_type::now()) {
|
||||
call_error_cb(boost::asio::error::timed_out);
|
||||
stop();
|
||||
deadline_.expires_at(boost::posix_time::pos_infin);
|
||||
return;
|
||||
}
|
||||
|
||||
deadline_.async_wait(
|
||||
std::bind(&session_impl::handle_deadline, this->shared_from_this()));
|
||||
}
|
||||
|
||||
void handle_ping2(const boost::system::error_code &ec, int) {}
|
||||
|
||||
void session_impl::start_ping() {
|
||||
ping_.expires_from_now(boost::posix_time::seconds(30));
|
||||
ping_.async_wait(std::bind(&session_impl::handle_ping, shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
void session_impl::handle_ping(const boost::system::error_code &ec) {
|
||||
if (stopped_ || ec == boost::asio::error::operation_aborted ||
|
||||
!streams_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp2_submit_ping(session_, NGHTTP2_FLAG_NONE, nullptr);
|
||||
|
||||
signal_write();
|
||||
|
||||
start_ping();
|
||||
}
|
||||
|
||||
void session_impl::connected(tcp::resolver::iterator endpoint_it) {
|
||||
if (!setup_session()) {
|
||||
return;
|
||||
}
|
||||
|
||||
socket().set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
|
||||
do_write();
|
||||
do_read();
|
||||
|
||||
start_ping();
|
||||
|
||||
auto &connect_cb = on_connect();
|
||||
if (connect_cb) {
|
||||
connect_cb(endpoint_it);
|
||||
}
|
||||
}
|
||||
|
||||
void session_impl::not_connected(const boost::system::error_code &ec) {
|
||||
call_error_cb(ec);
|
||||
stop();
|
||||
}
|
||||
|
||||
void session_impl::on_connect(connect_cb cb) { connect_cb_ = std::move(cb); }
|
||||
|
||||
void session_impl::on_error(error_cb cb) { error_cb_ = std::move(cb); }
|
||||
|
||||
const connect_cb &session_impl::on_connect() const { return connect_cb_; }
|
||||
|
||||
const error_cb &session_impl::on_error() const { return error_cb_; }
|
||||
|
||||
void session_impl::call_error_cb(const boost::system::error_code &ec) {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
auto &error_cb = on_error();
|
||||
if (!error_cb) {
|
||||
return;
|
||||
}
|
||||
error_cb(ec);
|
||||
}
|
||||
|
||||
namespace {
|
||||
int on_begin_headers_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, void *user_data) {
|
||||
if (frame->hd.type != NGHTTP2_PUSH_PROMISE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
sess->create_push_stream(frame->push_promise.promised_stream_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen, uint8_t flags,
|
||||
void *user_data) {
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
stream *strm;
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS: {
|
||||
strm = sess->find_stream(frame->hd.stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ignore trailers
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_HEADERS &&
|
||||
!strm->expect_final_response()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
|
||||
auto &res = strm->response().impl();
|
||||
if (token == http2::HD__STATUS) {
|
||||
res.status_code(util::parse_uint(value, valuelen));
|
||||
} else {
|
||||
if (res.header_buffer_size() + namelen + valuelen > 64_k) {
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||
frame->hd.stream_id, NGHTTP2_INTERNAL_ERROR);
|
||||
break;
|
||||
}
|
||||
res.update_header_buffer_size(namelen + valuelen);
|
||||
|
||||
if (token == http2::HD_CONTENT_LENGTH) {
|
||||
res.content_length(util::parse_uint(value, valuelen));
|
||||
}
|
||||
|
||||
res.header().emplace(
|
||||
std::string(name, name + namelen),
|
||||
header_value{std::string(value, value + valuelen),
|
||||
(flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_PUSH_PROMISE: {
|
||||
strm = sess->find_stream(frame->push_promise.promised_stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto &req = strm->request().impl();
|
||||
auto &uri = req.uri();
|
||||
|
||||
switch (http2::lookup_token(name, namelen)) {
|
||||
case http2::HD__METHOD:
|
||||
req.method(std::string(value, value + valuelen));
|
||||
break;
|
||||
case http2::HD__SCHEME:
|
||||
uri.scheme.assign(value, value + valuelen);
|
||||
break;
|
||||
case http2::HD__PATH:
|
||||
split_path(uri, value, value + valuelen);
|
||||
break;
|
||||
case http2::HD__AUTHORITY:
|
||||
uri.host.assign(value, value + valuelen);
|
||||
break;
|
||||
case http2::HD_HOST:
|
||||
if (uri.host.empty()) {
|
||||
uri.host.assign(value, value + valuelen);
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
if (req.header_buffer_size() + namelen + valuelen > 64_k) {
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||
frame->hd.stream_id, NGHTTP2_INTERNAL_ERROR);
|
||||
break;
|
||||
}
|
||||
req.update_header_buffer_size(namelen + valuelen);
|
||||
|
||||
req.header().emplace(
|
||||
std::string(name, name + namelen),
|
||||
header_value{std::string(value, value + valuelen),
|
||||
(flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
auto strm = sess->find_stream(frame->hd.stream_id);
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_DATA: {
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
strm->response().impl().call_on_data(nullptr, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_HEADERS: {
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ignore trailers
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_HEADERS &&
|
||||
!strm->expect_final_response()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strm->expect_final_response()) {
|
||||
// wait for final response
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto &req = strm->request().impl();
|
||||
req.call_on_response(strm->response());
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
strm->response().impl().call_on_data(nullptr, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_PUSH_PROMISE: {
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto push_strm = sess->find_stream(frame->push_promise.promised_stream_id);
|
||||
if (!push_strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
strm->request().impl().call_on_push(push_strm->request());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *data,
|
||||
size_t len, void *user_data) {
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
auto strm = sess->find_stream(stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto &res = strm->response().impl();
|
||||
res.call_on_data(data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code, void *user_data) {
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
auto strm = sess->pop_stream(stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
strm->request().impl().call_on_close(error_code);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool session_impl::setup_session() {
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
auto cb_del = defer(nghttp2_session_callbacks_del, callbacks);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
callbacks, on_begin_headers_callback);
|
||||
nghttp2_session_callbacks_set_on_header_callback(callbacks,
|
||||
on_header_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
|
||||
on_frame_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
callbacks, on_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, on_stream_close_callback);
|
||||
|
||||
auto rv = nghttp2_session_client_new(&session_, callbacks, this);
|
||||
if (rv != 0) {
|
||||
call_error_cb(make_error_code(static_cast<nghttp2_error>(rv)));
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t window_size = 256_m;
|
||||
|
||||
std::array<nghttp2_settings_entry, 2> iv{
|
||||
{{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100},
|
||||
// typically client is just a *sink* and just process data as
|
||||
// much as possible. Use large window size by default.
|
||||
{NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, window_size}}};
|
||||
nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, iv.data(), iv.size());
|
||||
// increase connection window size up to window_size
|
||||
nghttp2_session_set_local_window_size(session_, NGHTTP2_FLAG_NONE, 0,
|
||||
window_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
int session_impl::write_trailer(stream &strm, header_map h) {
|
||||
int rv;
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(h.size());
|
||||
for (auto &hd : h) {
|
||||
nva.push_back(nghttp2::http2::make_nv(hd.first, hd.second.value,
|
||||
hd.second.sensitive));
|
||||
}
|
||||
|
||||
rv = nghttp2_submit_trailer(session_, strm.stream_id(), nva.data(),
|
||||
nva.size());
|
||||
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
signal_write();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void session_impl::cancel(stream &strm, uint32_t error_code) {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp2_submit_rst_stream(session_, NGHTTP2_FLAG_NONE, strm.stream_id(),
|
||||
error_code);
|
||||
signal_write();
|
||||
}
|
||||
|
||||
void session_impl::resume(stream &strm) {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp2_session_resume_data(session_, strm.stream_id());
|
||||
signal_write();
|
||||
}
|
||||
|
||||
stream *session_impl::find_stream(int32_t stream_id) {
|
||||
auto it = streams_.find(stream_id);
|
||||
if (it == std::end(streams_)) {
|
||||
return nullptr;
|
||||
}
|
||||
return (*it).second.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<stream> session_impl::pop_stream(int32_t stream_id) {
|
||||
auto it = streams_.find(stream_id);
|
||||
if (it == std::end(streams_)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto strm = std::move((*it).second);
|
||||
streams_.erase(it);
|
||||
if (streams_.empty()) {
|
||||
start_ping();
|
||||
}
|
||||
return strm;
|
||||
}
|
||||
|
||||
stream *session_impl::create_push_stream(int32_t stream_id) {
|
||||
auto strm = create_stream();
|
||||
strm->stream_id(stream_id);
|
||||
auto p = streams_.emplace(stream_id, std::move(strm));
|
||||
assert(p.second);
|
||||
ping_.cancel();
|
||||
return (*p.first).second.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<stream> session_impl::create_stream() {
|
||||
return std::make_unique<stream>(this);
|
||||
}
|
||||
|
||||
const request *session_impl::submit(boost::system::error_code &ec,
|
||||
const std::string &method,
|
||||
const std::string &uri, generator_cb cb,
|
||||
header_map h, priority_spec prio) {
|
||||
ec.clear();
|
||||
|
||||
if (stopped_) {
|
||||
ec = make_error_code(static_cast<nghttp2_error>(NGHTTP2_INTERNAL_ERROR));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
http_parser_url u{};
|
||||
// TODO Handle CONNECT method
|
||||
if (http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) != 0) {
|
||||
ec = make_error_code(boost::system::errc::invalid_argument);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((u.field_set & (1 << UF_SCHEMA)) == 0 ||
|
||||
(u.field_set & (1 << UF_HOST)) == 0) {
|
||||
ec = make_error_code(boost::system::errc::invalid_argument);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto strm = create_stream();
|
||||
auto &req = strm->request().impl();
|
||||
auto &uref = req.uri();
|
||||
|
||||
http2::copy_url_component(uref.scheme, &u, UF_SCHEMA, uri.c_str());
|
||||
http2::copy_url_component(uref.host, &u, UF_HOST, uri.c_str());
|
||||
http2::copy_url_component(uref.raw_path, &u, UF_PATH, uri.c_str());
|
||||
http2::copy_url_component(uref.raw_query, &u, UF_QUERY, uri.c_str());
|
||||
|
||||
if (util::ipv6_numeric_addr(uref.host.c_str())) {
|
||||
uref.host = "[" + uref.host;
|
||||
uref.host += ']';
|
||||
}
|
||||
if (u.field_set & (1 << UF_PORT)) {
|
||||
uref.host += ':';
|
||||
uref.host += util::utos(u.port);
|
||||
}
|
||||
|
||||
if (uref.raw_path.empty()) {
|
||||
uref.raw_path = "/";
|
||||
}
|
||||
|
||||
uref.path = percent_decode(uref.raw_path);
|
||||
|
||||
auto path = uref.raw_path;
|
||||
if (u.field_set & (1 << UF_QUERY)) {
|
||||
path += '?';
|
||||
path += uref.raw_query;
|
||||
}
|
||||
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(4 + h.size());
|
||||
nva.push_back(http2::make_nv_ls(":method", method));
|
||||
nva.push_back(http2::make_nv_ls(":scheme", uref.scheme));
|
||||
nva.push_back(http2::make_nv_ls(":path", path));
|
||||
nva.push_back(http2::make_nv_ls(":authority", uref.host));
|
||||
for (auto &kv : h) {
|
||||
nva.push_back(
|
||||
http2::make_nv(kv.first, kv.second.value, kv.second.sensitive));
|
||||
}
|
||||
|
||||
req.header(std::move(h));
|
||||
|
||||
nghttp2_data_provider *prdptr = nullptr;
|
||||
nghttp2_data_provider prd;
|
||||
|
||||
if (cb) {
|
||||
strm->request().impl().on_read(std::move(cb));
|
||||
prd.source.ptr = strm.get();
|
||||
prd.read_callback = [](nghttp2_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t length, uint32_t *data_flags,
|
||||
nghttp2_data_source *source,
|
||||
void *user_data) -> ssize_t {
|
||||
auto strm = static_cast<stream *>(source->ptr);
|
||||
return strm->request().impl().call_on_read(buf, length, data_flags);
|
||||
};
|
||||
prdptr = &prd;
|
||||
}
|
||||
|
||||
auto stream_id = nghttp2_submit_request(session_, prio.get(), nva.data(),
|
||||
nva.size(), prdptr, strm.get());
|
||||
if (stream_id < 0) {
|
||||
ec = make_error_code(static_cast<nghttp2_error>(stream_id));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
signal_write();
|
||||
|
||||
strm->stream_id(stream_id);
|
||||
|
||||
auto p = streams_.emplace(stream_id, std::move(strm));
|
||||
assert(p.second);
|
||||
ping_.cancel();
|
||||
return &(*p.first).second->request();
|
||||
}
|
||||
|
||||
void session_impl::shutdown() {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp2_session_terminate_session(session_, NGHTTP2_NO_ERROR);
|
||||
signal_write();
|
||||
}
|
||||
|
||||
boost::asio::io_service &session_impl::io_service() { return io_service_; }
|
||||
|
||||
void session_impl::signal_write() {
|
||||
if (!inside_callback_) {
|
||||
do_write();
|
||||
}
|
||||
}
|
||||
|
||||
bool session_impl::should_stop() const {
|
||||
return !writing_ && !nghttp2_session_want_read(session_) &&
|
||||
!nghttp2_session_want_write(session_);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct callback_guard {
|
||||
callback_guard(session_impl &sess) : sess(sess) { sess.enter_callback(); }
|
||||
~callback_guard() { sess.leave_callback(); }
|
||||
|
||||
session_impl &sess;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void session_impl::enter_callback() {
|
||||
assert(!inside_callback_);
|
||||
inside_callback_ = true;
|
||||
}
|
||||
|
||||
void session_impl::leave_callback() {
|
||||
assert(inside_callback_);
|
||||
inside_callback_ = false;
|
||||
}
|
||||
|
||||
void session_impl::do_read() {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
deadline_.expires_from_now(read_timeout_);
|
||||
|
||||
auto self = this->shared_from_this();
|
||||
|
||||
read_socket([self](const boost::system::error_code &ec,
|
||||
std::size_t bytes_transferred) {
|
||||
if (ec) {
|
||||
if (!self->should_stop()) {
|
||||
self->call_error_cb(ec);
|
||||
}
|
||||
self->stop();
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
callback_guard cg(*self);
|
||||
|
||||
auto rv = nghttp2_session_mem_recv(self->session_, self->rb_.data(),
|
||||
bytes_transferred);
|
||||
|
||||
if (rv != static_cast<ssize_t>(bytes_transferred)) {
|
||||
self->call_error_cb(make_error_code(
|
||||
static_cast<nghttp2_error>(rv < 0 ? rv : NGHTTP2_ERR_PROTO)));
|
||||
self->stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self->do_write();
|
||||
|
||||
if (self->should_stop()) {
|
||||
self->stop();
|
||||
return;
|
||||
}
|
||||
|
||||
self->do_read();
|
||||
});
|
||||
}
|
||||
|
||||
void session_impl::do_write() {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (writing_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_pending_) {
|
||||
std::copy_n(data_pending_, data_pendinglen_, std::begin(wb_) + wblen_);
|
||||
|
||||
wblen_ += data_pendinglen_;
|
||||
|
||||
data_pending_ = nullptr;
|
||||
data_pendinglen_ = 0;
|
||||
}
|
||||
|
||||
{
|
||||
callback_guard cg(*this);
|
||||
|
||||
for (;;) {
|
||||
const uint8_t *data;
|
||||
auto n = nghttp2_session_mem_send(session_, &data);
|
||||
if (n < 0) {
|
||||
call_error_cb(make_error_code(static_cast<nghttp2_error>(n)));
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (wblen_ + n > wb_.size()) {
|
||||
data_pending_ = data;
|
||||
data_pendinglen_ = n;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
std::copy_n(data, n, std::begin(wb_) + wblen_);
|
||||
|
||||
wblen_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
if (wblen_ == 0) {
|
||||
if (should_stop()) {
|
||||
stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
writing_ = true;
|
||||
|
||||
// Reset read deadline here, because normally client is sending
|
||||
// something, it does not expect timeout while doing it.
|
||||
deadline_.expires_from_now(read_timeout_);
|
||||
|
||||
auto self = this->shared_from_this();
|
||||
|
||||
write_socket([self](const boost::system::error_code &ec, std::size_t n) {
|
||||
if (ec) {
|
||||
self->call_error_cb(ec);
|
||||
self->stop();
|
||||
return;
|
||||
}
|
||||
|
||||
self->wblen_ = 0;
|
||||
self->writing_ = false;
|
||||
|
||||
self->do_write();
|
||||
});
|
||||
}
|
||||
|
||||
void session_impl::stop() {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
shutdown_socket();
|
||||
deadline_.cancel();
|
||||
ping_.cancel();
|
||||
stopped_ = true;
|
||||
}
|
||||
|
||||
bool session_impl::stopped() const { return stopped_; }
|
||||
|
||||
void session_impl::read_timeout(const boost::posix_time::time_duration &t) {
|
||||
read_timeout_ = t;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_SESSION_IMPL_H
|
||||
#define ASIO_CLIENT_SESSION_IMPL_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <boost/array.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
class stream;
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
class session_impl : public std::enable_shared_from_this<session_impl> {
|
||||
public:
|
||||
session_impl(boost::asio::io_service &io_service,
|
||||
const boost::posix_time::time_duration &connect_timeout);
|
||||
virtual ~session_impl();
|
||||
|
||||
void start_resolve(const std::string &host, const std::string &service);
|
||||
|
||||
void connected(tcp::resolver::iterator endpoint_it);
|
||||
void not_connected(const boost::system::error_code &ec);
|
||||
|
||||
void on_connect(connect_cb cb);
|
||||
void on_error(error_cb cb);
|
||||
|
||||
const connect_cb &on_connect() const;
|
||||
const error_cb &on_error() const;
|
||||
|
||||
int write_trailer(stream &strm, header_map h);
|
||||
|
||||
void cancel(stream &strm, uint32_t error_code);
|
||||
void resume(stream &strm);
|
||||
|
||||
std::unique_ptr<stream> create_stream();
|
||||
std::unique_ptr<stream> pop_stream(int32_t stream_id);
|
||||
stream *create_push_stream(int32_t stream_id);
|
||||
stream *find_stream(int32_t stream_id);
|
||||
|
||||
const request *submit(boost::system::error_code &ec,
|
||||
const std::string &method, const std::string &uri,
|
||||
generator_cb cb, header_map h, priority_spec spec);
|
||||
|
||||
virtual void start_connect(tcp::resolver::iterator endpoint_it) = 0;
|
||||
virtual tcp::socket &socket() = 0;
|
||||
virtual void read_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)>
|
||||
h) = 0;
|
||||
virtual void write_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)>
|
||||
h) = 0;
|
||||
virtual void shutdown_socket() = 0;
|
||||
|
||||
void shutdown();
|
||||
|
||||
boost::asio::io_service &io_service();
|
||||
|
||||
void signal_write();
|
||||
|
||||
void enter_callback();
|
||||
void leave_callback();
|
||||
|
||||
void do_read();
|
||||
void do_write();
|
||||
|
||||
void read_timeout(const boost::posix_time::time_duration &t);
|
||||
|
||||
void stop();
|
||||
bool stopped() const;
|
||||
|
||||
protected:
|
||||
boost::array<uint8_t, 8_k> rb_;
|
||||
boost::array<uint8_t, 64_k> wb_;
|
||||
std::size_t wblen_;
|
||||
|
||||
private:
|
||||
bool should_stop() const;
|
||||
bool setup_session();
|
||||
void call_error_cb(const boost::system::error_code &ec);
|
||||
void handle_deadline();
|
||||
void start_ping();
|
||||
void handle_ping(const boost::system::error_code &ec);
|
||||
|
||||
boost::asio::io_service &io_service_;
|
||||
tcp::resolver resolver_;
|
||||
|
||||
std::map<int32_t, std::unique_ptr<stream>> streams_;
|
||||
|
||||
connect_cb connect_cb_;
|
||||
error_cb error_cb_;
|
||||
|
||||
boost::asio::deadline_timer deadline_;
|
||||
boost::posix_time::time_duration connect_timeout_;
|
||||
boost::posix_time::time_duration read_timeout_;
|
||||
|
||||
boost::asio::deadline_timer ping_;
|
||||
|
||||
nghttp2_session *session_;
|
||||
|
||||
const uint8_t *data_pending_;
|
||||
std::size_t data_pendinglen_;
|
||||
|
||||
bool writing_;
|
||||
bool inside_callback_;
|
||||
bool stopped_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_SESSION_IMPL_H
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_session_tcp_impl.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
session_tcp_impl::session_tcp_impl(
|
||||
boost::asio::io_service &io_service, const std::string &host,
|
||||
const std::string &service,
|
||||
const boost::posix_time::time_duration &connect_timeout)
|
||||
: session_impl(io_service, connect_timeout), socket_(io_service) {}
|
||||
|
||||
session_tcp_impl::session_tcp_impl(
|
||||
boost::asio::io_service &io_service,
|
||||
const boost::asio::ip::tcp::endpoint &local_endpoint,
|
||||
const std::string &host, const std::string &service,
|
||||
const boost::posix_time::time_duration &connect_timeout)
|
||||
: session_impl(io_service, connect_timeout), socket_(io_service) {
|
||||
socket_.open(local_endpoint.protocol());
|
||||
boost::asio::socket_base::reuse_address option(true);
|
||||
socket_.set_option(option);
|
||||
socket_.bind(local_endpoint);
|
||||
}
|
||||
|
||||
session_tcp_impl::~session_tcp_impl() {}
|
||||
|
||||
void session_tcp_impl::start_connect(tcp::resolver::iterator endpoint_it) {
|
||||
auto self = shared_from_this();
|
||||
socket_.async_connect(
|
||||
*endpoint_it, [self, endpoint_it](const boost::system::error_code &ec) {
|
||||
if (self->stopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ec) {
|
||||
self->not_connected(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
self->connected(endpoint_it);
|
||||
});
|
||||
}
|
||||
|
||||
tcp::socket &session_tcp_impl::socket() { return socket_; }
|
||||
|
||||
void session_tcp_impl::read_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)> h) {
|
||||
socket_.async_read_some(boost::asio::buffer(rb_), h);
|
||||
}
|
||||
|
||||
void session_tcp_impl::write_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)> h) {
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(wb_, wblen_), h);
|
||||
}
|
||||
|
||||
void session_tcp_impl::shutdown_socket() {
|
||||
boost::system::error_code ignored_ec;
|
||||
socket_.close(ignored_ec);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_SESSION_TCP_IMPL_H
|
||||
#define ASIO_CLIENT_SESSION_TCP_IMPL_H
|
||||
|
||||
#include "asio_client_session_impl.h"
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
class session_tcp_impl : public session_impl {
|
||||
public:
|
||||
session_tcp_impl(boost::asio::io_service &io_service, const std::string &host,
|
||||
const std::string &service,
|
||||
const boost::posix_time::time_duration &connect_timeout);
|
||||
session_tcp_impl(boost::asio::io_service &io_service,
|
||||
const boost::asio::ip::tcp::endpoint &local_endpoint,
|
||||
const std::string &host, const std::string &service,
|
||||
const boost::posix_time::time_duration &connect_timeout);
|
||||
virtual ~session_tcp_impl();
|
||||
|
||||
virtual void start_connect(tcp::resolver::iterator endpoint_it);
|
||||
virtual tcp::socket &socket();
|
||||
virtual void read_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)>
|
||||
h);
|
||||
virtual void write_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)>
|
||||
h);
|
||||
virtual void shutdown_socket();
|
||||
|
||||
private:
|
||||
tcp::socket socket_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_SESSION_TCP_IMPL_H
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_session_tls_impl.h"
|
||||
#include "asio_common.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
session_tls_impl::session_tls_impl(
|
||||
boost::asio::io_service &io_service, boost::asio::ssl::context &tls_ctx,
|
||||
const std::string &host, const std::string &service,
|
||||
const boost::posix_time::time_duration &connect_timeout)
|
||||
: session_impl(io_service, connect_timeout), socket_(io_service, tls_ctx) {
|
||||
// this callback setting is no effect is
|
||||
// ssl::context::set_verify_mode(boost::asio::ssl::verify_peer) is
|
||||
// not used, which is what we want.
|
||||
socket_.set_verify_callback(boost::asio::ssl::rfc2818_verification(host));
|
||||
auto ssl = socket_.native_handle();
|
||||
if (!util::numeric_host(host.c_str())) {
|
||||
SSL_set_tlsext_host_name(ssl, host.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
session_tls_impl::~session_tls_impl() {}
|
||||
|
||||
void session_tls_impl::start_connect(tcp::resolver::iterator endpoint_it) {
|
||||
auto self = std::static_pointer_cast<session_tls_impl>(shared_from_this());
|
||||
boost::asio::async_connect(
|
||||
socket(), endpoint_it,
|
||||
[self](const boost::system::error_code &ec,
|
||||
tcp::resolver::iterator endpoint_it) {
|
||||
if (self->stopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ec) {
|
||||
self->not_connected(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
self->socket_.async_handshake(
|
||||
boost::asio::ssl::stream_base::client,
|
||||
[self, endpoint_it](const boost::system::error_code &ec) {
|
||||
if (self->stopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ec) {
|
||||
self->not_connected(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tls_h2_negotiated(self->socket_)) {
|
||||
self->not_connected(make_error_code(
|
||||
NGHTTP2_ASIO_ERR_TLS_NO_APP_PROTO_NEGOTIATED));
|
||||
return;
|
||||
}
|
||||
|
||||
self->connected(endpoint_it);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
tcp::socket &session_tls_impl::socket() { return socket_.next_layer(); }
|
||||
|
||||
void session_tls_impl::read_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)> h) {
|
||||
socket_.async_read_some(boost::asio::buffer(rb_), h);
|
||||
}
|
||||
|
||||
void session_tls_impl::write_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)> h) {
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(wb_, wblen_), h);
|
||||
}
|
||||
|
||||
void session_tls_impl::shutdown_socket() {
|
||||
boost::system::error_code ignored_ec;
|
||||
socket_.lowest_layer().close(ignored_ec);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_SESSION_TLS_IMPL_H
|
||||
#define ASIO_CLIENT_SESSION_TLS_IMPL_H
|
||||
|
||||
#include "asio_client_session_impl.h"
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using ssl_socket = boost::asio::ssl::stream<tcp::socket>;
|
||||
|
||||
class session_tls_impl : public session_impl {
|
||||
public:
|
||||
session_tls_impl(boost::asio::io_service &io_service,
|
||||
boost::asio::ssl::context &tls_ctx, const std::string &host,
|
||||
const std::string &service,
|
||||
const boost::posix_time::time_duration &connect_timeout);
|
||||
virtual ~session_tls_impl();
|
||||
|
||||
virtual void start_connect(tcp::resolver::iterator endpoint_it);
|
||||
virtual tcp::socket &socket();
|
||||
virtual void read_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)>
|
||||
h);
|
||||
virtual void write_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)>
|
||||
h);
|
||||
virtual void shutdown_socket();
|
||||
|
||||
private:
|
||||
ssl_socket socket_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_SESSION_TLS_IMPL_H
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_stream.h"
|
||||
|
||||
#include "asio_client_request_impl.h"
|
||||
#include "asio_client_response_impl.h"
|
||||
#include "asio_client_session_impl.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
stream::stream(session_impl *sess) : sess_(sess), stream_id_(0) {
|
||||
request_.impl().stream(this);
|
||||
}
|
||||
|
||||
void stream::stream_id(int32_t stream_id) { stream_id_ = stream_id; }
|
||||
|
||||
int32_t stream::stream_id() const { return stream_id_; }
|
||||
|
||||
class request &stream::request() {
|
||||
return request_;
|
||||
}
|
||||
|
||||
class response &stream::response() {
|
||||
return response_;
|
||||
}
|
||||
|
||||
session_impl *stream::session() const { return sess_; }
|
||||
|
||||
bool stream::expect_final_response() const {
|
||||
return response_.status_code() / 100 == 1;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_STREAM_H
|
||||
#define ASIO_CLIENT_STREAM_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
class request;
|
||||
class response;
|
||||
class session_impl;
|
||||
|
||||
class stream {
|
||||
public:
|
||||
stream(session_impl *sess);
|
||||
|
||||
stream(const stream &) = delete;
|
||||
stream &operator=(const stream &) = delete;
|
||||
|
||||
void stream_id(int32_t stream_id);
|
||||
int32_t stream_id() const;
|
||||
|
||||
class request &request();
|
||||
class response &response();
|
||||
|
||||
session_impl *session() const;
|
||||
|
||||
bool expect_final_response() const;
|
||||
|
||||
private:
|
||||
nghttp2::asio_http2::client::request request_;
|
||||
nghttp2::asio_http2::client::response response_;
|
||||
session_impl *sess_;
|
||||
uint32_t stream_id_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_STREAM_H
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_tls_context.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
#include "tls.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
namespace {
|
||||
int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
if (!util::select_h2(const_cast<const unsigned char **>(out), outlen, in,
|
||||
inlen)) {
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
boost::system::error_code
|
||||
configure_tls_context(boost::system::error_code &ec,
|
||||
boost::asio::ssl::context &tls_ctx) {
|
||||
ec.clear();
|
||||
|
||||
auto ctx = tls_ctx.native_handle();
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ctx, client_select_next_proto_cb, nullptr);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
auto proto_list = util::get_default_alpn();
|
||||
|
||||
SSL_CTX_set_alpn_protos(ctx, proto_list.data(), proto_list.size());
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_TLS_CONTEXT_H
|
||||
#define ASIO_CLIENT_TLS_CONTEXT_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_client.h>
|
||||
|
||||
#endif // ASIO_CLIENT_TLS_CONTEXT_H
|
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_common.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
|
||||
#include "util.h"
|
||||
#include "template.h"
|
||||
#include "http2.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
|
||||
class nghttp2_category_impl : public boost::system::error_category {
|
||||
public:
|
||||
const char *name() const noexcept { return "nghttp2"; }
|
||||
std::string message(int ev) const { return nghttp2_strerror(ev); }
|
||||
};
|
||||
|
||||
const boost::system::error_category &nghttp2_category() noexcept {
|
||||
static nghttp2_category_impl cat;
|
||||
return cat;
|
||||
}
|
||||
|
||||
boost::system::error_code make_error_code(nghttp2_error ev) {
|
||||
return boost::system::error_code(static_cast<int>(ev), nghttp2_category());
|
||||
}
|
||||
|
||||
class nghttp2_asio_category_impl : public boost::system::error_category {
|
||||
public:
|
||||
const char *name() const noexcept { return "nghttp2_asio"; }
|
||||
std::string message(int ev) const {
|
||||
switch (ev) {
|
||||
case NGHTTP2_ASIO_ERR_NO_ERROR:
|
||||
return "no error";
|
||||
case NGHTTP2_ASIO_ERR_TLS_NO_APP_PROTO_NEGOTIATED:
|
||||
return "tls: no application protocol negotiated";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const boost::system::error_category &nghttp2_asio_category() noexcept {
|
||||
static nghttp2_asio_category_impl cat;
|
||||
return cat;
|
||||
}
|
||||
|
||||
boost::system::error_code make_error_code(nghttp2_asio_error ev) {
|
||||
return boost::system::error_code(static_cast<int>(ev),
|
||||
nghttp2_asio_category());
|
||||
}
|
||||
|
||||
generator_cb string_generator(std::string data) {
|
||||
auto strio = std::make_shared<std::pair<std::string, size_t>>(std::move(data),
|
||||
data.size());
|
||||
return [strio](uint8_t *buf, size_t len, uint32_t *data_flags) {
|
||||
auto &data = strio->first;
|
||||
auto &left = strio->second;
|
||||
auto n = std::min(len, left);
|
||||
std::copy_n(data.c_str() + data.size() - left, n, buf);
|
||||
left -= n;
|
||||
if (left == 0) {
|
||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||
}
|
||||
return n;
|
||||
};
|
||||
}
|
||||
|
||||
generator_cb deferred_generator() {
|
||||
return [](uint8_t *buf, size_t len, uint32_t *data_flags) {
|
||||
return NGHTTP2_ERR_DEFERRED;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename F, typename... T>
|
||||
std::shared_ptr<Defer<F, T...>> defer_shared(F &&f, T &&...t) {
|
||||
return std::make_shared<Defer<F, T...>>(std::forward<F>(f),
|
||||
std::forward<T>(t)...);
|
||||
}
|
||||
|
||||
generator_cb file_generator(const std::string &path) {
|
||||
auto fd = open(path.c_str(), O_RDONLY);
|
||||
if (fd == -1) {
|
||||
return generator_cb();
|
||||
}
|
||||
|
||||
return file_generator_from_fd(fd);
|
||||
}
|
||||
|
||||
generator_cb file_generator_from_fd(int fd) {
|
||||
auto d = defer_shared(close, fd);
|
||||
|
||||
return [fd, d](uint8_t *buf, size_t len,
|
||||
uint32_t *data_flags) -> generator_cb::result_type {
|
||||
ssize_t n;
|
||||
while ((n = read(fd, buf, len)) == -1 && errno == EINTR)
|
||||
;
|
||||
|
||||
if (n == -1) {
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||
}
|
||||
|
||||
return n;
|
||||
};
|
||||
}
|
||||
|
||||
bool check_path(const std::string &path) { return util::check_path(path); }
|
||||
|
||||
std::string percent_decode(const std::string &s) {
|
||||
return util::percent_decode(std::begin(s), std::end(s));
|
||||
}
|
||||
|
||||
std::string http_date(int64_t t) { return util::http_date(t); }
|
||||
|
||||
boost::system::error_code host_service_from_uri(boost::system::error_code &ec,
|
||||
std::string &scheme,
|
||||
std::string &host,
|
||||
std::string &service,
|
||||
const std::string &uri) {
|
||||
ec.clear();
|
||||
|
||||
http_parser_url u{};
|
||||
if (http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) != 0) {
|
||||
ec = make_error_code(boost::system::errc::invalid_argument);
|
||||
return ec;
|
||||
}
|
||||
|
||||
if ((u.field_set & (1 << UF_SCHEMA)) == 0 ||
|
||||
(u.field_set & (1 << UF_HOST)) == 0) {
|
||||
ec = make_error_code(boost::system::errc::invalid_argument);
|
||||
return ec;
|
||||
}
|
||||
|
||||
http2::copy_url_component(scheme, &u, UF_SCHEMA, uri.c_str());
|
||||
http2::copy_url_component(host, &u, UF_HOST, uri.c_str());
|
||||
|
||||
if (u.field_set & (1 << UF_PORT)) {
|
||||
http2::copy_url_component(service, &u, UF_PORT, uri.c_str());
|
||||
} else {
|
||||
service = scheme;
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
bool tls_h2_negotiated(ssl_socket &socket) {
|
||||
auto ssl = socket.native_handle();
|
||||
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len = 0;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
if (next_proto == nullptr) {
|
||||
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
if (next_proto == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return util::check_h2_is_selected(StringRef{next_proto, next_proto_len});
|
||||
}
|
||||
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_COMMON_H
|
||||
#define ASIO_COMMON_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
boost::system::error_code make_error_code(nghttp2_error ev);
|
||||
|
||||
boost::system::error_code make_error_code(nghttp2_asio_error ev);
|
||||
|
||||
generator_cb string_generator(std::string data);
|
||||
|
||||
// Returns generator_cb, which just returns NGHTTP2_ERR_DEFERRED
|
||||
generator_cb deferred_generator();
|
||||
|
||||
template <typename InputIt>
|
||||
void split_path(uri_ref &dst, InputIt first, InputIt last) {
|
||||
auto path_last = std::find(first, last, '?');
|
||||
InputIt query_first;
|
||||
if (path_last == last) {
|
||||
query_first = path_last = last;
|
||||
} else {
|
||||
query_first = path_last + 1;
|
||||
}
|
||||
dst.path = util::percent_decode(first, path_last);
|
||||
dst.raw_path.assign(first, path_last);
|
||||
dst.raw_query.assign(query_first, last);
|
||||
}
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using ssl_socket = boost::asio::ssl::stream<tcp::socket>;
|
||||
|
||||
bool tls_h2_negotiated(ssl_socket &socket);
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_COMMON_H
|
|
@ -1,107 +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.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// io_service_pool.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "asio_io_service_pool.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
io_service_pool::io_service_pool(std::size_t pool_size) : next_io_service_(0) {
|
||||
if (pool_size == 0) {
|
||||
throw std::runtime_error("io_service_pool size is 0");
|
||||
}
|
||||
|
||||
// Give all the io_services work to do so that their run() functions will not
|
||||
// exit until they are explicitly stopped.
|
||||
for (std::size_t i = 0; i < pool_size; ++i) {
|
||||
auto io_service = std::make_shared<boost::asio::io_service>();
|
||||
auto work = std::make_shared<boost::asio::io_service::work>(*io_service);
|
||||
io_services_.push_back(io_service);
|
||||
work_.push_back(work);
|
||||
}
|
||||
}
|
||||
|
||||
void io_service_pool::run(bool asynchronous) {
|
||||
// Create a pool of threads to run all of the io_services.
|
||||
for (std::size_t i = 0; i < io_services_.size(); ++i) {
|
||||
futures_.push_back(std::async(std::launch::async,
|
||||
(size_t(boost::asio::io_service::*)(void)) &
|
||||
boost::asio::io_service::run,
|
||||
io_services_[i]));
|
||||
}
|
||||
|
||||
if (!asynchronous) {
|
||||
join();
|
||||
}
|
||||
}
|
||||
|
||||
void io_service_pool::join() {
|
||||
// Wait for all threads in the pool to exit.
|
||||
for (auto &fut : futures_) {
|
||||
fut.get();
|
||||
}
|
||||
}
|
||||
|
||||
void io_service_pool::force_stop() {
|
||||
// Explicitly stop all io_services.
|
||||
for (auto &iosv : io_services_) {
|
||||
iosv->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void io_service_pool::stop() {
|
||||
// Destroy all work objects to signals end of work
|
||||
work_.clear();
|
||||
}
|
||||
|
||||
boost::asio::io_service &io_service_pool::get_io_service() {
|
||||
// Use a round-robin scheme to choose the next io_service to use.
|
||||
auto &io_service = *io_services_[next_io_service_];
|
||||
++next_io_service_;
|
||||
if (next_io_service_ == io_services_.size()) {
|
||||
next_io_service_ = 0;
|
||||
}
|
||||
return io_service;
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<boost::asio::io_service>> &
|
||||
io_service_pool::io_services() const {
|
||||
return io_services_;
|
||||
}
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
|
@ -1,98 +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.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// io_service_pool.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef ASIO_IO_SERVICE_POOL_H
|
||||
#define ASIO_IO_SERVICE_POOL_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
/// A pool of io_service objects.
|
||||
class io_service_pool : private boost::noncopyable {
|
||||
public:
|
||||
/// Construct the io_service pool.
|
||||
explicit io_service_pool(std::size_t pool_size);
|
||||
|
||||
/// Run all io_service objects in the pool.
|
||||
void run(bool asynchronous = false);
|
||||
|
||||
/// Stop all io_service objects in the pool.
|
||||
void force_stop();
|
||||
|
||||
/// Destroy all work objects to signals end of work
|
||||
void stop();
|
||||
|
||||
/// Join on all io_service objects in the pool.
|
||||
void join();
|
||||
|
||||
/// Get an io_service to use.
|
||||
boost::asio::io_service &get_io_service();
|
||||
|
||||
/// Get access to all io_service objects.
|
||||
const std::vector<std::shared_ptr<boost::asio::io_service>> &
|
||||
io_services() const;
|
||||
|
||||
private:
|
||||
/// The pool of io_services.
|
||||
std::vector<std::shared_ptr<boost::asio::io_service>> io_services_;
|
||||
|
||||
/// The work that keeps the io_services running.
|
||||
std::vector<std::shared_ptr<boost::asio::io_service::work>> work_;
|
||||
|
||||
/// The next io_service to use for a connection.
|
||||
std::size_t next_io_service_;
|
||||
|
||||
/// Futures to all the io_service objects
|
||||
std::vector<std::future<std::size_t>> futures_;
|
||||
};
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_IO_SERVICE_POOL_H
|
|
@ -1,214 +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.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// server.cpp
|
||||
// ~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include "asio_server.h"
|
||||
|
||||
#include "asio_server_connection.h"
|
||||
#include "asio_common.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
server::server(std::size_t io_service_pool_size,
|
||||
const boost::posix_time::time_duration &tls_handshake_timeout,
|
||||
const boost::posix_time::time_duration &read_timeout)
|
||||
: io_service_pool_(io_service_pool_size),
|
||||
tls_handshake_timeout_(tls_handshake_timeout),
|
||||
read_timeout_(read_timeout) {}
|
||||
|
||||
boost::system::error_code
|
||||
server::listen_and_serve(boost::system::error_code &ec,
|
||||
boost::asio::ssl::context *tls_context,
|
||||
const std::string &address, const std::string &port,
|
||||
int backlog, serve_mux &mux, bool asynchronous) {
|
||||
ec.clear();
|
||||
|
||||
if (bind_and_listen(ec, address, port, backlog)) {
|
||||
return ec;
|
||||
}
|
||||
|
||||
for (auto &acceptor : acceptors_) {
|
||||
if (tls_context) {
|
||||
start_accept(*tls_context, acceptor, mux);
|
||||
} else {
|
||||
start_accept(acceptor, mux);
|
||||
}
|
||||
}
|
||||
|
||||
io_service_pool_.run(asynchronous);
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
boost::system::error_code server::bind_and_listen(boost::system::error_code &ec,
|
||||
const std::string &address,
|
||||
const std::string &port,
|
||||
int backlog) {
|
||||
// Open the acceptor with the option to reuse the address (i.e.
|
||||
// SO_REUSEADDR).
|
||||
tcp::resolver resolver(io_service_pool_.get_io_service());
|
||||
tcp::resolver::query query(address, port);
|
||||
auto it = resolver.resolve(query, ec);
|
||||
if (ec) {
|
||||
return ec;
|
||||
}
|
||||
|
||||
for (; it != tcp::resolver::iterator(); ++it) {
|
||||
tcp::endpoint endpoint = *it;
|
||||
auto acceptor = tcp::acceptor(io_service_pool_.get_io_service());
|
||||
|
||||
if (acceptor.open(endpoint.protocol(), ec)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
acceptor.set_option(tcp::acceptor::reuse_address(true));
|
||||
|
||||
if (acceptor.bind(endpoint, ec)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (acceptor.listen(
|
||||
backlog == -1 ? boost::asio::socket_base::max_connections : backlog,
|
||||
ec)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
acceptors_.push_back(std::move(acceptor));
|
||||
}
|
||||
|
||||
if (acceptors_.empty()) {
|
||||
return ec;
|
||||
}
|
||||
|
||||
// ec could have some errors since we may have failed to bind some
|
||||
// interfaces.
|
||||
ec.clear();
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
void server::start_accept(boost::asio::ssl::context &tls_context,
|
||||
tcp::acceptor &acceptor, serve_mux &mux) {
|
||||
|
||||
if (!acceptor.is_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto new_connection = std::make_shared<connection<ssl_socket>>(
|
||||
mux, tls_handshake_timeout_, read_timeout_,
|
||||
io_service_pool_.get_io_service(), tls_context);
|
||||
|
||||
acceptor.async_accept(
|
||||
new_connection->socket().lowest_layer(),
|
||||
[this, &tls_context, &acceptor, &mux,
|
||||
new_connection](const boost::system::error_code &e) {
|
||||
if (!e) {
|
||||
new_connection->socket().lowest_layer().set_option(
|
||||
tcp::no_delay(true));
|
||||
new_connection->start_tls_handshake_deadline();
|
||||
new_connection->socket().async_handshake(
|
||||
boost::asio::ssl::stream_base::server,
|
||||
[new_connection](const boost::system::error_code &e) {
|
||||
if (e) {
|
||||
new_connection->stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tls_h2_negotiated(new_connection->socket())) {
|
||||
new_connection->stop();
|
||||
return;
|
||||
}
|
||||
|
||||
new_connection->start();
|
||||
});
|
||||
}
|
||||
|
||||
start_accept(tls_context, acceptor, mux);
|
||||
});
|
||||
}
|
||||
|
||||
void server::start_accept(tcp::acceptor &acceptor, serve_mux &mux) {
|
||||
|
||||
if (!acceptor.is_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto new_connection = std::make_shared<connection<tcp::socket>>(
|
||||
mux, tls_handshake_timeout_, read_timeout_,
|
||||
io_service_pool_.get_io_service());
|
||||
|
||||
acceptor.async_accept(
|
||||
new_connection->socket(), [this, &acceptor, &mux, new_connection](
|
||||
const boost::system::error_code &e) {
|
||||
if (!e) {
|
||||
new_connection->socket().set_option(tcp::no_delay(true));
|
||||
new_connection->start_read_deadline();
|
||||
new_connection->start();
|
||||
}
|
||||
if (acceptor.is_open()) {
|
||||
start_accept(acceptor, mux);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void server::stop() {
|
||||
for (auto &acceptor : acceptors_) {
|
||||
acceptor.close();
|
||||
}
|
||||
io_service_pool_.stop();
|
||||
}
|
||||
|
||||
void server::join() { io_service_pool_.join(); }
|
||||
|
||||
const std::vector<std::shared_ptr<boost::asio::io_service>> &
|
||||
server::io_services() const {
|
||||
return io_service_pool_.io_services();
|
||||
}
|
||||
|
||||
const std::vector<int> server::ports() const {
|
||||
auto ports = std::vector<int>(acceptors_.size());
|
||||
auto index = 0;
|
||||
for (const auto &acceptor : acceptors_) {
|
||||
ports[index++] = acceptor.local_endpoint().port();
|
||||
}
|
||||
return ports;
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,117 +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.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// server.hpp
|
||||
// ~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef ASIO_SERVER_H
|
||||
#define ASIO_SERVER_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
#include "asio_io_service_pool.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
class serve_mux;
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using ssl_socket = boost::asio::ssl::stream<tcp::socket>;
|
||||
|
||||
class server : private boost::noncopyable {
|
||||
public:
|
||||
explicit server(std::size_t io_service_pool_size,
|
||||
const boost::posix_time::time_duration &tls_handshake_timeout,
|
||||
const boost::posix_time::time_duration &read_timeout);
|
||||
|
||||
boost::system::error_code
|
||||
listen_and_serve(boost::system::error_code &ec,
|
||||
boost::asio::ssl::context *tls_context,
|
||||
const std::string &address, const std::string &port,
|
||||
int backlog, serve_mux &mux, bool asynchronous = false);
|
||||
void join();
|
||||
void stop();
|
||||
|
||||
/// Get access to all io_service objects.
|
||||
const std::vector<std::shared_ptr<boost::asio::io_service>> &
|
||||
io_services() const;
|
||||
|
||||
/// Returns a vector with all the acceptors ports in use.
|
||||
const std::vector<int> ports() const;
|
||||
|
||||
private:
|
||||
/// Initiate an asynchronous accept operation.
|
||||
void start_accept(tcp::acceptor &acceptor, serve_mux &mux);
|
||||
/// Same as above but with tls_context
|
||||
void start_accept(boost::asio::ssl::context &tls_context,
|
||||
tcp::acceptor &acceptor, serve_mux &mux);
|
||||
|
||||
/// Resolves address and bind socket to the resolved addresses.
|
||||
boost::system::error_code bind_and_listen(boost::system::error_code &ec,
|
||||
const std::string &address,
|
||||
const std::string &port,
|
||||
int backlog);
|
||||
|
||||
/// The pool of io_service objects used to perform asynchronous
|
||||
/// operations.
|
||||
io_service_pool io_service_pool_;
|
||||
|
||||
/// Acceptor used to listen for incoming connections.
|
||||
std::vector<tcp::acceptor> acceptors_;
|
||||
|
||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx_;
|
||||
|
||||
boost::posix_time::time_duration tls_handshake_timeout_;
|
||||
boost::posix_time::time_duration read_timeout_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_SERVER_H
|
|
@ -1,253 +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.
|
||||
*/
|
||||
// We wrote this code based on the original code which has the
|
||||
// following license:
|
||||
//
|
||||
// connection.hpp
|
||||
// ~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef ASIO_SERVER_CONNECTION_H
|
||||
#define ASIO_SERVER_CONNECTION_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/array.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
#include "asio_server_http2_handler.h"
|
||||
#include "asio_server_serve_mux.h"
|
||||
#include "util.h"
|
||||
#include "template.h"
|
||||
|
||||
#if BOOST_VERSION >= 107000
|
||||
# define GET_IO_SERVICE(s) \
|
||||
((boost::asio::io_context &)(s).get_executor().context())
|
||||
#else
|
||||
# define GET_IO_SERVICE(s) ((s).get_io_service())
|
||||
#endif
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
template <typename socket_type>
|
||||
class connection : public std::enable_shared_from_this<connection<socket_type>>,
|
||||
private boost::noncopyable {
|
||||
public:
|
||||
/// Construct a connection with the given io_service.
|
||||
template <typename... SocketArgs>
|
||||
explicit connection(
|
||||
serve_mux &mux,
|
||||
const boost::posix_time::time_duration &tls_handshake_timeout,
|
||||
const boost::posix_time::time_duration &read_timeout,
|
||||
SocketArgs &&...args)
|
||||
: socket_(std::forward<SocketArgs>(args)...),
|
||||
mux_(mux),
|
||||
deadline_(GET_IO_SERVICE(socket_)),
|
||||
tls_handshake_timeout_(tls_handshake_timeout),
|
||||
read_timeout_(read_timeout),
|
||||
writing_(false),
|
||||
stopped_(false) {}
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start() {
|
||||
boost::system::error_code ec;
|
||||
|
||||
handler_ = std::make_shared<http2_handler>(
|
||||
GET_IO_SERVICE(socket_), socket_.lowest_layer().remote_endpoint(ec),
|
||||
[this]() { do_write(); }, mux_);
|
||||
if (handler_->start() != 0) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
do_read();
|
||||
}
|
||||
|
||||
socket_type &socket() { return socket_; }
|
||||
|
||||
void start_tls_handshake_deadline() {
|
||||
deadline_.expires_from_now(tls_handshake_timeout_);
|
||||
deadline_.async_wait(
|
||||
std::bind(&connection::handle_deadline, this->shared_from_this()));
|
||||
}
|
||||
|
||||
void start_read_deadline() {
|
||||
deadline_.expires_from_now(read_timeout_);
|
||||
deadline_.async_wait(
|
||||
std::bind(&connection::handle_deadline, this->shared_from_this()));
|
||||
}
|
||||
|
||||
void handle_deadline() {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (deadline_.expires_at() <=
|
||||
boost::asio::deadline_timer::traits_type::now()) {
|
||||
stop();
|
||||
deadline_.expires_at(boost::posix_time::pos_infin);
|
||||
return;
|
||||
}
|
||||
|
||||
deadline_.async_wait(
|
||||
std::bind(&connection::handle_deadline, this->shared_from_this()));
|
||||
}
|
||||
|
||||
void do_read() {
|
||||
auto self = this->shared_from_this();
|
||||
|
||||
deadline_.expires_from_now(read_timeout_);
|
||||
|
||||
socket_.async_read_some(
|
||||
boost::asio::buffer(buffer_),
|
||||
[this, self](const boost::system::error_code &e,
|
||||
std::size_t bytes_transferred) {
|
||||
if (e) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler_->on_read(buffer_, bytes_transferred) != 0) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
do_write();
|
||||
|
||||
if (!writing_ && handler_->should_stop()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
do_read();
|
||||
|
||||
// If an error occurs then no new asynchronous operations are
|
||||
// started. This means that all shared_ptr references to the
|
||||
// connection object will disappear and the object will be
|
||||
// destroyed automatically after this handler returns. The
|
||||
// connection class's destructor closes the socket.
|
||||
});
|
||||
}
|
||||
|
||||
void do_write() {
|
||||
auto self = this->shared_from_this();
|
||||
|
||||
if (writing_) {
|
||||
return;
|
||||
}
|
||||
|
||||
int rv;
|
||||
std::size_t nwrite;
|
||||
|
||||
rv = handler_->on_write(outbuf_, nwrite);
|
||||
|
||||
if (rv != 0) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (nwrite == 0) {
|
||||
if (handler_->should_stop()) {
|
||||
stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
writing_ = true;
|
||||
|
||||
// Reset read deadline here, because normally client is sending
|
||||
// something, it does not expect timeout while doing it.
|
||||
deadline_.expires_from_now(read_timeout_);
|
||||
|
||||
boost::asio::async_write(
|
||||
socket_, boost::asio::buffer(outbuf_, nwrite),
|
||||
[this, self](const boost::system::error_code &e, std::size_t) {
|
||||
if (e) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
writing_ = false;
|
||||
|
||||
do_write();
|
||||
});
|
||||
|
||||
// No new asynchronous operations are started. This means that all
|
||||
// shared_ptr references to the connection object will disappear and
|
||||
// the object will be destroyed automatically after this handler
|
||||
// returns. The connection class's destructor closes the socket.
|
||||
}
|
||||
|
||||
void stop() {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
stopped_ = true;
|
||||
boost::system::error_code ignored_ec;
|
||||
socket_.lowest_layer().close(ignored_ec);
|
||||
deadline_.cancel();
|
||||
}
|
||||
|
||||
private:
|
||||
socket_type socket_;
|
||||
|
||||
serve_mux &mux_;
|
||||
|
||||
std::shared_ptr<http2_handler> handler_;
|
||||
|
||||
/// Buffer for incoming data.
|
||||
boost::array<uint8_t, 8_k> buffer_;
|
||||
|
||||
boost::array<uint8_t, 64_k> outbuf_;
|
||||
|
||||
boost::asio::deadline_timer deadline_;
|
||||
boost::posix_time::time_duration tls_handshake_timeout_;
|
||||
boost::posix_time::time_duration read_timeout_;
|
||||
|
||||
bool writing_;
|
||||
bool stopped_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_SERVER_CONNECTION_H
|
|
@ -1,99 +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 "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
#include "asio_server_http2_impl.h"
|
||||
#include "asio_server.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
http2::http2() : impl_(std::make_unique<http2_impl>()) {}
|
||||
|
||||
http2::~http2() {}
|
||||
|
||||
http2::http2(http2 &&other) noexcept : impl_(std::move(other.impl_)) {}
|
||||
|
||||
http2 &http2::operator=(http2 &&other) noexcept {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
impl_ = std::move(other.impl_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
boost::system::error_code http2::listen_and_serve(boost::system::error_code &ec,
|
||||
const std::string &address,
|
||||
const std::string &port,
|
||||
bool asynchronous) {
|
||||
return impl_->listen_and_serve(ec, nullptr, address, port, asynchronous);
|
||||
}
|
||||
|
||||
boost::system::error_code http2::listen_and_serve(
|
||||
boost::system::error_code &ec, boost::asio::ssl::context &tls_context,
|
||||
const std::string &address, const std::string &port, bool asynchronous) {
|
||||
return impl_->listen_and_serve(ec, &tls_context, address, port, asynchronous);
|
||||
}
|
||||
|
||||
void http2::num_threads(size_t num_threads) { impl_->num_threads(num_threads); }
|
||||
|
||||
void http2::backlog(int backlog) { impl_->backlog(backlog); }
|
||||
|
||||
void http2::tls_handshake_timeout(const boost::posix_time::time_duration &t) {
|
||||
impl_->tls_handshake_timeout(t);
|
||||
}
|
||||
|
||||
void http2::read_timeout(const boost::posix_time::time_duration &t) {
|
||||
impl_->read_timeout(t);
|
||||
}
|
||||
|
||||
bool http2::handle(std::string pattern, request_cb cb) {
|
||||
return impl_->handle(std::move(pattern), std::move(cb));
|
||||
}
|
||||
|
||||
void http2::stop() { impl_->stop(); }
|
||||
|
||||
void http2::join() { return impl_->join(); }
|
||||
|
||||
const std::vector<std::shared_ptr<boost::asio::io_service>> &
|
||||
http2::io_services() const {
|
||||
return impl_->io_services();
|
||||
}
|
||||
|
||||
std::vector<int> http2::ports() const { return impl_->ports(); }
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
|
@ -1,497 +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 "asio_server_http2_handler.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "asio_common.h"
|
||||
#include "asio_server_serve_mux.h"
|
||||
#include "asio_server_stream.h"
|
||||
#include "asio_server_request_impl.h"
|
||||
#include "asio_server_response_impl.h"
|
||||
#include "http2.h"
|
||||
#include "util.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
namespace {
|
||||
int stream_error(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code) {
|
||||
return nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, stream_id,
|
||||
error_code);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_begin_headers_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, void *user_data) {
|
||||
auto handler = static_cast<http2_handler *>(user_data);
|
||||
|
||||
if (frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
handler->create_stream(frame->hd.stream_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen, uint8_t flags,
|
||||
void *user_data) {
|
||||
auto handler = static_cast<http2_handler *>(user_data);
|
||||
auto stream_id = frame->hd.stream_id;
|
||||
|
||||
if (frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto strm = handler->find_stream(stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto &req = strm->request().impl();
|
||||
auto &uref = req.uri();
|
||||
|
||||
switch (nghttp2::http2::lookup_token(name, namelen)) {
|
||||
case nghttp2::http2::HD__METHOD:
|
||||
req.method(std::string(value, value + valuelen));
|
||||
break;
|
||||
case nghttp2::http2::HD__SCHEME:
|
||||
uref.scheme.assign(value, value + valuelen);
|
||||
break;
|
||||
case nghttp2::http2::HD__AUTHORITY:
|
||||
uref.host.assign(value, value + valuelen);
|
||||
break;
|
||||
case nghttp2::http2::HD__PATH:
|
||||
split_path(uref, value, value + valuelen);
|
||||
break;
|
||||
case nghttp2::http2::HD_HOST:
|
||||
if (uref.host.empty()) {
|
||||
uref.host.assign(value, value + valuelen);
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
if (req.header_buffer_size() + namelen + valuelen > 64_k) {
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
break;
|
||||
}
|
||||
req.update_header_buffer_size(namelen + valuelen);
|
||||
|
||||
req.header().emplace(std::string(name, name + namelen),
|
||||
header_value{std::string(value, value + valuelen),
|
||||
(flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0});
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
auto handler = static_cast<http2_handler *>(user_data);
|
||||
auto strm = handler->find_stream(frame->hd.stream_id);
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
if (!strm) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
strm->request().impl().call_on_data(nullptr, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
case NGHTTP2_HEADERS: {
|
||||
if (!strm || frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto &req = strm->request().impl();
|
||||
req.remote_endpoint(handler->remote_endpoint());
|
||||
|
||||
handler->call_on_request(*strm);
|
||||
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
strm->request().impl().call_on_data(nullptr, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *data,
|
||||
size_t len, void *user_data) {
|
||||
auto handler = static_cast<http2_handler *>(user_data);
|
||||
auto strm = handler->find_stream(stream_id);
|
||||
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
strm->request().impl().call_on_data(data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code, void *user_data) {
|
||||
auto handler = static_cast<http2_handler *>(user_data);
|
||||
|
||||
auto strm = handler->find_stream(stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
strm->response().impl().call_on_close(error_code);
|
||||
|
||||
handler->close_stream(stream_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
auto handler = static_cast<http2_handler *>(user_data);
|
||||
|
||||
if (frame->hd.type != NGHTTP2_PUSH_PROMISE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto strm = handler->find_stream(frame->push_promise.promised_stream_id);
|
||||
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto &res = strm->response().impl();
|
||||
res.push_promise_sent();
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_frame_not_send_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, int lib_error_code,
|
||||
void *user_data) {
|
||||
if (frame->hd.type != NGHTTP2_HEADERS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Issue RST_STREAM so that stream does not hang around.
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
http2_handler::http2_handler(boost::asio::io_service &io_service,
|
||||
boost::asio::ip::tcp::endpoint ep,
|
||||
connection_write writefun, serve_mux &mux)
|
||||
: writefun_(writefun),
|
||||
mux_(mux),
|
||||
io_service_(io_service),
|
||||
remote_ep_(ep),
|
||||
session_(nullptr),
|
||||
buf_(nullptr),
|
||||
buflen_(0),
|
||||
inside_callback_(false),
|
||||
write_signaled_(false),
|
||||
tstamp_cached_(time(nullptr)),
|
||||
formatted_date_(util::http_date(tstamp_cached_)) {}
|
||||
|
||||
http2_handler::~http2_handler() {
|
||||
for (auto &p : streams_) {
|
||||
auto &strm = p.second;
|
||||
strm->response().impl().call_on_close(NGHTTP2_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
nghttp2_session_del(session_);
|
||||
}
|
||||
|
||||
const std::string &http2_handler::http_date() {
|
||||
auto t = time(nullptr);
|
||||
if (t != tstamp_cached_) {
|
||||
tstamp_cached_ = t;
|
||||
formatted_date_ = util::http_date(t);
|
||||
}
|
||||
return formatted_date_;
|
||||
}
|
||||
|
||||
int http2_handler::start() {
|
||||
int rv;
|
||||
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
rv = nghttp2_session_callbacks_new(&callbacks);
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto cb_del = defer(nghttp2_session_callbacks_del, callbacks);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
callbacks, on_begin_headers_callback);
|
||||
nghttp2_session_callbacks_set_on_header_callback(callbacks,
|
||||
on_header_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
|
||||
on_frame_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
callbacks, on_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, on_stream_close_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
|
||||
on_frame_send_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||
callbacks, on_frame_not_send_callback);
|
||||
|
||||
rv = nghttp2_session_server_new(&session_, callbacks, this);
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
nghttp2_settings_entry ent{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100};
|
||||
nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, &ent, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream *http2_handler::create_stream(int32_t stream_id) {
|
||||
auto p =
|
||||
streams_.emplace(stream_id, std::make_unique<stream>(this, stream_id));
|
||||
assert(p.second);
|
||||
return (*p.first).second.get();
|
||||
}
|
||||
|
||||
void http2_handler::close_stream(int32_t stream_id) {
|
||||
streams_.erase(stream_id);
|
||||
}
|
||||
|
||||
stream *http2_handler::find_stream(int32_t stream_id) {
|
||||
auto i = streams_.find(stream_id);
|
||||
if (i == std::end(streams_)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (*i).second.get();
|
||||
}
|
||||
|
||||
void http2_handler::call_on_request(stream &strm) {
|
||||
auto cb = mux_.handler(strm.request().impl());
|
||||
cb(strm.request(), strm.response());
|
||||
}
|
||||
|
||||
bool http2_handler::should_stop() const {
|
||||
return !nghttp2_session_want_read(session_) &&
|
||||
!nghttp2_session_want_write(session_);
|
||||
}
|
||||
|
||||
int http2_handler::start_response(stream &strm) {
|
||||
int rv;
|
||||
|
||||
auto &res = strm.response().impl();
|
||||
auto &header = res.header();
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(2 + header.size());
|
||||
auto status = util::utos(res.status_code());
|
||||
auto date = http_date();
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":status", status));
|
||||
nva.push_back(nghttp2::http2::make_nv_ls("date", date));
|
||||
for (auto &hd : header) {
|
||||
nva.push_back(nghttp2::http2::make_nv(hd.first, hd.second.value,
|
||||
hd.second.sensitive));
|
||||
}
|
||||
|
||||
nghttp2_data_provider *prd_ptr = nullptr, prd;
|
||||
auto &req = strm.request().impl();
|
||||
if (::nghttp2::http2::expect_response_body(req.method(), res.status_code())) {
|
||||
prd.source.ptr = &strm;
|
||||
prd.read_callback = [](nghttp2_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t length, uint32_t *data_flags,
|
||||
nghttp2_data_source *source,
|
||||
void *user_data) -> ssize_t {
|
||||
auto &strm = *static_cast<stream *>(source->ptr);
|
||||
return strm.response().impl().call_read(buf, length, data_flags);
|
||||
};
|
||||
prd_ptr = &prd;
|
||||
}
|
||||
rv = nghttp2_submit_response(session_, strm.get_stream_id(), nva.data(),
|
||||
nva.size(), prd_ptr);
|
||||
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
signal_write();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http2_handler::submit_trailer(stream &strm, header_map h) {
|
||||
int rv;
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(h.size());
|
||||
for (auto &hd : h) {
|
||||
nva.push_back(nghttp2::http2::make_nv(hd.first, hd.second.value,
|
||||
hd.second.sensitive));
|
||||
}
|
||||
|
||||
rv = nghttp2_submit_trailer(session_, strm.get_stream_id(), nva.data(),
|
||||
nva.size());
|
||||
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
signal_write();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void http2_handler::enter_callback() {
|
||||
assert(!inside_callback_);
|
||||
inside_callback_ = true;
|
||||
}
|
||||
|
||||
void http2_handler::leave_callback() {
|
||||
assert(inside_callback_);
|
||||
inside_callback_ = false;
|
||||
}
|
||||
|
||||
void http2_handler::stream_error(int32_t stream_id, uint32_t error_code) {
|
||||
::nghttp2::asio_http2::server::stream_error(session_, stream_id, error_code);
|
||||
signal_write();
|
||||
}
|
||||
|
||||
void http2_handler::signal_write() {
|
||||
if (!inside_callback_ && !write_signaled_) {
|
||||
write_signaled_ = true;
|
||||
auto self = shared_from_this();
|
||||
io_service_.post([self]() { self->initiate_write(); });
|
||||
}
|
||||
}
|
||||
|
||||
void http2_handler::initiate_write() {
|
||||
write_signaled_ = false;
|
||||
writefun_();
|
||||
}
|
||||
|
||||
void http2_handler::resume(stream &strm) {
|
||||
nghttp2_session_resume_data(session_, strm.get_stream_id());
|
||||
signal_write();
|
||||
}
|
||||
|
||||
response *http2_handler::push_promise(boost::system::error_code &ec,
|
||||
stream &strm, std::string method,
|
||||
std::string raw_path_query,
|
||||
header_map h) {
|
||||
int rv;
|
||||
|
||||
ec.clear();
|
||||
|
||||
auto &req = strm.request().impl();
|
||||
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(4 + h.size());
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":method", method));
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":scheme", req.uri().scheme));
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":authority", req.uri().host));
|
||||
nva.push_back(nghttp2::http2::make_nv_ls(":path", raw_path_query));
|
||||
|
||||
for (auto &hd : h) {
|
||||
nva.push_back(nghttp2::http2::make_nv(hd.first, hd.second.value,
|
||||
hd.second.sensitive));
|
||||
}
|
||||
|
||||
rv = nghttp2_submit_push_promise(session_, NGHTTP2_FLAG_NONE,
|
||||
strm.get_stream_id(), nva.data(), nva.size(),
|
||||
nullptr);
|
||||
|
||||
if (rv < 0) {
|
||||
ec = make_error_code(static_cast<nghttp2_error>(rv));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto promised_strm = create_stream(rv);
|
||||
auto &promised_req = promised_strm->request().impl();
|
||||
promised_req.header(std::move(h));
|
||||
promised_req.method(std::move(method));
|
||||
|
||||
auto &uref = promised_req.uri();
|
||||
uref.scheme = req.uri().scheme;
|
||||
uref.host = req.uri().host;
|
||||
split_path(uref, std::begin(raw_path_query), std::end(raw_path_query));
|
||||
|
||||
auto &promised_res = promised_strm->response().impl();
|
||||
promised_res.pushed(true);
|
||||
|
||||
signal_write();
|
||||
|
||||
return &promised_strm->response();
|
||||
}
|
||||
|
||||
boost::asio::io_service &http2_handler::io_service() { return io_service_; }
|
||||
|
||||
const boost::asio::ip::tcp::endpoint &http2_handler::remote_endpoint() {
|
||||
return remote_ep_;
|
||||
}
|
||||
|
||||
callback_guard::callback_guard(http2_handler &h) : handler(h) {
|
||||
handler.enter_callback();
|
||||
}
|
||||
|
||||
callback_guard::~callback_guard() { handler.leave_callback(); }
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
|
@ -1,174 +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 ASIO_SERVER_HTTP2_HANDLER_H
|
||||
#define ASIO_SERVER_HTTP2_HANDLER_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include <boost/array.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
class http2_handler;
|
||||
class stream;
|
||||
class serve_mux;
|
||||
|
||||
struct callback_guard {
|
||||
callback_guard(http2_handler &h);
|
||||
~callback_guard();
|
||||
http2_handler &handler;
|
||||
};
|
||||
|
||||
using connection_write = std::function<void(void)>;
|
||||
|
||||
class http2_handler : public std::enable_shared_from_this<http2_handler> {
|
||||
public:
|
||||
http2_handler(boost::asio::io_service &io_service,
|
||||
boost::asio::ip::tcp::endpoint ep, connection_write writefun,
|
||||
serve_mux &mux);
|
||||
|
||||
~http2_handler();
|
||||
|
||||
int start();
|
||||
|
||||
stream *create_stream(int32_t stream_id);
|
||||
void close_stream(int32_t stream_id);
|
||||
stream *find_stream(int32_t stream_id);
|
||||
|
||||
void call_on_request(stream &s);
|
||||
|
||||
bool should_stop() const;
|
||||
|
||||
int start_response(stream &s);
|
||||
|
||||
int submit_trailer(stream &s, header_map h);
|
||||
|
||||
void stream_error(int32_t stream_id, uint32_t error_code);
|
||||
|
||||
void initiate_write();
|
||||
|
||||
void enter_callback();
|
||||
void leave_callback();
|
||||
|
||||
void resume(stream &s);
|
||||
|
||||
response *push_promise(boost::system::error_code &ec, stream &s,
|
||||
std::string method, std::string raw_path_query,
|
||||
header_map h);
|
||||
|
||||
void signal_write();
|
||||
|
||||
boost::asio::io_service &io_service();
|
||||
|
||||
const boost::asio::ip::tcp::endpoint &remote_endpoint();
|
||||
|
||||
const std::string &http_date();
|
||||
|
||||
template <size_t N>
|
||||
int on_read(const boost::array<uint8_t, N> &buffer, std::size_t len) {
|
||||
callback_guard cg(*this);
|
||||
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, buffer.data(), len);
|
||||
|
||||
if (rv < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
int on_write(boost::array<uint8_t, N> &buffer, std::size_t &len) {
|
||||
callback_guard cg(*this);
|
||||
|
||||
len = 0;
|
||||
|
||||
if (buf_) {
|
||||
std::copy_n(buf_, buflen_, std::begin(buffer));
|
||||
|
||||
len += buflen_;
|
||||
|
||||
buf_ = nullptr;
|
||||
buflen_ = 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
const uint8_t *data;
|
||||
auto nread = nghttp2_session_mem_send(session_, &data);
|
||||
if (nread < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nread == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (len + nread > buffer.size()) {
|
||||
buf_ = data;
|
||||
buflen_ = nread;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
std::copy_n(data, nread, std::begin(buffer) + len);
|
||||
|
||||
len += nread;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<int32_t, std::shared_ptr<stream>> streams_;
|
||||
connection_write writefun_;
|
||||
serve_mux &mux_;
|
||||
boost::asio::io_service &io_service_;
|
||||
boost::asio::ip::tcp::endpoint remote_ep_;
|
||||
nghttp2_session *session_;
|
||||
const uint8_t *buf_;
|
||||
std::size_t buflen_;
|
||||
bool inside_callback_;
|
||||
// true if we have pending on_write call. This avoids repeated call
|
||||
// of io_service::post.
|
||||
bool write_signaled_;
|
||||
time_t tstamp_cached_;
|
||||
std::string formatted_date_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_SERVER_HTTP2_HANDLER_H
|
|
@ -1,87 +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 "asio_server_http2_impl.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "asio_server.h"
|
||||
#include "util.h"
|
||||
#include "tls.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
http2_impl::http2_impl()
|
||||
: num_threads_(1),
|
||||
backlog_(-1),
|
||||
tls_handshake_timeout_(boost::posix_time::seconds(60)),
|
||||
read_timeout_(boost::posix_time::seconds(60)) {}
|
||||
|
||||
boost::system::error_code http2_impl::listen_and_serve(
|
||||
boost::system::error_code &ec, boost::asio::ssl::context *tls_context,
|
||||
const std::string &address, const std::string &port, bool asynchronous) {
|
||||
server_.reset(
|
||||
new server(num_threads_, tls_handshake_timeout_, read_timeout_));
|
||||
return server_->listen_and_serve(ec, tls_context, address, port, backlog_,
|
||||
mux_, asynchronous);
|
||||
}
|
||||
|
||||
void http2_impl::num_threads(size_t num_threads) { num_threads_ = num_threads; }
|
||||
|
||||
void http2_impl::backlog(int backlog) { backlog_ = backlog; }
|
||||
|
||||
void http2_impl::tls_handshake_timeout(
|
||||
const boost::posix_time::time_duration &t) {
|
||||
tls_handshake_timeout_ = t;
|
||||
}
|
||||
|
||||
void http2_impl::read_timeout(const boost::posix_time::time_duration &t) {
|
||||
read_timeout_ = t;
|
||||
}
|
||||
|
||||
bool http2_impl::handle(std::string pattern, request_cb cb) {
|
||||
return mux_.handle(std::move(pattern), std::move(cb));
|
||||
}
|
||||
|
||||
void http2_impl::stop() { return server_->stop(); }
|
||||
|
||||
void http2_impl::join() { return server_->join(); }
|
||||
|
||||
const std::vector<std::shared_ptr<boost::asio::io_service>> &
|
||||
http2_impl::io_services() const {
|
||||
return server_->io_services();
|
||||
}
|
||||
|
||||
std::vector<int> http2_impl::ports() const { return server_->ports(); }
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
|
@ -1,74 +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 ASIO_SERVER_HTTP2_IMPL_H
|
||||
#define ASIO_SERVER_HTTP2_IMPL_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
#include "asio_server_serve_mux.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
class server;
|
||||
|
||||
class http2_impl {
|
||||
public:
|
||||
http2_impl();
|
||||
boost::system::error_code listen_and_serve(
|
||||
boost::system::error_code &ec, boost::asio::ssl::context *tls_context,
|
||||
const std::string &address, const std::string &port, bool asynchronous);
|
||||
void num_threads(size_t num_threads);
|
||||
void backlog(int backlog);
|
||||
void tls_handshake_timeout(const boost::posix_time::time_duration &t);
|
||||
void read_timeout(const boost::posix_time::time_duration &t);
|
||||
bool handle(std::string pattern, request_cb cb);
|
||||
void stop();
|
||||
void join();
|
||||
const std::vector<std::shared_ptr<boost::asio::io_service>> &
|
||||
io_services() const;
|
||||
std::vector<int> ports() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<server> server_;
|
||||
std::size_t num_threads_;
|
||||
int backlog_;
|
||||
serve_mux mux_;
|
||||
boost::posix_time::time_duration tls_handshake_timeout_;
|
||||
boost::posix_time::time_duration read_timeout_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_SERVER_HTTP2_IMPL_H
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
#include "asio_server_request_impl.h"
|
||||
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
request::request() : impl_(std::make_unique<request_impl>()) {}
|
||||
|
||||
request::~request() {}
|
||||
|
||||
const header_map &request::header() const { return impl_->header(); }
|
||||
|
||||
const std::string &request::method() const { return impl_->method(); }
|
||||
|
||||
const uri_ref &request::uri() const { return impl_->uri(); }
|
||||
|
||||
void request::on_data(data_cb cb) const {
|
||||
return impl_->on_data(std::move(cb));
|
||||
}
|
||||
|
||||
request_impl &request::impl() const { return *impl_; }
|
||||
|
||||
const boost::asio::ip::tcp::endpoint &request::remote_endpoint() const {
|
||||
return impl_->remote_endpoint();
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_server_request_handler.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "http2.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
namespace {
|
||||
std::string create_html(int status_code) {
|
||||
BlockAllocator balloc(1024, 1024);
|
||||
std::string res;
|
||||
res.reserve(512);
|
||||
auto status_string = ::nghttp2::http2::stringify_status(balloc, status_code);
|
||||
auto reason_phrase = ::nghttp2::http2::get_reason_phrase(status_code);
|
||||
res += R"(<!DOCTYPE html><html lang="en"><title>)";
|
||||
res += status_string;
|
||||
res += ' ';
|
||||
res += reason_phrase;
|
||||
res += "</title><body><h1>";
|
||||
res += status_string;
|
||||
res += ' ';
|
||||
res += reason_phrase;
|
||||
res += "</h1></body></html>";
|
||||
return res;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
request_cb redirect_handler(int status_code, std::string uri) {
|
||||
return [status_code, uri](const request &req, const response &res) {
|
||||
header_map h;
|
||||
h.emplace("location", header_value{std::move(uri)});
|
||||
std::string html;
|
||||
if (req.method() == "GET") {
|
||||
html = create_html(status_code);
|
||||
}
|
||||
h.emplace("content-length", header_value{util::utos(html.size())});
|
||||
|
||||
res.write_head(status_code, std::move(h));
|
||||
res.end(std::move(html));
|
||||
};
|
||||
}
|
||||
|
||||
request_cb status_handler(int status_code) {
|
||||
return [status_code](const request &req, const response &res) {
|
||||
if (!::nghttp2::http2::expect_response_body(status_code)) {
|
||||
res.write_head(status_code);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
// we supply content-length for HEAD request, but body will not be
|
||||
// sent.
|
||||
auto html = create_html(status_code);
|
||||
header_map h;
|
||||
h.emplace("content-length", header_value{util::utos(html.size())});
|
||||
h.emplace("content-type", header_value{"text/html; charset=utf-8"});
|
||||
|
||||
res.write_head(status_code, std::move(h));
|
||||
res.end(std::move(html));
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_SERVER_REQUEST_HANDLER_H
|
||||
#define ASIO_SERVER_REQUEST_HANDLER_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2_server.h>
|
||||
|
||||
#endif // ASIO_SERVER_REQUEST_HANDLER_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue