Merge pull request #1846 from nghttp2/remove-python
Remove deprecated python bindings
This commit is contained in:
commit
30bb4eb8f2
|
@ -54,4 +54,3 @@ _VC_ROOT/
|
||||||
.depend.MSVC
|
.depend.MSVC
|
||||||
*.pyd
|
*.pyd
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
python/nghttp2.c
|
|
||||||
|
|
|
@ -52,9 +52,8 @@ endif()
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
# For Python bindings and documentation
|
# For documentation
|
||||||
# (Must be called before PythonLibs for matching versions.)
|
find_package(Python3 COMPONENTS Interpreter)
|
||||||
find_package(PythonInterp)
|
|
||||||
|
|
||||||
# Auto-detection of features that can be toggled
|
# Auto-detection of features that can be toggled
|
||||||
find_package(OpenSSL 1.0.1)
|
find_package(OpenSSL 1.0.1)
|
||||||
|
@ -84,13 +83,6 @@ set(ENABLE_HPACK_TOOLS_DEFAULT ${JANSSON_FOUND})
|
||||||
# 2.0.8 is required because we use evconnlistener_set_error_cb()
|
# 2.0.8 is required because we use evconnlistener_set_error_cb()
|
||||||
find_package(Libevent 2.0.8 COMPONENTS core extra openssl)
|
find_package(Libevent 2.0.8 COMPONENTS core extra openssl)
|
||||||
set(ENABLE_EXAMPLES_DEFAULT ${LIBEVENT_OPENSSL_FOUND})
|
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)
|
find_package(LibXml2 2.6.26)
|
||||||
set(WITH_LIBXML2_DEFAULT ${LIBXML2_FOUND})
|
set(WITH_LIBXML2_DEFAULT ${LIBXML2_FOUND})
|
||||||
|
@ -99,8 +91,7 @@ set(WITH_JEMALLOC_DEFAULT ${JEMALLOC_FOUND})
|
||||||
|
|
||||||
include(CMakeOptions.txt)
|
include(CMakeOptions.txt)
|
||||||
|
|
||||||
if(ENABLE_LIB_ONLY AND (ENABLE_APP OR ENABLE_HPACK_TOOLS OR ENABLE_EXAMPLES OR
|
if(ENABLE_LIB_ONLY AND (ENABLE_APP OR ENABLE_HPACK_TOOLS OR ENABLE_EXAMPLES))
|
||||||
ENABLE_PYTHON_BINDINGS))
|
|
||||||
# Remember when disabled options are disabled for later diagnostics.
|
# Remember when disabled options are disabled for later diagnostics.
|
||||||
set(ENABLE_LIB_ONLY_DISABLED_OTHERS 1)
|
set(ENABLE_LIB_ONLY_DISABLED_OTHERS 1)
|
||||||
else()
|
else()
|
||||||
|
@ -110,7 +101,6 @@ if(ENABLE_LIB_ONLY)
|
||||||
set(ENABLE_APP OFF)
|
set(ENABLE_APP OFF)
|
||||||
set(ENABLE_HPACK_TOOLS OFF)
|
set(ENABLE_HPACK_TOOLS OFF)
|
||||||
set(ENABLE_EXAMPLES OFF)
|
set(ENABLE_EXAMPLES OFF)
|
||||||
set(ENABLE_PYTHON_BINDINGS OFF)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Do not disable assertions based on CMAKE_BUILD_TYPE.
|
# 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.
|
# Additional libraries required for programs under src directory.
|
||||||
set(APP_LIBRARIES)
|
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)
|
set(CMAKE_THREAD_PREFER_PTHREAD 1)
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
if(CMAKE_USE_PTHREADS_INIT)
|
if(CMAKE_USE_PTHREADS_INIT)
|
||||||
|
@ -463,7 +439,6 @@ set(sbindir "${CMAKE_INSTALL_FULL_SBINDIR}")
|
||||||
foreach(name
|
foreach(name
|
||||||
lib/libnghttp2.pc
|
lib/libnghttp2.pc
|
||||||
lib/includes/nghttp2/nghttp2ver.h
|
lib/includes/nghttp2/nghttp2ver.h
|
||||||
python/setup.py
|
|
||||||
integration-tests/config.go
|
integration-tests/config.go
|
||||||
integration-tests/setenv
|
integration-tests/setenv
|
||||||
doc/conf.py
|
doc/conf.py
|
||||||
|
@ -474,7 +449,6 @@ foreach(name
|
||||||
doc/tutorial-hpack.rst
|
doc/tutorial-hpack.rst
|
||||||
doc/nghttpx-howto.rst
|
doc/nghttpx-howto.rst
|
||||||
doc/h2load-howto.rst
|
doc/h2load-howto.rst
|
||||||
doc/python-apiref.rst
|
|
||||||
doc/building-android-binary.rst
|
doc/building-android-binary.rst
|
||||||
doc/nghttp2.h.rst
|
doc/nghttp2.h.rst
|
||||||
doc/nghttp2ver.h.rst
|
doc/nghttp2ver.h.rst
|
||||||
|
@ -502,7 +476,6 @@ add_subdirectory(third-party)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
#add_subdirectory(src/includes)
|
#add_subdirectory(src/includes)
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
add_subdirectory(python)
|
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
#add_subdirectory(tests/testdata)
|
#add_subdirectory(tests/testdata)
|
||||||
add_subdirectory(integration-tests)
|
add_subdirectory(integration-tests)
|
||||||
|
@ -530,10 +503,8 @@ message(STATUS "summary of build options:
|
||||||
WARNCFLAGS: ${WARNCFLAGS}
|
WARNCFLAGS: ${WARNCFLAGS}
|
||||||
CXX1XCXXFLAGS: ${CXX1XCXXFLAGS}
|
CXX1XCXXFLAGS: ${CXX1XCXXFLAGS}
|
||||||
Python:
|
Python:
|
||||||
Python: ${PYTHON_EXECUTABLE}
|
Python: ${Python3_EXECUTABLE}
|
||||||
PYTHON_VERSION: ${PYTHON_VERSION_STRING}
|
Python3_VERSION: ${Python3_VERSION}
|
||||||
Library version:${PYTHONLIBS_VERSION_STRING}
|
|
||||||
Cython: ${CYTHON_EXECUTABLE}
|
|
||||||
Test:
|
Test:
|
||||||
CUnit: ${HAVE_CUNIT} (LIBS='${CUNIT_LIBRARIES}')
|
CUnit: ${HAVE_CUNIT} (LIBS='${CUNIT_LIBRARIES}')
|
||||||
Failmalloc: ${ENABLE_FAILMALLOC}
|
Failmalloc: ${ENABLE_FAILMALLOC}
|
||||||
|
@ -559,7 +530,6 @@ message(STATUS "summary of build options:
|
||||||
Applications: ${ENABLE_APP}
|
Applications: ${ENABLE_APP}
|
||||||
HPACK tools: ${ENABLE_HPACK_TOOLS}
|
HPACK tools: ${ENABLE_HPACK_TOOLS}
|
||||||
Examples: ${ENABLE_EXAMPLES}
|
Examples: ${ENABLE_EXAMPLES}
|
||||||
Python bindings:${ENABLE_PYTHON_BINDINGS}
|
|
||||||
Threading: ${ENABLE_THREADS}
|
Threading: ${ENABLE_THREADS}
|
||||||
HTTP/3(EXPERIMENTAL): ${ENABLE_HTTP3}
|
HTTP/3(EXPERIMENTAL): ${ENABLE_HTTP3}
|
||||||
")
|
")
|
||||||
|
|
|
@ -9,10 +9,8 @@ option(ENABLE_HPACK_TOOLS "Build HPACK tools"
|
||||||
${ENABLE_HPACK_TOOLS_DEFAULT})
|
${ENABLE_HPACK_TOOLS_DEFAULT})
|
||||||
option(ENABLE_EXAMPLES "Build examples"
|
option(ENABLE_EXAMPLES "Build examples"
|
||||||
${ENABLE_EXAMPLES_DEFAULT})
|
${ENABLE_EXAMPLES_DEFAULT})
|
||||||
option(ENABLE_PYTHON_BINDINGS "Build Python bindings"
|
|
||||||
${ENABLE_PYTHON_BINDINGS_DEFAULT})
|
|
||||||
option(ENABLE_FAILMALLOC "Build failmalloc test program" ON)
|
option(ENABLE_FAILMALLOC "Build failmalloc test program" ON)
|
||||||
option(ENABLE_LIB_ONLY "Build libnghttp2 only. This is a short hand for -DENABLE_APP=0 -DENABLE_EXAMPLES=0 -DENABLE_HPACK_TOOLS=0 -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_STATIC_LIB "Build libnghttp2 in static mode also")
|
||||||
option(ENABLE_SHARED_LIB "Build libnghttp2 as a shared library" ON)
|
option(ENABLE_SHARED_LIB "Build libnghttp2 as a shared library" ON)
|
||||||
option(ENABLE_STATIC_CRT "Build libnghttp2 against the MS LIBCMT[d]")
|
option(ENABLE_STATIC_CRT "Build libnghttp2 against the MS LIBCMT[d]")
|
||||||
|
|
|
@ -33,7 +33,7 @@ RUN apt-get update && \
|
||||||
apt-get install -y unzip make binutils autoconf \
|
apt-get install -y unzip make binutils autoconf \
|
||||||
automake autotools-dev libtool pkg-config git \
|
automake autotools-dev libtool pkg-config git \
|
||||||
curl dpkg-dev libxml2-dev genisoimage libc6-i386 \
|
curl dpkg-dev libxml2-dev genisoimage libc6-i386 \
|
||||||
lib32stdc++6 python3 && \
|
lib32stdc++6 && \
|
||||||
rm -rf /var/cache/apt/*
|
rm -rf /var/cache/apt/*
|
||||||
|
|
||||||
# Download NDK
|
# Download NDK
|
||||||
|
@ -112,7 +112,6 @@ RUN autoreconf -i && \
|
||||||
--host=$TARGET \
|
--host=$TARGET \
|
||||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||||
--without-libxml2 \
|
--without-libxml2 \
|
||||||
--disable-python-bindings \
|
|
||||||
--disable-examples \
|
--disable-examples \
|
||||||
--disable-threads \
|
--disable-threads \
|
||||||
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||||
|
|
|
@ -20,14 +20,9 @@
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
SUBDIRS = lib third-party src bpf examples python tests integration-tests \
|
SUBDIRS = lib third-party src bpf examples tests integration-tests \
|
||||||
doc contrib script
|
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
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
dist_doc_DATA = README.rst
|
dist_doc_DATA = README.rst
|
||||||
|
@ -42,7 +37,6 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-env \
|
||||||
cmake/FindLibev.cmake \
|
cmake/FindLibev.cmake \
|
||||||
cmake/FindCUnit.cmake \
|
cmake/FindCUnit.cmake \
|
||||||
cmake/Version.cmake \
|
cmake/Version.cmake \
|
||||||
cmake/FindCython.cmake \
|
|
||||||
cmake/FindLibevent.cmake \
|
cmake/FindLibevent.cmake \
|
||||||
cmake/FindJansson.cmake \
|
cmake/FindJansson.cmake \
|
||||||
cmake/FindLibcares.cmake \
|
cmake/FindLibcares.cmake \
|
||||||
|
|
125
README.rst
125
README.rst
|
@ -103,12 +103,6 @@ To mitigate heap fragmentation in long running server programs
|
||||||
Alpine Linux currently does not support malloc replacement
|
Alpine Linux currently does not support malloc replacement
|
||||||
due to musl limitations. See details in issue `#762 <https://github.com/nghttp2/nghttp2/issues/762>`_.
|
due to musl limitations. See details in issue `#762 <https://github.com/nghttp2/nghttp2/issues/762>`_.
|
||||||
|
|
||||||
The Python bindings (deprecated) require the following packages:
|
|
||||||
|
|
||||||
* cython >= 0.19
|
|
||||||
* python >= 3.8
|
|
||||||
* python-setuptools
|
|
||||||
|
|
||||||
To enable mruby support for nghttpx, `mruby
|
To enable mruby support for nghttpx, `mruby
|
||||||
<https://github.com/mruby/mruby>`_ is required. We need to build
|
<https://github.com/mruby/mruby>`_ is required. We need to build
|
||||||
mruby with C++ ABI explicitly turned on, and probably need other
|
mruby with C++ ABI explicitly turned on, and probably need other
|
||||||
|
@ -400,7 +394,6 @@ Build nghttp2:
|
||||||
$ git submodule update --init
|
$ git submodule update --init
|
||||||
$ autoreconf -i
|
$ autoreconf -i
|
||||||
$ ./configure --with-mruby --with-neverbleed --enable-http3 --with-libbpf \
|
$ ./configure --with-mruby --with-neverbleed --enable-http3 --with-libbpf \
|
||||||
--disable-python-bindings \
|
|
||||||
CC=clang-14 CXX=clang++-14 \
|
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" \
|
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"
|
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../openssl/build/lib -Wl,-rpath,$PWD/../libbpf/build/lib64"
|
||||||
|
@ -1425,124 +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
|
corresponding header set was processed. The format is the same as
|
||||||
``deflatehd``.
|
``deflatehd``.
|
||||||
|
|
||||||
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
|
Contribution
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
--host=$TARGET \
|
--host=$TARGET \
|
||||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||||
--without-libxml2 \
|
--without-libxml2 \
|
||||||
--disable-python-bindings \
|
|
||||||
--disable-examples \
|
--disable-examples \
|
||||||
--disable-threads \
|
--disable-threads \
|
||||||
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||||
|
|
|
@ -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 )
|
|
62
configure.ac
62
configure.ac
|
@ -87,11 +87,6 @@ AC_ARG_ENABLE([examples],
|
||||||
[Build examples [default=check]])],
|
[Build examples [default=check]])],
|
||||||
[request_examples=$enableval], [request_examples=check])
|
[request_examples=$enableval], [request_examples=check])
|
||||||
|
|
||||||
AC_ARG_ENABLE([python-bindings],
|
|
||||||
[AS_HELP_STRING([--enable-python-bindings],
|
|
||||||
[Build Python bindings [default=no]])],
|
|
||||||
[request_python_bindings=$enableval], [request_python_bindings=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([failmalloc],
|
AC_ARG_ENABLE([failmalloc],
|
||||||
[AS_HELP_STRING([--disable-failmalloc],
|
[AS_HELP_STRING([--disable-failmalloc],
|
||||||
[Do not build failmalloc test program])],
|
[Do not build failmalloc test program])],
|
||||||
|
@ -99,7 +94,7 @@ AC_ARG_ENABLE([failmalloc],
|
||||||
|
|
||||||
AC_ARG_ENABLE([lib-only],
|
AC_ARG_ENABLE([lib-only],
|
||||||
[AS_HELP_STRING([--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])
|
[request_lib_only=$enableval], [request_lib_only=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE([http3],
|
AC_ARG_ENABLE([http3],
|
||||||
|
@ -167,11 +162,6 @@ AC_ARG_WITH([neverbleed],
|
||||||
[Use neverbleed [default=no]])],
|
[Use neverbleed [default=no]])],
|
||||||
[request_neverbleed=$withval], [request_neverbleed=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],
|
AC_ARG_WITH([libngtcp2],
|
||||||
[AS_HELP_STRING([--with-libngtcp2],
|
[AS_HELP_STRING([--with-libngtcp2],
|
||||||
[Use libngtcp2 [default=check]])],
|
[Use libngtcp2 [default=check]])],
|
||||||
|
@ -188,8 +178,6 @@ AC_ARG_WITH([libbpf],
|
||||||
[request_libbpf=$withval], [request_libbpf=no])
|
[request_libbpf=$withval], [request_libbpf=no])
|
||||||
|
|
||||||
dnl Define variables
|
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_CFLAGS], [C compiler flags for libev, skipping any checks])
|
||||||
AC_ARG_VAR([LIBEV_LIBS], [linker flags for libev, skipping any checks])
|
AC_ARG_VAR([LIBEV_LIBS], [linker flags for libev, skipping any checks])
|
||||||
|
|
||||||
|
@ -215,16 +203,10 @@ PKG_PROG_PKG_CONFIG([0.20])
|
||||||
|
|
||||||
AM_PATH_PYTHON([3.8],, [:])
|
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
|
if [test "x$request_lib_only" = "xyes"]; then
|
||||||
request_app=no
|
request_app=no
|
||||||
request_hpack_tools=no
|
request_hpack_tools=no
|
||||||
request_examples=no
|
request_examples=no
|
||||||
request_python_bindings=no
|
|
||||||
request_http3=no
|
request_http3=no
|
||||||
request_libxml2=no
|
request_libxml2=no
|
||||||
request_jansson=no
|
request_jansson=no
|
||||||
|
@ -242,19 +224,6 @@ if [test "x$request_lib_only" = "xyes"]; then
|
||||||
request_libbpf=no
|
request_libbpf=no
|
||||||
fi
|
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
|
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])
|
AC_DEFINE([NGHTTP2_NORETURN], [__attribute__((noreturn))], [Hint to the compiler that a function never return])
|
||||||
else
|
else
|
||||||
|
@ -857,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_MRUBY], [test "x${have_mruby}" = "xyes"])
|
||||||
AM_CONDITIONAL([HAVE_NEVERBLEED], [test "x${have_neverbleed}" = "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
|
# failmalloc tests
|
||||||
enable_failmalloc=no
|
enable_failmalloc=no
|
||||||
if test "x${request_failmalloc}" = "xyes"; then
|
if test "x${request_failmalloc}" = "xyes"; then
|
||||||
|
@ -1126,8 +1074,6 @@ AC_CONFIG_FILES([
|
||||||
src/Makefile
|
src/Makefile
|
||||||
bpf/Makefile
|
bpf/Makefile
|
||||||
examples/Makefile
|
examples/Makefile
|
||||||
python/Makefile
|
|
||||||
python/setup.py
|
|
||||||
integration-tests/Makefile
|
integration-tests/Makefile
|
||||||
integration-tests/config.go
|
integration-tests/config.go
|
||||||
integration-tests/setenv
|
integration-tests/setenv
|
||||||
|
@ -1140,7 +1086,6 @@ AC_CONFIG_FILES([
|
||||||
doc/tutorial-hpack.rst
|
doc/tutorial-hpack.rst
|
||||||
doc/nghttpx-howto.rst
|
doc/nghttpx-howto.rst
|
||||||
doc/h2load-howto.rst
|
doc/h2load-howto.rst
|
||||||
doc/python-apiref.rst
|
|
||||||
doc/building-android-binary.rst
|
doc/building-android-binary.rst
|
||||||
doc/nghttp2.h.rst
|
doc/nghttp2.h.rst
|
||||||
doc/nghttp2ver.h.rst
|
doc/nghttp2ver.h.rst
|
||||||
|
@ -1185,10 +1130,6 @@ AC_MSG_NOTICE([summary of build options:
|
||||||
Python:
|
Python:
|
||||||
Python: ${PYTHON}
|
Python: ${PYTHON}
|
||||||
PYTHON_VERSION: ${PYTHON_VERSION}
|
PYTHON_VERSION: ${PYTHON_VERSION}
|
||||||
pyexecdir: ${pyexecdir}
|
|
||||||
PYTHON_CPPFLAGS:${PYTHON_CPPFLAGS}
|
|
||||||
PYTHON_LIBS: ${PYTHON_LIBS}
|
|
||||||
Cython: ${CYTHON}
|
|
||||||
Test:
|
Test:
|
||||||
CUnit: ${have_cunit} (CFLAGS='${CUNIT_CFLAGS}' LIBS='${CUNIT_LIBS}')
|
CUnit: ${have_cunit} (CFLAGS='${CUNIT_CFLAGS}' LIBS='${CUNIT_LIBS}')
|
||||||
Failmalloc: ${enable_failmalloc}
|
Failmalloc: ${enable_failmalloc}
|
||||||
|
@ -1215,7 +1156,6 @@ AC_MSG_NOTICE([summary of build options:
|
||||||
Applications: ${enable_app}
|
Applications: ${enable_app}
|
||||||
HPACK tools: ${enable_hpack_tools}
|
HPACK tools: ${enable_hpack_tools}
|
||||||
Examples: ${enable_examples}
|
Examples: ${enable_examples}
|
||||||
Python bindings:${enable_python_bindings}
|
|
||||||
Threading: ${enable_threads}
|
Threading: ${enable_threads}
|
||||||
HTTP/3 (EXPERIMENTAL): ${enable_http3}
|
HTTP/3 (EXPERIMENTAL): ${enable_http3}
|
||||||
])
|
])
|
||||||
|
|
|
@ -13,7 +13,6 @@ nghttp2_*.rst
|
||||||
nghttp2ver.h.rst
|
nghttp2ver.h.rst
|
||||||
nghttpx-howto.rst
|
nghttpx-howto.rst
|
||||||
package_README.rst
|
package_README.rst
|
||||||
python-apiref.rst
|
|
||||||
tutorial-client.rst
|
tutorial-client.rst
|
||||||
tutorial-hpack.rst
|
tutorial-hpack.rst
|
||||||
tutorial-server.rst
|
tutorial-server.rst
|
||||||
|
|
|
@ -180,7 +180,6 @@ set(EXTRA_DIST
|
||||||
sources/tutorial-hpack.rst
|
sources/tutorial-hpack.rst
|
||||||
sources/nghttpx-howto.rst
|
sources/nghttpx-howto.rst
|
||||||
sources/h2load-howto.rst
|
sources/h2load-howto.rst
|
||||||
sources/python-apiref.rst
|
|
||||||
sources/building-android-binary.rst
|
sources/building-android-binary.rst
|
||||||
sources/contribute.rst
|
sources/contribute.rst
|
||||||
_exts/rubydomain/LICENSE.rubydomain
|
_exts/rubydomain/LICENSE.rubydomain
|
||||||
|
@ -268,7 +267,7 @@ add_custom_command(
|
||||||
apiref.rst
|
apiref.rst
|
||||||
${APIDOCS}
|
${APIDOCS}
|
||||||
COMMAND
|
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.rst macros.rst enums.rst types.rst .
|
||||||
${apiref_SOURCES}
|
${apiref_SOURCES}
|
||||||
DEPENDS
|
DEPENDS
|
||||||
|
|
|
@ -206,7 +206,6 @@ EXTRA_DIST = \
|
||||||
sources/tutorial-hpack.rst \
|
sources/tutorial-hpack.rst \
|
||||||
sources/nghttpx-howto.rst \
|
sources/nghttpx-howto.rst \
|
||||||
sources/h2load-howto.rst \
|
sources/h2load-howto.rst \
|
||||||
sources/python-apiref.rst \
|
|
||||||
sources/building-android-binary.rst \
|
sources/building-android-binary.rst \
|
||||||
sources/contribute.rst \
|
sources/contribute.rst \
|
||||||
sources/security.rst \
|
sources/security.rst \
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
.. include:: @top_srcdir@/doc/sources/python-apiref.rst
|
|
|
@ -31,7 +31,6 @@ Contents:
|
||||||
h2load-howto
|
h2load-howto
|
||||||
programmers-guide
|
programmers-guide
|
||||||
apiref
|
apiref
|
||||||
python-apiref
|
|
||||||
nghttp2.h
|
nghttp2.h
|
||||||
nghttp2ver.h
|
nghttp2ver.h
|
||||||
Source <https://github.com/nghttp2/nghttp2>
|
Source <https://github.com/nghttp2/nghttp2>
|
||||||
|
|
|
@ -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()
|
|
|
@ -47,7 +47,7 @@ RUN git clone --depth 1 https://github.com/nghttp2/nghttp2.git && \
|
||||||
git submodule update --init && \
|
git submodule update --init && \
|
||||||
autoreconf -i && \
|
autoreconf -i && \
|
||||||
./configure --disable-examples --disable-hpack-tools \
|
./configure --disable-examples --disable-hpack-tools \
|
||||||
--disable-python-bindings --with-mruby --with-neverbleed \
|
--with-mruby --with-neverbleed \
|
||||||
--enable-http3 --with-libbpf \
|
--enable-http3 --with-libbpf \
|
||||||
CC=clang CXX=clang++ \
|
CC=clang CXX=clang++ \
|
||||||
LIBTOOL_LDFLAGS="-static-libtool-libs" \
|
LIBTOOL_LDFLAGS="-static-libtool-libs" \
|
||||||
|
|
|
@ -6,15 +6,8 @@
|
||||||
# The MIT License apply.
|
# 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))
|
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 := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV//g' -e 's/], //g')
|
||||||
_VERSION := $(subst ., ,$(_VERSION))
|
_VERSION := $(subst ., ,$(_VERSION))
|
||||||
VER_MAJOR := $(word 1,$(_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
|
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 'Welcome to NgHTTP2 (release + debug).'
|
||||||
@echo 'Do a "make -f Makefile.MSVC install" at own risk!'
|
@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 \
|
install: includes/nghttp2/nghttp2.h includes/nghttp2/nghttp2ver.h \
|
||||||
$(TARGETS) \
|
$(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.
|
# 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:=$(shell cygpath -w $(abspath $(OBJ_DIR)))
|
||||||
WIN_OBJDIR:=$(subst \,/,$(WIN_OBJDIR))
|
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)
|
$(OBJ_DIR)/r_%.obj: %.c $(THIS_MAKEFILE)
|
||||||
$(CC) $(CFLAGS_R) $(CFLAGS) -Fo$@ -c $<
|
$(CC) $(CFLAGS_R) $(CFLAGS) -Fo$@ -c $<
|
||||||
@echo
|
@echo
|
||||||
|
@ -262,7 +230,7 @@ clean:
|
||||||
rm -f $(OBJ_DIR)/* includes/nghttp2/nghttp2ver.h
|
rm -f $(OBJ_DIR)/* includes/nghttp2/nghttp2ver.h
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
vclean realclean: clean clean_nghttp2_pyd_$(USE_CYTHON)
|
vclean realclean: clean
|
||||||
- rm -rf $(OBJ_DIR)
|
- rm -rf $(OBJ_DIR)
|
||||||
- rm -f .depend.MSVC
|
- rm -f .depend.MSVC
|
||||||
|
|
||||||
|
|
|
@ -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()
|
|
Loading…
Reference in New Issue