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
|
||||
*.pyd
|
||||
*.egg-info/
|
||||
python/nghttp2.c
|
||||
|
|
|
@ -52,9 +52,8 @@ endif()
|
|||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# For Python bindings and documentation
|
||||
# (Must be called before PythonLibs for matching versions.)
|
||||
find_package(PythonInterp)
|
||||
# For documentation
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
|
||||
# Auto-detection of features that can be toggled
|
||||
find_package(OpenSSL 1.0.1)
|
||||
|
@ -84,13 +83,6 @@ set(ENABLE_HPACK_TOOLS_DEFAULT ${JANSSON_FOUND})
|
|||
# 2.0.8 is required because we use evconnlistener_set_error_cb()
|
||||
find_package(Libevent 2.0.8 COMPONENTS core extra openssl)
|
||||
set(ENABLE_EXAMPLES_DEFAULT ${LIBEVENT_OPENSSL_FOUND})
|
||||
find_package(Cython)
|
||||
find_package(PythonLibs)
|
||||
if(CYTHON_FOUND AND PYTHONLIBS_FOUND)
|
||||
set(ENABLE_PYTHON_BINDINGS_DEFAULT ON)
|
||||
else()
|
||||
set(ENABLE_PYTHON_BINDINGS_DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
find_package(LibXml2 2.6.26)
|
||||
set(WITH_LIBXML2_DEFAULT ${LIBXML2_FOUND})
|
||||
|
@ -99,8 +91,7 @@ set(WITH_JEMALLOC_DEFAULT ${JEMALLOC_FOUND})
|
|||
|
||||
include(CMakeOptions.txt)
|
||||
|
||||
if(ENABLE_LIB_ONLY AND (ENABLE_APP OR ENABLE_HPACK_TOOLS OR ENABLE_EXAMPLES OR
|
||||
ENABLE_PYTHON_BINDINGS))
|
||||
if(ENABLE_LIB_ONLY AND (ENABLE_APP OR ENABLE_HPACK_TOOLS OR ENABLE_EXAMPLES))
|
||||
# Remember when disabled options are disabled for later diagnostics.
|
||||
set(ENABLE_LIB_ONLY_DISABLED_OTHERS 1)
|
||||
else()
|
||||
|
@ -110,7 +101,6 @@ if(ENABLE_LIB_ONLY)
|
|||
set(ENABLE_APP OFF)
|
||||
set(ENABLE_HPACK_TOOLS OFF)
|
||||
set(ENABLE_EXAMPLES OFF)
|
||||
set(ENABLE_PYTHON_BINDINGS OFF)
|
||||
endif()
|
||||
|
||||
# Do not disable assertions based on CMAKE_BUILD_TYPE.
|
||||
|
@ -156,20 +146,6 @@ cmake_pop_check_state()
|
|||
# Additional libraries required for programs under src directory.
|
||||
set(APP_LIBRARIES)
|
||||
|
||||
if(ENABLE_PYTHON_BINDINGS)
|
||||
if(NOT (CYTHON_FOUND AND PYTHONLIBS_FOUND))
|
||||
message(FATAL_ERROR "python bindings were requested "
|
||||
"(ENABLE_PYTHON_BINDINGS=1) but dependencies are not met.")
|
||||
endif()
|
||||
if(NOT PYTHON_VERSION_STRING STREQUAL PYTHONLIBS_VERSION_STRING)
|
||||
message(FATAL_ERROR
|
||||
"Python executable and library must have the same version!"
|
||||
" Found Python ${PYTHON_VERSION_STRING} and"
|
||||
" PythonLibs ${PYTHONLIBS_VERSION_STRING}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD 1)
|
||||
find_package(Threads)
|
||||
if(CMAKE_USE_PTHREADS_INIT)
|
||||
|
@ -463,7 +439,6 @@ set(sbindir "${CMAKE_INSTALL_FULL_SBINDIR}")
|
|||
foreach(name
|
||||
lib/libnghttp2.pc
|
||||
lib/includes/nghttp2/nghttp2ver.h
|
||||
python/setup.py
|
||||
integration-tests/config.go
|
||||
integration-tests/setenv
|
||||
doc/conf.py
|
||||
|
@ -474,7 +449,6 @@ foreach(name
|
|||
doc/tutorial-hpack.rst
|
||||
doc/nghttpx-howto.rst
|
||||
doc/h2load-howto.rst
|
||||
doc/python-apiref.rst
|
||||
doc/building-android-binary.rst
|
||||
doc/nghttp2.h.rst
|
||||
doc/nghttp2ver.h.rst
|
||||
|
@ -502,7 +476,6 @@ add_subdirectory(third-party)
|
|||
add_subdirectory(src)
|
||||
#add_subdirectory(src/includes)
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(python)
|
||||
add_subdirectory(tests)
|
||||
#add_subdirectory(tests/testdata)
|
||||
add_subdirectory(integration-tests)
|
||||
|
@ -530,10 +503,8 @@ message(STATUS "summary of build options:
|
|||
WARNCFLAGS: ${WARNCFLAGS}
|
||||
CXX1XCXXFLAGS: ${CXX1XCXXFLAGS}
|
||||
Python:
|
||||
Python: ${PYTHON_EXECUTABLE}
|
||||
PYTHON_VERSION: ${PYTHON_VERSION_STRING}
|
||||
Library version:${PYTHONLIBS_VERSION_STRING}
|
||||
Cython: ${CYTHON_EXECUTABLE}
|
||||
Python: ${Python3_EXECUTABLE}
|
||||
Python3_VERSION: ${Python3_VERSION}
|
||||
Test:
|
||||
CUnit: ${HAVE_CUNIT} (LIBS='${CUNIT_LIBRARIES}')
|
||||
Failmalloc: ${ENABLE_FAILMALLOC}
|
||||
|
@ -559,7 +530,6 @@ message(STATUS "summary of build options:
|
|||
Applications: ${ENABLE_APP}
|
||||
HPACK tools: ${ENABLE_HPACK_TOOLS}
|
||||
Examples: ${ENABLE_EXAMPLES}
|
||||
Python bindings:${ENABLE_PYTHON_BINDINGS}
|
||||
Threading: ${ENABLE_THREADS}
|
||||
HTTP/3(EXPERIMENTAL): ${ENABLE_HTTP3}
|
||||
")
|
||||
|
|
|
@ -9,10 +9,8 @@ option(ENABLE_HPACK_TOOLS "Build HPACK tools"
|
|||
${ENABLE_HPACK_TOOLS_DEFAULT})
|
||||
option(ENABLE_EXAMPLES "Build examples"
|
||||
${ENABLE_EXAMPLES_DEFAULT})
|
||||
option(ENABLE_PYTHON_BINDINGS "Build Python bindings"
|
||||
${ENABLE_PYTHON_BINDINGS_DEFAULT})
|
||||
option(ENABLE_FAILMALLOC "Build failmalloc test program" ON)
|
||||
option(ENABLE_LIB_ONLY "Build libnghttp2 only. This is a short hand for -DENABLE_APP=0 -DENABLE_EXAMPLES=0 -DENABLE_HPACK_TOOLS=0 -DENABLE_PYTHON_BINDINGS=0")
|
||||
option(ENABLE_LIB_ONLY "Build libnghttp2 only. This is a short hand for -DENABLE_APP=0 -DENABLE_EXAMPLES=0 -DENABLE_HPACK_TOOLS=0")
|
||||
option(ENABLE_STATIC_LIB "Build libnghttp2 in static mode also")
|
||||
option(ENABLE_SHARED_LIB "Build libnghttp2 as a shared library" ON)
|
||||
option(ENABLE_STATIC_CRT "Build libnghttp2 against the MS LIBCMT[d]")
|
||||
|
|
|
@ -33,7 +33,7 @@ RUN apt-get update && \
|
|||
apt-get install -y unzip make binutils autoconf \
|
||||
automake autotools-dev libtool pkg-config git \
|
||||
curl dpkg-dev libxml2-dev genisoimage libc6-i386 \
|
||||
lib32stdc++6 python3 && \
|
||||
lib32stdc++6 && \
|
||||
rm -rf /var/cache/apt/*
|
||||
|
||||
# Download NDK
|
||||
|
@ -112,7 +112,6 @@ RUN autoreconf -i && \
|
|||
--host=$TARGET \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--without-libxml2 \
|
||||
--disable-python-bindings \
|
||||
--disable-examples \
|
||||
--disable-threads \
|
||||
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||
|
|
|
@ -20,14 +20,9 @@
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
SUBDIRS = lib third-party src bpf examples python tests integration-tests \
|
||||
SUBDIRS = lib third-party src bpf examples tests integration-tests \
|
||||
doc contrib script
|
||||
|
||||
# Now with python setuptools, make uninstall will leave many files we
|
||||
# cannot easily remove (e.g., easy-install.pth). Disable it for
|
||||
# distcheck rule.
|
||||
AM_DISTCHECK_CONFIGURE_FLAGS = --disable-python-bindings
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
dist_doc_DATA = README.rst
|
||||
|
@ -42,7 +37,6 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-env \
|
|||
cmake/FindLibev.cmake \
|
||||
cmake/FindCUnit.cmake \
|
||||
cmake/Version.cmake \
|
||||
cmake/FindCython.cmake \
|
||||
cmake/FindLibevent.cmake \
|
||||
cmake/FindJansson.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
|
||||
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
|
||||
<https://github.com/mruby/mruby>`_ is required. We need to build
|
||||
mruby with C++ ABI explicitly turned on, and probably need other
|
||||
|
@ -400,7 +394,6 @@ Build nghttp2:
|
|||
$ git submodule update --init
|
||||
$ autoreconf -i
|
||||
$ ./configure --with-mruby --with-neverbleed --enable-http3 --with-libbpf \
|
||||
--disable-python-bindings \
|
||||
CC=clang-14 CXX=clang++-14 \
|
||||
PKG_CONFIG_PATH="$PWD/../openssl/build/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig:$PWD/../ngtcp2/build/lib/pkgconfig:$PWD/../libbpf/build/lib64/pkgconfig" \
|
||||
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../openssl/build/lib -Wl,-rpath,$PWD/../libbpf/build/lib64"
|
||||
|
@ -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
|
||||
``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
|
||||
------------
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
--host=$TARGET \
|
||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||
--without-libxml2 \
|
||||
--disable-python-bindings \
|
||||
--disable-examples \
|
||||
--disable-threads \
|
||||
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]])],
|
||||
[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],
|
||||
[AS_HELP_STRING([--disable-failmalloc],
|
||||
[Do not build failmalloc test program])],
|
||||
|
@ -99,7 +94,7 @@ AC_ARG_ENABLE([failmalloc],
|
|||
|
||||
AC_ARG_ENABLE([lib-only],
|
||||
[AS_HELP_STRING([--enable-lib-only],
|
||||
[Build libnghttp2 only. This is a short hand for --disable-app --disable-examples --disable-hpack-tools --disable-python-bindings])],
|
||||
[Build libnghttp2 only. This is a short hand for --disable-app --disable-examples --disable-hpack-tools])],
|
||||
[request_lib_only=$enableval], [request_lib_only=no])
|
||||
|
||||
AC_ARG_ENABLE([http3],
|
||||
|
@ -167,11 +162,6 @@ AC_ARG_WITH([neverbleed],
|
|||
[Use neverbleed [default=no]])],
|
||||
[request_neverbleed=$withval], [request_neverbleed=no])
|
||||
|
||||
AC_ARG_WITH([cython],
|
||||
[AS_HELP_STRING([--with-cython=PATH],
|
||||
[Use cython in given PATH])],
|
||||
[cython_path=$withval], [])
|
||||
|
||||
AC_ARG_WITH([libngtcp2],
|
||||
[AS_HELP_STRING([--with-libngtcp2],
|
||||
[Use libngtcp2 [default=check]])],
|
||||
|
@ -188,8 +178,6 @@ AC_ARG_WITH([libbpf],
|
|||
[request_libbpf=$withval], [request_libbpf=no])
|
||||
|
||||
dnl Define variables
|
||||
AC_ARG_VAR([CYTHON], [the Cython executable])
|
||||
|
||||
AC_ARG_VAR([LIBEV_CFLAGS], [C compiler flags for libev, skipping any checks])
|
||||
AC_ARG_VAR([LIBEV_LIBS], [linker flags for libev, skipping any checks])
|
||||
|
||||
|
@ -215,16 +203,10 @@ PKG_PROG_PKG_CONFIG([0.20])
|
|||
|
||||
AM_PATH_PYTHON([3.8],, [:])
|
||||
|
||||
if test "x$request_python_bindings" = "xyes" &&
|
||||
test "x$PYTHON" = "x:"; then
|
||||
AC_MSG_ERROR([python was requested (enable-python-bindings) but not found])
|
||||
fi
|
||||
|
||||
if [test "x$request_lib_only" = "xyes"]; then
|
||||
request_app=no
|
||||
request_hpack_tools=no
|
||||
request_examples=no
|
||||
request_python_bindings=no
|
||||
request_http3=no
|
||||
request_libxml2=no
|
||||
request_jansson=no
|
||||
|
@ -242,19 +224,6 @@ if [test "x$request_lib_only" = "xyes"]; then
|
|||
request_libbpf=no
|
||||
fi
|
||||
|
||||
if test "x$request_python_bindings" != "xno" &&
|
||||
test "x$PYTHON" != "x:"; then
|
||||
# version check is broken
|
||||
AX_PYTHON_DEVEL()
|
||||
fi
|
||||
|
||||
if test "x${cython_path}" = "x"; then
|
||||
AC_CHECK_PROGS([CYTHON], [cython.py cython])
|
||||
else
|
||||
CYTHON=${cython_path}
|
||||
AC_SUBST([CYTHON])
|
||||
fi
|
||||
|
||||
if test "x$GCC" = "xyes" -o "x$CC" = "xclang" ; then
|
||||
AC_DEFINE([NGHTTP2_NORETURN], [__attribute__((noreturn))], [Hint to the compiler that a function never return])
|
||||
else
|
||||
|
@ -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_NEVERBLEED], [test "x${have_neverbleed}" = "xyes"])
|
||||
|
||||
# Python bindings
|
||||
enable_python_bindings=no
|
||||
if test "x${request_python_bindings}" != "xno" &&
|
||||
test "x${CYTHON}" != "x" &&
|
||||
test "x${PYTHON}" != "x:" &&
|
||||
test "x${PYTHON_VERSION}" != "x"; then
|
||||
enable_python_bindings=yes
|
||||
fi
|
||||
|
||||
if test "x${request_python_bindings}" = "xyes" &&
|
||||
test "x${enable_python_bindings}" != "xyes"; then
|
||||
AC_MSG_ERROR([python bindings were requested (--enable-python-bindings) but dependencies are not met.])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_PYTHON_BINDINGS],
|
||||
[test "x${enable_python_bindings}" = "xyes"])
|
||||
|
||||
# Produce cython conditional, so that we can distribute generated C
|
||||
# source
|
||||
AM_CONDITIONAL([HAVE_CYTHON], [test "x${CYTHON}" != "x"])
|
||||
|
||||
# failmalloc tests
|
||||
enable_failmalloc=no
|
||||
if test "x${request_failmalloc}" = "xyes"; then
|
||||
|
@ -1126,8 +1074,6 @@ AC_CONFIG_FILES([
|
|||
src/Makefile
|
||||
bpf/Makefile
|
||||
examples/Makefile
|
||||
python/Makefile
|
||||
python/setup.py
|
||||
integration-tests/Makefile
|
||||
integration-tests/config.go
|
||||
integration-tests/setenv
|
||||
|
@ -1140,7 +1086,6 @@ AC_CONFIG_FILES([
|
|||
doc/tutorial-hpack.rst
|
||||
doc/nghttpx-howto.rst
|
||||
doc/h2load-howto.rst
|
||||
doc/python-apiref.rst
|
||||
doc/building-android-binary.rst
|
||||
doc/nghttp2.h.rst
|
||||
doc/nghttp2ver.h.rst
|
||||
|
@ -1185,10 +1130,6 @@ AC_MSG_NOTICE([summary of build options:
|
|||
Python:
|
||||
Python: ${PYTHON}
|
||||
PYTHON_VERSION: ${PYTHON_VERSION}
|
||||
pyexecdir: ${pyexecdir}
|
||||
PYTHON_CPPFLAGS:${PYTHON_CPPFLAGS}
|
||||
PYTHON_LIBS: ${PYTHON_LIBS}
|
||||
Cython: ${CYTHON}
|
||||
Test:
|
||||
CUnit: ${have_cunit} (CFLAGS='${CUNIT_CFLAGS}' LIBS='${CUNIT_LIBS}')
|
||||
Failmalloc: ${enable_failmalloc}
|
||||
|
@ -1215,7 +1156,6 @@ AC_MSG_NOTICE([summary of build options:
|
|||
Applications: ${enable_app}
|
||||
HPACK tools: ${enable_hpack_tools}
|
||||
Examples: ${enable_examples}
|
||||
Python bindings:${enable_python_bindings}
|
||||
Threading: ${enable_threads}
|
||||
HTTP/3 (EXPERIMENTAL): ${enable_http3}
|
||||
])
|
||||
|
|
|
@ -13,7 +13,6 @@ nghttp2_*.rst
|
|||
nghttp2ver.h.rst
|
||||
nghttpx-howto.rst
|
||||
package_README.rst
|
||||
python-apiref.rst
|
||||
tutorial-client.rst
|
||||
tutorial-hpack.rst
|
||||
tutorial-server.rst
|
||||
|
|
|
@ -180,7 +180,6 @@ set(EXTRA_DIST
|
|||
sources/tutorial-hpack.rst
|
||||
sources/nghttpx-howto.rst
|
||||
sources/h2load-howto.rst
|
||||
sources/python-apiref.rst
|
||||
sources/building-android-binary.rst
|
||||
sources/contribute.rst
|
||||
_exts/rubydomain/LICENSE.rubydomain
|
||||
|
@ -268,7 +267,7 @@ add_custom_command(
|
|||
apiref.rst
|
||||
${APIDOCS}
|
||||
COMMAND
|
||||
"${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkapiref.py"
|
||||
"${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkapiref.py"
|
||||
apiref.rst macros.rst enums.rst types.rst .
|
||||
${apiref_SOURCES}
|
||||
DEPENDS
|
||||
|
|
|
@ -206,7 +206,6 @@ EXTRA_DIST = \
|
|||
sources/tutorial-hpack.rst \
|
||||
sources/nghttpx-howto.rst \
|
||||
sources/h2load-howto.rst \
|
||||
sources/python-apiref.rst \
|
||||
sources/building-android-binary.rst \
|
||||
sources/contribute.rst \
|
||||
sources/security.rst \
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
.. include:: @top_srcdir@/doc/sources/python-apiref.rst
|
|
@ -31,7 +31,6 @@ Contents:
|
|||
h2load-howto
|
||||
programmers-guide
|
||||
apiref
|
||||
python-apiref
|
||||
nghttp2.h
|
||||
nghttp2ver.h
|
||||
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 && \
|
||||
autoreconf -i && \
|
||||
./configure --disable-examples --disable-hpack-tools \
|
||||
--disable-python-bindings --with-mruby --with-neverbleed \
|
||||
--with-mruby --with-neverbleed \
|
||||
--enable-http3 --with-libbpf \
|
||||
CC=clang CXX=clang++ \
|
||||
LIBTOOL_LDFLAGS="-static-libtool-libs" \
|
||||
|
|
|
@ -6,15 +6,8 @@
|
|||
# The MIT License apply.
|
||||
#
|
||||
|
||||
#
|
||||
# Choose your weapons:
|
||||
# Set 'USE_CYTHON=1' to build and install the 'nghttp2.pyd' Python extension.
|
||||
#
|
||||
THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||
|
||||
USE_CYTHON := 0
|
||||
#USE_CYTHON := 1
|
||||
|
||||
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV//g' -e 's/], //g')
|
||||
_VERSION := $(subst ., ,$(_VERSION))
|
||||
VER_MAJOR := $(word 1,$(_VERSION))
|
||||
|
@ -102,7 +95,7 @@ NGHTTP2_OBJ_D := $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
|||
clean_nghttp2_pyd_0 clean_nghttp2_pyd_1
|
||||
|
||||
|
||||
all: intro includes/nghttp2/nghttp2ver.h $(OBJ_DIR) $(TARGETS) build_nghttp2_pyd_$(USE_CYTHON)
|
||||
all: intro includes/nghttp2/nghttp2ver.h $(OBJ_DIR) $(TARGETS)
|
||||
@echo 'Welcome to NgHTTP2 (release + debug).'
|
||||
@echo 'Do a "make -f Makefile.MSVC install" at own risk!'
|
||||
|
||||
|
@ -121,7 +114,7 @@ $(OBJ_DIR):
|
|||
|
||||
install: includes/nghttp2/nghttp2.h includes/nghttp2/nghttp2ver.h \
|
||||
$(TARGETS) \
|
||||
copy_headers_and_libs install_nghttp2_pyd_$(USE_CYTHON)
|
||||
copy_headers_and_libs
|
||||
|
||||
#
|
||||
# This MUST be done before using the 'install_nghttp2_pyd_1' rule.
|
||||
|
@ -160,31 +153,6 @@ $(DLL_D): $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res
|
|||
WIN_OBJDIR:=$(shell cygpath -w $(abspath $(OBJ_DIR)))
|
||||
WIN_OBJDIR:=$(subst \,/,$(WIN_OBJDIR))
|
||||
|
||||
../python/setup.py: ../python/setup.py.in $(THIS_MAKEFILE)
|
||||
cd ../python ; \
|
||||
echo '# $(GENERATED). DO NOT EDIT.' > setup.py ; \
|
||||
sed -e 's/@top_srcdir@/../' \
|
||||
-e 's%@top_builddir@%$(WIN_OBJDIR)%' \
|
||||
-e 's/@PACKAGE_VERSION@/$(VERSION)/' setup.py.in >> setup.py ;
|
||||
|
||||
build_nghttp2_pyd_0: ;
|
||||
|
||||
build_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx)
|
||||
cd ../python ; \
|
||||
python setup.py build_ext -i -f bdist_wininst
|
||||
|
||||
install_nghttp2_pyd_0: ;
|
||||
|
||||
install_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx)
|
||||
cd ../python ; \
|
||||
pip install .
|
||||
|
||||
clean_nghttp2_pyd_0: ;
|
||||
|
||||
clean_nghttp2_pyd_1:
|
||||
cd ../python ; \
|
||||
rm -fR build dist
|
||||
|
||||
$(OBJ_DIR)/r_%.obj: %.c $(THIS_MAKEFILE)
|
||||
$(CC) $(CFLAGS_R) $(CFLAGS) -Fo$@ -c $<
|
||||
@echo
|
||||
|
@ -262,7 +230,7 @@ clean:
|
|||
rm -f $(OBJ_DIR)/* includes/nghttp2/nghttp2ver.h
|
||||
@echo
|
||||
|
||||
vclean realclean: clean clean_nghttp2_pyd_$(USE_CYTHON)
|
||||
vclean realclean: clean
|
||||
- rm -rf $(OBJ_DIR)
|
||||
- rm -f .depend.MSVC
|
||||
|
||||
|
|
|
@ -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