first commit
CI / Build (clang, clang++, ubuntu-22.04, linux, 3.10, master, x86,x86_64) (push) Canceled after 0s
CI / Build (clang, clang++, windows-2022, windows, 3.10, master, x86,x86_64) (push) Canceled after 0s
CI / Release (push) Canceled after 0s

This commit is contained in:
2026-09-13 22:18:11 +01:00
commit 08c03ac533
6701 changed files with 1577314 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
if(ENABLE_EXAMPLES)
file(GLOB c_sources *.c)
set_source_files_properties(${c_sources} PROPERTIES
COMPILE_FLAGS "${WARNCFLAGS}")
file(GLOB cxx_sources *.cc)
set_source_files_properties(${cxx_sources} PROPERTIES
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party"
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party/llhttp/include"
${LIBEVENT_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIRS}
)
link_libraries(
nghttp2
${LIBEVENT_OPENSSL_LIBRARIES}
${OPENSSL_LIBRARIES}
${APP_LIBRARIES}
)
add_executable(client client.c $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:url-parser>
)
add_executable(libevent-client libevent-client.c $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:url-parser>
)
add_executable(libevent-server libevent-server.c $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:url-parser>
)
add_executable(deflate deflate.c $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:url-parser>
)
if(ENABLE_ASIO_LIB)
foreach(name asio-sv asio-sv2 asio-cl asio-cl2)
add_executable(${name} ${name}.cc $<TARGET_OBJECTS:llhttp>
$<TARGET_OBJECTS:url-parser>
)
target_include_directories(${name} PRIVATE
${OPENSSL_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
)
target_link_libraries(${name}
nghttp2
nghttp2_asio
${JEMALLOC_LIBRARIES}
${OPENSSL_LIBRARIES}
${Boost_LIBRARIES}
${APP_LIBRARIES}
)
endforeach()
endif()
endif()
+90
View File
@@ -0,0 +1,90 @@
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2012 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
EXTRA_DIST = CMakeLists.txt
if ENABLE_EXAMPLES
AM_CFLAGS = $(WARNCFLAGS)
AM_CXXFLAGS = $(WARNCXXFLAGS) $(CXX1XCXXFLAGS)
AM_CPPFLAGS = \
-I$(top_srcdir)/lib/includes \
-I$(top_builddir)/lib/includes \
-I$(top_srcdir)/src/includes \
-I$(top_srcdir)/third-party \
@LIBEVENT_OPENSSL_CFLAGS@ \
@OPENSSL_CFLAGS@ \
@DEFS@
LDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/third-party/liburl-parser.la \
@LIBEVENT_OPENSSL_LIBS@ \
@OPENSSL_LIBS@ \
@APPLDFLAGS@
noinst_PROGRAMS = client libevent-client libevent-server deflate
client_SOURCES = client.c
libevent_client_SOURCES = libevent-client.c
libevent_server_SOURCES = libevent-server.c
deflate_SOURCES = deflate.c
if ENABLE_ASIO_LIB
noinst_PROGRAMS += asio-sv asio-sv2 asio-cl asio-cl2
# AM_CPPFLAGS must be placed first, so that header file (e.g.,
# nghttp2/nghttp2.h) in this package is used rather than installed
# one.
ASIOCPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
$(top_builddir)/third-party/liburl-parser.la \
@OPENSSL_LIBS@ \
${BOOST_LDFLAGS} \
${BOOST_ASIO_LIB} \
${BOOST_THREAD_LIB} \
${BOOST_SYSTEM_LIB} \
@APPLDFLAGS@
asio_sv_SOURCES = asio-sv.cc
asio_sv_CPPFLAGS = ${ASIOCPPFLAGS}
asio_sv_LDADD = ${ASIOLDADD}
asio_sv2_SOURCES = asio-sv2.cc
asio_sv2_CPPFLAGS = ${ASIOCPPFLAGS}
asio_sv2_LDADD = ${ASIOLDADD}
asio_cl_SOURCES = asio-cl.cc
asio_cl_CPPFLAGS = ${ASIOCPPFLAGS}
asio_cl_LDADD = ${ASIOLDADD}
asio_cl2_SOURCES = asio-cl2.cc
asio_cl2_CPPFLAGS = ${ASIOCPPFLAGS}
asio_cl2_LDADD = ${ASIOLDADD}
endif # ENABLE_ASIO_LIB
endif # ENABLE_EXAMPLES
+956
View File
@@ -0,0 +1,956 @@
# Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
# nghttp2 - HTTP/2 C Library
# Copyright (c) 2012 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.
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
@ENABLE_EXAMPLES_TRUE@noinst_PROGRAMS = client$(EXEEXT) \
@ENABLE_EXAMPLES_TRUE@ libevent-client$(EXEEXT) \
@ENABLE_EXAMPLES_TRUE@ libevent-server$(EXEEXT) \
@ENABLE_EXAMPLES_TRUE@ deflate$(EXEEXT) $(am__EXEEXT_1)
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@am__append_1 = asio-sv asio-sv2 asio-cl asio-cl2
subdir = examples
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_asio.m4 \
$(top_srcdir)/m4/ax_boost_base.m4 \
$(top_srcdir)/m4/ax_boost_system.m4 \
$(top_srcdir)/m4/ax_boost_thread.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
$(top_srcdir)/m4/ax_python_devel.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@am__EXEEXT_1 = \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ asio-sv$(EXEEXT) \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ asio-sv2$(EXEEXT) \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ asio-cl$(EXEEXT) \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ asio-cl2$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
am__asio_cl_SOURCES_DIST = asio-cl.cc
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@am_asio_cl_OBJECTS = asio_cl-asio-cl.$(OBJEXT)
asio_cl_OBJECTS = $(am_asio_cl_OBJECTS)
am__DEPENDENCIES_1 =
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@am__DEPENDENCIES_2 = $(top_builddir)/lib/libnghttp2.la \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/src/libnghttp2_asio.la \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/third-party/liburl-parser.la \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ $(am__DEPENDENCIES_1) \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ $(am__DEPENDENCIES_1) \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ $(am__DEPENDENCIES_1) \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ $(am__DEPENDENCIES_1)
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_cl_DEPENDENCIES = $(am__DEPENDENCIES_2)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
am__asio_cl2_SOURCES_DIST = asio-cl2.cc
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@am_asio_cl2_OBJECTS = asio_cl2-asio-cl2.$(OBJEXT)
asio_cl2_OBJECTS = $(am_asio_cl2_OBJECTS)
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_cl2_DEPENDENCIES = $(am__DEPENDENCIES_2)
am__asio_sv_SOURCES_DIST = asio-sv.cc
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@am_asio_sv_OBJECTS = asio_sv-asio-sv.$(OBJEXT)
asio_sv_OBJECTS = $(am_asio_sv_OBJECTS)
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_sv_DEPENDENCIES = $(am__DEPENDENCIES_2)
am__asio_sv2_SOURCES_DIST = asio-sv2.cc
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@am_asio_sv2_OBJECTS = asio_sv2-asio-sv2.$(OBJEXT)
asio_sv2_OBJECTS = $(am_asio_sv2_OBJECTS)
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_sv2_DEPENDENCIES = $(am__DEPENDENCIES_2)
am__client_SOURCES_DIST = client.c
@ENABLE_EXAMPLES_TRUE@am_client_OBJECTS = client.$(OBJEXT)
client_OBJECTS = $(am_client_OBJECTS)
client_LDADD = $(LDADD)
@ENABLE_EXAMPLES_TRUE@client_DEPENDENCIES = \
@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/lib/libnghttp2.la \
@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/third-party/liburl-parser.la
am__deflate_SOURCES_DIST = deflate.c
@ENABLE_EXAMPLES_TRUE@am_deflate_OBJECTS = deflate.$(OBJEXT)
deflate_OBJECTS = $(am_deflate_OBJECTS)
deflate_LDADD = $(LDADD)
@ENABLE_EXAMPLES_TRUE@deflate_DEPENDENCIES = \
@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/lib/libnghttp2.la \
@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/third-party/liburl-parser.la
am__libevent_client_SOURCES_DIST = libevent-client.c
@ENABLE_EXAMPLES_TRUE@am_libevent_client_OBJECTS = \
@ENABLE_EXAMPLES_TRUE@ libevent-client.$(OBJEXT)
libevent_client_OBJECTS = $(am_libevent_client_OBJECTS)
libevent_client_LDADD = $(LDADD)
@ENABLE_EXAMPLES_TRUE@libevent_client_DEPENDENCIES = \
@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/lib/libnghttp2.la \
@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/third-party/liburl-parser.la
am__libevent_server_SOURCES_DIST = libevent-server.c
@ENABLE_EXAMPLES_TRUE@am_libevent_server_OBJECTS = \
@ENABLE_EXAMPLES_TRUE@ libevent-server.$(OBJEXT)
libevent_server_OBJECTS = $(am_libevent_server_OBJECTS)
libevent_server_LDADD = $(LDADD)
@ENABLE_EXAMPLES_TRUE@libevent_server_DEPENDENCIES = \
@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/lib/libnghttp2.la \
@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/third-party/liburl-parser.la
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/asio_cl-asio-cl.Po \
./$(DEPDIR)/asio_cl2-asio-cl2.Po \
./$(DEPDIR)/asio_sv-asio-sv.Po \
./$(DEPDIR)/asio_sv2-asio-sv2.Po ./$(DEPDIR)/client.Po \
./$(DEPDIR)/deflate.Po ./$(DEPDIR)/libevent-client.Po \
./$(DEPDIR)/libevent-server.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_@AM_V@)
am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
am__v_CXX_0 = @echo " CXX " $@;
am__v_CXX_1 =
CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
am__v_CXXLD_0 = @echo " CXXLD " $@;
am__v_CXXLD_1 =
SOURCES = $(asio_cl_SOURCES) $(asio_cl2_SOURCES) $(asio_sv_SOURCES) \
$(asio_sv2_SOURCES) $(client_SOURCES) $(deflate_SOURCES) \
$(libevent_client_SOURCES) $(libevent_server_SOURCES)
DIST_SOURCES = $(am__asio_cl_SOURCES_DIST) \
$(am__asio_cl2_SOURCES_DIST) $(am__asio_sv_SOURCES_DIST) \
$(am__asio_sv2_SOURCES_DIST) $(am__client_SOURCES_DIST) \
$(am__deflate_SOURCES_DIST) \
$(am__libevent_client_SOURCES_DIST) \
$(am__libevent_server_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPLDFLAGS = @APPLDFLAGS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BOOST_ASIO_LIB = @BOOST_ASIO_LIB@
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
BOOST_LDFLAGS = @BOOST_LDFLAGS@
BOOST_SYSTEM_LIB = @BOOST_SYSTEM_LIB@
BOOST_THREAD_LIB = @BOOST_THREAD_LIB@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CUNIT_CFLAGS = @CUNIT_CFLAGS@
CUNIT_LIBS = @CUNIT_LIBS@
CXX = @CXX@
CXX1XCXXFLAGS = @CXX1XCXXFLAGS@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
CYTHON = @CYTHON@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
EXTRACFLAG = @EXTRACFLAG@
FGREP = @FGREP@
GREP = @GREP@
HAVE_CXX14 = @HAVE_CXX14@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
JANSSON_CFLAGS = @JANSSON_CFLAGS@
JANSSON_LIBS = @JANSSON_LIBS@
JEMALLOC_LIBS = @JEMALLOC_LIBS@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCARES_CFLAGS = @LIBCARES_CFLAGS@
LIBCARES_LIBS = @LIBCARES_LIBS@
LIBEVENT_OPENSSL_CFLAGS = @LIBEVENT_OPENSSL_CFLAGS@
LIBEVENT_OPENSSL_LIBS = @LIBEVENT_OPENSSL_LIBS@
LIBEV_CFLAGS = @LIBEV_CFLAGS@
LIBEV_LIBS = @LIBEV_LIBS@
LIBMRUBY_CFLAGS = @LIBMRUBY_CFLAGS@
LIBMRUBY_LIBS = @LIBMRUBY_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
LIBXML2_LIBS = @LIBXML2_LIBS@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_AGE = @LT_AGE@
LT_CURRENT = @LT_CURRENT@
LT_REVISION = @LT_REVISION@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
OPENSSL_LIBS = @OPENSSL_LIBS@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PACKAGE_VERSION_NUM = @PACKAGE_VERSION_NUM@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PYTHON = @PYTHON@
PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
PYTHON_LIBS = @PYTHON_LIBS@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
PYTHON_VERSION = @PYTHON_VERSION@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
TESTLDADD = @TESTLDADD@
VERSION = @VERSION@
WARNCFLAGS = @WARNCFLAGS@
WARNCXXFLAGS = @WARNCXXFLAGS@
ZLIB_CFLAGS = @ZLIB_CFLAGS@
ZLIB_LIBS = @ZLIB_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
pkgpyexecdir = @pkgpyexecdir@
pkgpythondir = @pkgpythondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
pyexecdir = @pyexecdir@
pythondir = @pythondir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
EXTRA_DIST = CMakeLists.txt
@ENABLE_EXAMPLES_TRUE@AM_CFLAGS = $(WARNCFLAGS)
@ENABLE_EXAMPLES_TRUE@AM_CXXFLAGS = $(WARNCXXFLAGS) $(CXX1XCXXFLAGS)
@ENABLE_EXAMPLES_TRUE@AM_CPPFLAGS = \
@ENABLE_EXAMPLES_TRUE@ -I$(top_srcdir)/lib/includes \
@ENABLE_EXAMPLES_TRUE@ -I$(top_builddir)/lib/includes \
@ENABLE_EXAMPLES_TRUE@ -I$(top_srcdir)/src/includes \
@ENABLE_EXAMPLES_TRUE@ -I$(top_srcdir)/third-party \
@ENABLE_EXAMPLES_TRUE@ @LIBEVENT_OPENSSL_CFLAGS@ \
@ENABLE_EXAMPLES_TRUE@ @OPENSSL_CFLAGS@ \
@ENABLE_EXAMPLES_TRUE@ @DEFS@
@ENABLE_EXAMPLES_TRUE@LDADD = $(top_builddir)/lib/libnghttp2.la \
@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/third-party/liburl-parser.la \
@ENABLE_EXAMPLES_TRUE@ @LIBEVENT_OPENSSL_LIBS@ \
@ENABLE_EXAMPLES_TRUE@ @OPENSSL_LIBS@ \
@ENABLE_EXAMPLES_TRUE@ @APPLDFLAGS@
@ENABLE_EXAMPLES_TRUE@client_SOURCES = client.c
@ENABLE_EXAMPLES_TRUE@libevent_client_SOURCES = libevent-client.c
@ENABLE_EXAMPLES_TRUE@libevent_server_SOURCES = libevent-server.c
@ENABLE_EXAMPLES_TRUE@deflate_SOURCES = deflate.c
# AM_CPPFLAGS must be placed first, so that header file (e.g.,
# nghttp2/nghttp2.h) in this package is used rather than installed
# one.
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ASIOCPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ $(top_builddir)/third-party/liburl-parser.la \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ @OPENSSL_LIBS@ \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ ${BOOST_LDFLAGS} \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ ${BOOST_ASIO_LIB} \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ ${BOOST_THREAD_LIB} \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ ${BOOST_SYSTEM_LIB} \
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@ @APPLDFLAGS@
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_sv_SOURCES = asio-sv.cc
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_sv_CPPFLAGS = ${ASIOCPPFLAGS}
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_sv_LDADD = ${ASIOLDADD}
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_sv2_SOURCES = asio-sv2.cc
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_sv2_CPPFLAGS = ${ASIOCPPFLAGS}
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_sv2_LDADD = ${ASIOLDADD}
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_cl_SOURCES = asio-cl.cc
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_cl_CPPFLAGS = ${ASIOCPPFLAGS}
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_cl_LDADD = ${ASIOLDADD}
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_cl2_SOURCES = asio-cl2.cc
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_cl2_CPPFLAGS = ${ASIOCPPFLAGS}
@ENABLE_ASIO_LIB_TRUE@@ENABLE_EXAMPLES_TRUE@asio_cl2_LDADD = ${ASIOLDADD}
all: all-am
.SUFFIXES:
.SUFFIXES: .c .cc .lo .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu examples/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu examples/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstPROGRAMS:
@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
asio-cl$(EXEEXT): $(asio_cl_OBJECTS) $(asio_cl_DEPENDENCIES) $(EXTRA_asio_cl_DEPENDENCIES)
@rm -f asio-cl$(EXEEXT)
$(AM_V_CXXLD)$(CXXLINK) $(asio_cl_OBJECTS) $(asio_cl_LDADD) $(LIBS)
asio-cl2$(EXEEXT): $(asio_cl2_OBJECTS) $(asio_cl2_DEPENDENCIES) $(EXTRA_asio_cl2_DEPENDENCIES)
@rm -f asio-cl2$(EXEEXT)
$(AM_V_CXXLD)$(CXXLINK) $(asio_cl2_OBJECTS) $(asio_cl2_LDADD) $(LIBS)
asio-sv$(EXEEXT): $(asio_sv_OBJECTS) $(asio_sv_DEPENDENCIES) $(EXTRA_asio_sv_DEPENDENCIES)
@rm -f asio-sv$(EXEEXT)
$(AM_V_CXXLD)$(CXXLINK) $(asio_sv_OBJECTS) $(asio_sv_LDADD) $(LIBS)
asio-sv2$(EXEEXT): $(asio_sv2_OBJECTS) $(asio_sv2_DEPENDENCIES) $(EXTRA_asio_sv2_DEPENDENCIES)
@rm -f asio-sv2$(EXEEXT)
$(AM_V_CXXLD)$(CXXLINK) $(asio_sv2_OBJECTS) $(asio_sv2_LDADD) $(LIBS)
client$(EXEEXT): $(client_OBJECTS) $(client_DEPENDENCIES) $(EXTRA_client_DEPENDENCIES)
@rm -f client$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(client_OBJECTS) $(client_LDADD) $(LIBS)
deflate$(EXEEXT): $(deflate_OBJECTS) $(deflate_DEPENDENCIES) $(EXTRA_deflate_DEPENDENCIES)
@rm -f deflate$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(deflate_OBJECTS) $(deflate_LDADD) $(LIBS)
libevent-client$(EXEEXT): $(libevent_client_OBJECTS) $(libevent_client_DEPENDENCIES) $(EXTRA_libevent_client_DEPENDENCIES)
@rm -f libevent-client$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(libevent_client_OBJECTS) $(libevent_client_LDADD) $(LIBS)
libevent-server$(EXEEXT): $(libevent_server_OBJECTS) $(libevent_server_DEPENDENCIES) $(EXTRA_libevent_server_DEPENDENCIES)
@rm -f libevent-server$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(libevent_server_OBJECTS) $(libevent_server_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asio_cl-asio-cl.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asio_cl2-asio-cl2.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asio_sv-asio-sv.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asio_sv2-asio-sv2.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libevent-client.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libevent-server.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
.cc.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
.cc.obj:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.cc.lo:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
asio_cl-asio-cl.o: asio-cl.cc
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_cl_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asio_cl-asio-cl.o -MD -MP -MF $(DEPDIR)/asio_cl-asio-cl.Tpo -c -o asio_cl-asio-cl.o `test -f 'asio-cl.cc' || echo '$(srcdir)/'`asio-cl.cc
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asio_cl-asio-cl.Tpo $(DEPDIR)/asio_cl-asio-cl.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='asio-cl.cc' object='asio_cl-asio-cl.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_cl_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asio_cl-asio-cl.o `test -f 'asio-cl.cc' || echo '$(srcdir)/'`asio-cl.cc
asio_cl-asio-cl.obj: asio-cl.cc
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_cl_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asio_cl-asio-cl.obj -MD -MP -MF $(DEPDIR)/asio_cl-asio-cl.Tpo -c -o asio_cl-asio-cl.obj `if test -f 'asio-cl.cc'; then $(CYGPATH_W) 'asio-cl.cc'; else $(CYGPATH_W) '$(srcdir)/asio-cl.cc'; fi`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asio_cl-asio-cl.Tpo $(DEPDIR)/asio_cl-asio-cl.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='asio-cl.cc' object='asio_cl-asio-cl.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_cl_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asio_cl-asio-cl.obj `if test -f 'asio-cl.cc'; then $(CYGPATH_W) 'asio-cl.cc'; else $(CYGPATH_W) '$(srcdir)/asio-cl.cc'; fi`
asio_cl2-asio-cl2.o: asio-cl2.cc
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_cl2_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asio_cl2-asio-cl2.o -MD -MP -MF $(DEPDIR)/asio_cl2-asio-cl2.Tpo -c -o asio_cl2-asio-cl2.o `test -f 'asio-cl2.cc' || echo '$(srcdir)/'`asio-cl2.cc
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asio_cl2-asio-cl2.Tpo $(DEPDIR)/asio_cl2-asio-cl2.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='asio-cl2.cc' object='asio_cl2-asio-cl2.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_cl2_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asio_cl2-asio-cl2.o `test -f 'asio-cl2.cc' || echo '$(srcdir)/'`asio-cl2.cc
asio_cl2-asio-cl2.obj: asio-cl2.cc
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_cl2_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asio_cl2-asio-cl2.obj -MD -MP -MF $(DEPDIR)/asio_cl2-asio-cl2.Tpo -c -o asio_cl2-asio-cl2.obj `if test -f 'asio-cl2.cc'; then $(CYGPATH_W) 'asio-cl2.cc'; else $(CYGPATH_W) '$(srcdir)/asio-cl2.cc'; fi`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asio_cl2-asio-cl2.Tpo $(DEPDIR)/asio_cl2-asio-cl2.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='asio-cl2.cc' object='asio_cl2-asio-cl2.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_cl2_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asio_cl2-asio-cl2.obj `if test -f 'asio-cl2.cc'; then $(CYGPATH_W) 'asio-cl2.cc'; else $(CYGPATH_W) '$(srcdir)/asio-cl2.cc'; fi`
asio_sv-asio-sv.o: asio-sv.cc
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_sv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asio_sv-asio-sv.o -MD -MP -MF $(DEPDIR)/asio_sv-asio-sv.Tpo -c -o asio_sv-asio-sv.o `test -f 'asio-sv.cc' || echo '$(srcdir)/'`asio-sv.cc
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asio_sv-asio-sv.Tpo $(DEPDIR)/asio_sv-asio-sv.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='asio-sv.cc' object='asio_sv-asio-sv.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_sv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asio_sv-asio-sv.o `test -f 'asio-sv.cc' || echo '$(srcdir)/'`asio-sv.cc
asio_sv-asio-sv.obj: asio-sv.cc
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_sv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asio_sv-asio-sv.obj -MD -MP -MF $(DEPDIR)/asio_sv-asio-sv.Tpo -c -o asio_sv-asio-sv.obj `if test -f 'asio-sv.cc'; then $(CYGPATH_W) 'asio-sv.cc'; else $(CYGPATH_W) '$(srcdir)/asio-sv.cc'; fi`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asio_sv-asio-sv.Tpo $(DEPDIR)/asio_sv-asio-sv.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='asio-sv.cc' object='asio_sv-asio-sv.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_sv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asio_sv-asio-sv.obj `if test -f 'asio-sv.cc'; then $(CYGPATH_W) 'asio-sv.cc'; else $(CYGPATH_W) '$(srcdir)/asio-sv.cc'; fi`
asio_sv2-asio-sv2.o: asio-sv2.cc
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_sv2_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asio_sv2-asio-sv2.o -MD -MP -MF $(DEPDIR)/asio_sv2-asio-sv2.Tpo -c -o asio_sv2-asio-sv2.o `test -f 'asio-sv2.cc' || echo '$(srcdir)/'`asio-sv2.cc
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asio_sv2-asio-sv2.Tpo $(DEPDIR)/asio_sv2-asio-sv2.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='asio-sv2.cc' object='asio_sv2-asio-sv2.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_sv2_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asio_sv2-asio-sv2.o `test -f 'asio-sv2.cc' || echo '$(srcdir)/'`asio-sv2.cc
asio_sv2-asio-sv2.obj: asio-sv2.cc
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_sv2_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asio_sv2-asio-sv2.obj -MD -MP -MF $(DEPDIR)/asio_sv2-asio-sv2.Tpo -c -o asio_sv2-asio-sv2.obj `if test -f 'asio-sv2.cc'; then $(CYGPATH_W) 'asio-sv2.cc'; else $(CYGPATH_W) '$(srcdir)/asio-sv2.cc'; fi`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asio_sv2-asio-sv2.Tpo $(DEPDIR)/asio_sv2-asio-sv2.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='asio-sv2.cc' object='asio_sv2-asio-sv2.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asio_sv2_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asio_sv2-asio-sv2.obj `if test -f 'asio-sv2.cc'; then $(CYGPATH_W) 'asio-sv2.cc'; else $(CYGPATH_W) '$(srcdir)/asio-sv2.cc'; fi`
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/asio_cl-asio-cl.Po
-rm -f ./$(DEPDIR)/asio_cl2-asio-cl2.Po
-rm -f ./$(DEPDIR)/asio_sv-asio-sv.Po
-rm -f ./$(DEPDIR)/asio_sv2-asio-sv2.Po
-rm -f ./$(DEPDIR)/client.Po
-rm -f ./$(DEPDIR)/deflate.Po
-rm -f ./$(DEPDIR)/libevent-client.Po
-rm -f ./$(DEPDIR)/libevent-server.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/asio_cl-asio-cl.Po
-rm -f ./$(DEPDIR)/asio_cl2-asio-cl2.Po
-rm -f ./$(DEPDIR)/asio_sv-asio-sv.Po
-rm -f ./$(DEPDIR)/asio_sv2-asio-sv2.Po
-rm -f ./$(DEPDIR)/client.Po
-rm -f ./$(DEPDIR)/deflate.Po
-rm -f ./$(DEPDIR)/libevent-client.Po
-rm -f ./$(DEPDIR)/libevent-server.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am:
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \
ctags ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
+96
View File
@@ -0,0 +1,96 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2015 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <iostream>
#include <nghttp2/asio_http2_client.h>
using boost::asio::ip::tcp;
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::client;
int main(int argc, char *argv[]) {
try {
if (argc < 2) {
std::cerr << "Usage: asio-cl URI" << std::endl;
return 1;
}
boost::system::error_code ec;
boost::asio::io_service io_service;
std::string uri = argv[1];
std::string scheme, host, service;
if (host_service_from_uri(ec, scheme, host, service, uri)) {
std::cerr << "error: bad URI: " << ec.message() << std::endl;
return 1;
}
boost::asio::ssl::context tls_ctx(boost::asio::ssl::context::sslv23);
tls_ctx.set_default_verify_paths();
// disabled to make development easier...
// tls_ctx.set_verify_mode(boost::asio::ssl::verify_peer);
configure_tls_context(ec, tls_ctx);
auto sess = scheme == "https" ? session(io_service, tls_ctx, host, service)
: session(io_service, host, service);
sess.on_connect([&sess, &uri](tcp::resolver::iterator endpoint_it) {
boost::system::error_code ec;
auto req = sess.submit(ec, "GET", uri);
if (ec) {
std::cerr << "error: " << ec.message() << std::endl;
return;
}
req->on_response([](const response &res) {
std::cerr << "HTTP/2 " << res.status_code() << std::endl;
for (auto &kv : res.header()) {
std::cerr << kv.first << ": " << kv.second.value << "\n";
}
std::cerr << std::endl;
res.on_data([](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
});
req->on_close([&sess](uint32_t error_code) { sess.shutdown(); });
});
sess.on_error([](const boost::system::error_code &ec) {
std::cerr << "error: " << ec.message() << std::endl;
});
io_service.run();
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}
+134
View File
@@ -0,0 +1,134 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2015 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <iostream>
#include <string>
#include <nghttp2/asio_http2_client.h>
using boost::asio::ip::tcp;
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::client;
void print_header(const header_map &h) {
for (auto &kv : h) {
std::cerr << kv.first << ": " << kv.second.value << "\n";
}
std::cerr << std::endl;
}
void print_header(const response &res) {
std::cerr << "HTTP/2 " << res.status_code() << "\n";
print_header(res.header());
}
void print_header(const request &req) {
auto &uri = req.uri();
std::cerr << req.method() << " " << uri.scheme << "://" << uri.host
<< uri.path;
if (!uri.raw_query.empty()) {
std::cerr << "?" << uri.raw_query;
}
std::cerr << " HTTP/2\n";
print_header(req.header());
}
int main(int argc, char *argv[]) {
try {
if (argc < 2) {
std::cerr << "Usage: asio-cl URI" << std::endl;
return 1;
}
boost::system::error_code ec;
boost::asio::io_service io_service;
std::string uri = argv[1];
std::string scheme, host, service;
if (host_service_from_uri(ec, scheme, host, service, uri)) {
std::cerr << "error: bad URI: " << ec.message() << std::endl;
return 1;
}
boost::asio::ssl::context tls_ctx(boost::asio::ssl::context::sslv23);
tls_ctx.set_default_verify_paths();
// disabled to make development easier...
// tls_ctx.set_verify_mode(boost::asio::ssl::verify_peer);
configure_tls_context(ec, tls_ctx);
auto sess = scheme == "https" ? session(io_service, tls_ctx, host, service)
: session(io_service, host, service);
sess.on_connect([&sess, &uri](tcp::resolver::iterator endpoint_it) {
std::cerr << "connected to " << (*endpoint_it).endpoint() << std::endl;
boost::system::error_code ec;
auto req = sess.submit(ec, "GET", uri, {{"cookie", {"foo=bar", true}}});
if (ec) {
std::cerr << "error: " << ec.message() << std::endl;
return;
}
req->on_response([](const response &res) {
std::cerr << "response header was received" << std::endl;
print_header(res);
res.on_data([](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
});
req->on_close([](uint32_t error_code) {
std::cerr << "request done with error_code=" << error_code << std::endl;
});
req->on_push([](const request &push_req) {
std::cerr << "push request was received" << std::endl;
print_header(push_req);
push_req.on_response([](const response &res) {
std::cerr << "push response header was received" << std::endl;
res.on_data([](const uint8_t *data, std::size_t len) {
std::cerr.write(reinterpret_cast<const char *>(data), len);
std::cerr << std::endl;
});
});
});
});
sess.on_error([](const boost::system::error_code &ec) {
std::cerr << "error: " << ec.message() << std::endl;
});
io_service.run();
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}
+149
View File
@@ -0,0 +1,149 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// We wrote this code based on the original code which has the
// following license:
//
// main.cpp
// ~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <iostream>
#include <string>
#include <nghttp2/asio_http2_server.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
try {
// Check command line arguments.
if (argc < 4) {
std::cerr
<< "Usage: asio-sv <address> <port> <threads> [<private-key-file> "
<< "<cert-file>]\n";
return 1;
}
boost::system::error_code ec;
std::string addr = argv[1];
std::string port = argv[2];
std::size_t num_threads = std::stoi(argv[3]);
http2 server;
server.num_threads(num_threads);
server.handle("/", [](const request &req, const response &res) {
res.write_head(200, {{"foo", {"bar"}}});
res.end("hello, world\n");
});
server.handle("/secret/", [](const request &req, const response &res) {
res.write_head(200);
res.end("under construction!\n");
});
server.handle("/push", [](const request &req, const response &res) {
boost::system::error_code ec;
auto push = res.push(ec, "GET", "/push/1");
if (!ec) {
push->write_head(200);
push->end("server push FTW!\n");
}
res.write_head(200);
res.end("you'll receive server push!\n");
});
server.handle("/delay", [](const request &req, const response &res) {
res.write_head(200);
auto timer = std::make_shared<boost::asio::deadline_timer>(
res.io_service(), boost::posix_time::seconds(3));
auto closed = std::make_shared<bool>();
res.on_close([timer, closed](uint32_t error_code) {
timer->cancel();
*closed = true;
});
timer->async_wait([&res, closed](const boost::system::error_code &ec) {
if (ec || *closed) {
return;
}
res.end("finally!\n");
});
});
server.handle("/trailer", [](const request &req, const response &res) {
// send trailer part.
res.write_head(200, {{"trailers", {"digest"}}});
std::string body = "nghttp2 FTW!\n";
auto left = std::make_shared<size_t>(body.size());
res.end([&res, body, left](uint8_t *dst, std::size_t len,
uint32_t *data_flags) {
auto n = std::min(len, *left);
std::copy_n(body.c_str() + (body.size() - *left), n, dst);
*left -= n;
if (*left == 0) {
*data_flags |=
NGHTTP2_DATA_FLAG_EOF | NGHTTP2_DATA_FLAG_NO_END_STREAM;
// RFC 3230 Instance Digests in HTTP. The digest value is
// SHA-256 message digest of body.
res.write_trailer(
{{"digest",
{"SHA-256=qqXqskW7F3ueBSvmZRCiSwl2ym4HRO0M/pvQCBlSDis="}}});
}
return n;
});
});
if (argc >= 6) {
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
tls.use_private_key_file(argv[4], boost::asio::ssl::context::pem);
tls.use_certificate_chain_file(argv[5]);
configure_tls_context_easy(ec, tls);
if (server.listen_and_serve(ec, tls, addr, port)) {
std::cerr << "error: " << ec.message() << std::endl;
}
} else {
if (server.listen_and_serve(ec, addr, port)) {
std::cerr << "error: " << ec.message() << std::endl;
}
}
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}
+125
View File
@@ -0,0 +1,125 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// We wrote this code based on the original code which has the
// following license:
//
// main.cpp
// ~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif // HAVE_UNISTD_H
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif // HAVE_FCNTL_H
#include <iostream>
#include <string>
#include <nghttp2/asio_http2_server.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char *argv[]) {
try {
// Check command line arguments.
if (argc < 5) {
std::cerr << "Usage: asio-sv2 <address> <port> <threads> <doc-root> "
<< "[<private-key-file> <cert-file>]\n";
return 1;
}
boost::system::error_code ec;
std::string addr = argv[1];
std::string port = argv[2];
std::size_t num_threads = std::stoi(argv[3]);
std::string docroot = argv[4];
http2 server;
server.num_threads(num_threads);
server.handle("/", [&docroot](const request &req, const response &res) {
auto path = percent_decode(req.uri().path);
if (!check_path(path)) {
res.write_head(404);
res.end();
return;
}
if (path == "/") {
path = "/index.html";
}
path = docroot + path;
auto fd = open(path.c_str(), O_RDONLY);
if (fd == -1) {
res.write_head(404);
res.end();
return;
}
auto header = header_map();
struct stat stbuf;
if (stat(path.c_str(), &stbuf) == 0) {
header.emplace("content-length",
header_value{std::to_string(stbuf.st_size)});
header.emplace("last-modified",
header_value{http_date(stbuf.st_mtime)});
}
res.write_head(200, std::move(header));
res.end(file_generator_from_fd(fd));
});
if (argc >= 7) {
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
tls.use_private_key_file(argv[5], boost::asio::ssl::context::pem);
tls.use_certificate_chain_file(argv[6]);
configure_tls_context_easy(ec, tls);
if (server.listen_and_serve(ec, tls, addr, port)) {
std::cerr << "error: " << ec.message() << std::endl;
}
} else {
if (server.listen_and_serve(ec, addr, port)) {
std::cerr << "error: " << ec.message() << std::endl;
}
}
} catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n";
}
return 0;
}
+727
View File
@@ -0,0 +1,727 @@
/*
* 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 program is written to show how to use nghttp2 API in C and
* intentionally made simple.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <inttypes.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif /* HAVE_NETDB_H */
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <nghttp2/nghttp2.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/conf.h>
enum { IO_NONE, WANT_READ, WANT_WRITE };
#define MAKE_NV(NAME, VALUE) \
{ \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
#define MAKE_NV_CS(NAME, VALUE) \
{ \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, strlen(VALUE), \
NGHTTP2_NV_FLAG_NONE \
}
struct Connection {
SSL *ssl;
nghttp2_session *session;
/* WANT_READ if SSL/TLS connection needs more input; or WANT_WRITE
if it needs more output; or IO_NONE. This is necessary because
SSL/TLS re-negotiation is possible at any time. nghttp2 API
offers similar functions like nghttp2_session_want_read() and
nghttp2_session_want_write() but they do not take into account
SSL/TSL connection. */
int want_io;
};
struct Request {
char *host;
/* In this program, path contains query component as well. */
char *path;
/* This is the concatenation of host and port with ":" in
between. */
char *hostport;
/* Stream ID for this request. */
int32_t stream_id;
uint16_t port;
};
struct URI {
const char *host;
/* In this program, path contains query component as well. */
const char *path;
size_t pathlen;
const char *hostport;
size_t hostlen;
size_t hostportlen;
uint16_t port;
};
/*
* Returns copy of string |s| with the length |len|. The returned
* string is NULL-terminated.
*/
static char *strcopy(const char *s, size_t len) {
char *dst;
dst = malloc(len + 1);
memcpy(dst, s, len);
dst[len] = '\0';
return dst;
}
/*
* Prints error message |msg| and exit.
*/
NGHTTP2_NORETURN
static void die(const char *msg) {
fprintf(stderr, "FATAL: %s\n", msg);
exit(EXIT_FAILURE);
}
/*
* Prints error containing the function name |func| and message |msg|
* and exit.
*/
NGHTTP2_NORETURN
static void dief(const char *func, const char *msg) {
fprintf(stderr, "FATAL: %s: %s\n", func, msg);
exit(EXIT_FAILURE);
}
/*
* Prints error containing the function name |func| and error code
* |error_code| and exit.
*/
NGHTTP2_NORETURN
static void diec(const char *func, int error_code) {
fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,
nghttp2_strerror(error_code));
exit(EXIT_FAILURE);
}
/*
* The implementation of nghttp2_send_callback type. Here we write
* |data| with size |length| to the network and return the number of
* bytes actually written. See the documentation of
* nghttp2_send_callback for the details.
*/
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
size_t length, int flags, void *user_data) {
struct Connection *connection;
int rv;
(void)session;
(void)flags;
connection = (struct Connection *)user_data;
connection->want_io = IO_NONE;
ERR_clear_error();
rv = SSL_write(connection->ssl, data, (int)length);
if (rv <= 0) {
int err = SSL_get_error(connection->ssl, rv);
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
connection->want_io =
(err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);
rv = NGHTTP2_ERR_WOULDBLOCK;
} else {
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
return rv;
}
/*
* The implementation of nghttp2_recv_callback type. Here we read data
* from the network and write them in |buf|. The capacity of |buf| is
* |length| bytes. Returns the number of bytes stored in |buf|. See
* the documentation of nghttp2_recv_callback for the details.
*/
static ssize_t recv_callback(nghttp2_session *session, uint8_t *buf,
size_t length, int flags, void *user_data) {
struct Connection *connection;
int rv;
(void)session;
(void)flags;
connection = (struct Connection *)user_data;
connection->want_io = IO_NONE;
ERR_clear_error();
rv = SSL_read(connection->ssl, buf, (int)length);
if (rv < 0) {
int err = SSL_get_error(connection->ssl, rv);
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
connection->want_io =
(err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);
rv = NGHTTP2_ERR_WOULDBLOCK;
} else {
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
}
} else if (rv == 0) {
rv = NGHTTP2_ERR_EOF;
}
return rv;
}
static int on_frame_send_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data) {
size_t i;
(void)user_data;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if (nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
const nghttp2_nv *nva = frame->headers.nva;
printf("[INFO] C ----------------------------> S (HEADERS)\n");
for (i = 0; i < frame->headers.nvlen; ++i) {
fwrite(nva[i].name, 1, nva[i].namelen, stdout);
printf(": ");
fwrite(nva[i].value, 1, nva[i].valuelen, stdout);
printf("\n");
}
}
break;
case NGHTTP2_RST_STREAM:
printf("[INFO] C ----------------------------> S (RST_STREAM)\n");
break;
case NGHTTP2_GOAWAY:
printf("[INFO] C ----------------------------> S (GOAWAY)\n");
break;
}
return 0;
}
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data) {
size_t i;
(void)user_data;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
const nghttp2_nv *nva = frame->headers.nva;
struct Request *req;
req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (req) {
printf("[INFO] C <---------------------------- S (HEADERS)\n");
for (i = 0; i < frame->headers.nvlen; ++i) {
fwrite(nva[i].name, 1, nva[i].namelen, stdout);
printf(": ");
fwrite(nva[i].value, 1, nva[i].valuelen, stdout);
printf("\n");
}
}
}
break;
case NGHTTP2_RST_STREAM:
printf("[INFO] C <---------------------------- S (RST_STREAM)\n");
break;
case NGHTTP2_GOAWAY:
printf("[INFO] C <---------------------------- S (GOAWAY)\n");
break;
}
return 0;
}
/*
* The implementation of nghttp2_on_stream_close_callback type. We use
* this function to know the response is fully received. Since we just
* fetch 1 resource in this program, after reception of the response,
* we submit GOAWAY and close the session.
*/
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *user_data) {
struct Request *req;
(void)error_code;
(void)user_data;
req = nghttp2_session_get_stream_user_data(session, stream_id);
if (req) {
int rv;
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
if (rv != 0) {
diec("nghttp2_session_terminate_session", rv);
}
}
return 0;
}
/*
* The implementation of nghttp2_on_data_chunk_recv_callback type. We
* use this function to print the received response body.
*/
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
int32_t stream_id, const uint8_t *data,
size_t len, void *user_data) {
struct Request *req;
(void)flags;
(void)user_data;
req = nghttp2_session_get_stream_user_data(session, stream_id);
if (req) {
printf("[INFO] C <---------------------------- S (DATA chunk)\n"
"%lu bytes\n",
(unsigned long int)len);
fwrite(data, 1, len, stdout);
printf("\n");
}
return 0;
}
/*
* Setup callback functions. nghttp2 API offers many callback
* functions, but most of them are optional. The send_callback is
* always required. Since we use nghttp2_session_recv(), the
* recv_callback is also required.
*/
static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback);
nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
on_frame_send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
callbacks, on_data_chunk_recv_callback);
}
#ifndef OPENSSL_NO_NEXTPROTONEG
/*
* Callback function for TLS NPN. Since this program only supports
* HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2
* library supports, we terminate program.
*/
static int select_next_proto_cb(SSL *ssl, unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg) {
int rv;
(void)ssl;
(void)arg;
/* nghttp2_select_next_protocol() selects HTTP/2 protocol the
nghttp2 library supports. */
rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
if (rv <= 0) {
die("Server did not advertise HTTP/2 protocol");
}
return SSL_TLSEXT_ERR_OK;
}
#endif /* !OPENSSL_NO_NEXTPROTONEG */
/*
* Setup SSL/TLS context.
*/
static void init_ssl_ctx(SSL_CTX *ssl_ctx) {
/* Disable SSLv2 and enable all workarounds for buggy servers */
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
/* Set NPN callback */
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
}
static void ssl_handshake(SSL *ssl, int fd) {
int rv;
if (SSL_set_fd(ssl, fd) == 0) {
dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));
}
ERR_clear_error();
rv = SSL_connect(ssl);
if (rv <= 0) {
dief("SSL_connect", ERR_error_string(ERR_get_error(), NULL));
}
}
/*
* Connects to the host |host| and port |port|. This function returns
* the file descriptor of the client socket.
*/
static int connect_to(const char *host, uint16_t port) {
struct addrinfo hints;
int fd = -1;
int rv;
char service[NI_MAXSERV];
struct addrinfo *res, *rp;
snprintf(service, sizeof(service), "%u", port);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
rv = getaddrinfo(host, service, &hints, &res);
if (rv != 0) {
dief("getaddrinfo", gai_strerror(rv));
}
for (rp = res; rp; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (fd == -1) {
continue;
}
while ((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
errno == EINTR)
;
if (rv == 0) {
break;
}
close(fd);
fd = -1;
}
freeaddrinfo(res);
return fd;
}
static void make_non_block(int fd) {
int flags, rv;
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
;
if (flags == -1) {
dief("fcntl", strerror(errno));
}
while ((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
;
if (rv == -1) {
dief("fcntl", strerror(errno));
}
}
static void set_tcp_nodelay(int fd) {
int val = 1;
int rv;
rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
if (rv == -1) {
dief("setsockopt", strerror(errno));
}
}
/*
* Update |pollfd| based on the state of |connection|.
*/
static void ctl_poll(struct pollfd *pollfd, struct Connection *connection) {
pollfd->events = 0;
if (nghttp2_session_want_read(connection->session) ||
connection->want_io == WANT_READ) {
pollfd->events |= POLLIN;
}
if (nghttp2_session_want_write(connection->session) ||
connection->want_io == WANT_WRITE) {
pollfd->events |= POLLOUT;
}
}
/*
* Submits the request |req| to the connection |connection|. This
* function does not send packets; just append the request to the
* internal queue in |connection->session|.
*/
static void submit_request(struct Connection *connection, struct Request *req) {
int32_t stream_id;
/* Make sure that the last item is NULL */
const nghttp2_nv nva[] = {MAKE_NV(":method", "GET"),
MAKE_NV_CS(":path", req->path),
MAKE_NV(":scheme", "https"),
MAKE_NV_CS(":authority", req->hostport),
MAKE_NV("accept", "*/*"),
MAKE_NV("user-agent", "nghttp2/" NGHTTP2_VERSION)};
stream_id = nghttp2_submit_request(connection->session, NULL, nva,
sizeof(nva) / sizeof(nva[0]), NULL, req);
if (stream_id < 0) {
diec("nghttp2_submit_request", stream_id);
}
req->stream_id = stream_id;
printf("[INFO] Stream ID = %d\n", stream_id);
}
/*
* Performs the network I/O.
*/
static void exec_io(struct Connection *connection) {
int rv;
rv = nghttp2_session_recv(connection->session);
if (rv != 0) {
diec("nghttp2_session_recv", rv);
}
rv = nghttp2_session_send(connection->session);
if (rv != 0) {
diec("nghttp2_session_send", rv);
}
}
static void request_init(struct Request *req, const struct URI *uri) {
req->host = strcopy(uri->host, uri->hostlen);
req->port = uri->port;
req->path = strcopy(uri->path, uri->pathlen);
req->hostport = strcopy(uri->hostport, uri->hostportlen);
req->stream_id = -1;
}
static void request_free(struct Request *req) {
free(req->host);
free(req->path);
free(req->hostport);
}
/*
* Fetches the resource denoted by |uri|.
*/
static void fetch_uri(const struct URI *uri) {
nghttp2_session_callbacks *callbacks;
int fd;
SSL_CTX *ssl_ctx;
SSL *ssl;
struct Request req;
struct Connection connection;
int rv;
nfds_t npollfds = 1;
struct pollfd pollfds[1];
request_init(&req, uri);
/* Establish connection and setup SSL */
fd = connect_to(req.host, req.port);
if (fd == -1) {
die("Could not open file descriptor");
}
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (ssl_ctx == NULL) {
dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
}
init_ssl_ctx(ssl_ctx);
ssl = SSL_new(ssl_ctx);
if (ssl == NULL) {
dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
}
/* To simplify the program, we perform SSL/TLS handshake in blocking
I/O. */
ssl_handshake(ssl, fd);
connection.ssl = ssl;
connection.want_io = IO_NONE;
/* Here make file descriptor non-block */
make_non_block(fd);
set_tcp_nodelay(fd);
printf("[INFO] SSL/TLS handshake completed\n");
rv = nghttp2_session_callbacks_new(&callbacks);
if (rv != 0) {
diec("nghttp2_session_callbacks_new", rv);
}
setup_nghttp2_callbacks(callbacks);
rv = nghttp2_session_client_new(&connection.session, callbacks, &connection);
nghttp2_session_callbacks_del(callbacks);
if (rv != 0) {
diec("nghttp2_session_client_new", rv);
}
rv = nghttp2_submit_settings(connection.session, NGHTTP2_FLAG_NONE, NULL, 0);
if (rv != 0) {
diec("nghttp2_submit_settings", rv);
}
/* Submit the HTTP request to the outbound queue. */
submit_request(&connection, &req);
pollfds[0].fd = fd;
ctl_poll(pollfds, &connection);
/* Event loop */
while (nghttp2_session_want_read(connection.session) ||
nghttp2_session_want_write(connection.session)) {
int nfds = poll(pollfds, npollfds, -1);
if (nfds == -1) {
dief("poll", strerror(errno));
}
if (pollfds[0].revents & (POLLIN | POLLOUT)) {
exec_io(&connection);
}
if ((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
die("Connection error");
}
ctl_poll(pollfds, &connection);
}
/* Resource cleanup */
nghttp2_session_del(connection.session);
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ssl_ctx);
shutdown(fd, SHUT_WR);
close(fd);
request_free(&req);
}
static int parse_uri(struct URI *res, const char *uri) {
/* We only interested in https */
size_t len, i, offset;
int ipv6addr = 0;
memset(res, 0, sizeof(struct URI));
len = strlen(uri);
if (len < 9 || memcmp("https://", uri, 8) != 0) {
return -1;
}
offset = 8;
res->host = res->hostport = &uri[offset];
res->hostlen = 0;
if (uri[offset] == '[') {
/* IPv6 literal address */
++offset;
++res->host;
ipv6addr = 1;
for (i = offset; i < len; ++i) {
if (uri[i] == ']') {
res->hostlen = i - offset;
offset = i + 1;
break;
}
}
} else {
const char delims[] = ":/?#";
for (i = offset; i < len; ++i) {
if (strchr(delims, uri[i]) != NULL) {
break;
}
}
res->hostlen = i - offset;
offset = i;
}
if (res->hostlen == 0) {
return -1;
}
/* Assuming https */
res->port = 443;
if (offset < len) {
if (uri[offset] == ':') {
/* port */
const char delims[] = "/?#";
int port = 0;
++offset;
for (i = offset; i < len; ++i) {
if (strchr(delims, uri[i]) != NULL) {
break;
}
if ('0' <= uri[i] && uri[i] <= '9') {
port *= 10;
port += uri[i] - '0';
if (port > 65535) {
return -1;
}
} else {
return -1;
}
}
if (port == 0) {
return -1;
}
offset = i;
res->port = (uint16_t)port;
}
}
res->hostportlen = (size_t)(uri + offset + ipv6addr - res->host);
for (i = offset; i < len; ++i) {
if (uri[i] == '#') {
break;
}
}
if (i - offset == 0) {
res->path = "/";
res->pathlen = 1;
} else {
res->path = &uri[offset];
res->pathlen = i - offset;
}
return 0;
}
int main(int argc, char **argv) {
struct URI uri;
struct sigaction act;
int rv;
if (argc < 2) {
die("Specify a https URI");
}
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, 0);
SSL_load_error_strings();
SSL_library_init();
rv = parse_uri(&uri, argv[1]);
if (rv != 0) {
die("parse_uri failed");
}
fetch_uri(&uri);
return EXIT_SUCCESS;
}
+206
View File
@@ -0,0 +1,206 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* !HAVE_CONFIG_H */
#include <stdio.h>
#include <string.h>
#include <nghttp2/nghttp2.h>
#define MAKE_NV(K, V) \
{ \
(uint8_t *)K, (uint8_t *)V, sizeof(K) - 1, sizeof(V) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
static void deflate(nghttp2_hd_deflater *deflater,
nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva,
size_t nvlen);
static int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
size_t inlen, int final);
int main() {
int rv;
nghttp2_hd_deflater *deflater;
nghttp2_hd_inflater *inflater;
/* Define 1st header set. This is looks like a HTTP request. */
nghttp2_nv nva1[] = {
MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "example.org"),
MAKE_NV(":path", "/"), MAKE_NV("user-agent", "libnghttp2"),
MAKE_NV("accept-encoding", "gzip, deflate")};
/* Define 2nd header set */
nghttp2_nv nva2[] = {MAKE_NV(":scheme", "https"),
MAKE_NV(":authority", "example.org"),
MAKE_NV(":path", "/stylesheet/style.css"),
MAKE_NV("user-agent", "libnghttp2"),
MAKE_NV("accept-encoding", "gzip, deflate"),
MAKE_NV("referer", "https://example.org")};
rv = nghttp2_hd_deflate_new(&deflater, 4096);
if (rv != 0) {
fprintf(stderr, "nghttp2_hd_deflate_init failed with error: %s\n",
nghttp2_strerror(rv));
exit(EXIT_FAILURE);
}
rv = nghttp2_hd_inflate_new(&inflater);
if (rv != 0) {
fprintf(stderr, "nghttp2_hd_inflate_init failed with error: %s\n",
nghttp2_strerror(rv));
exit(EXIT_FAILURE);
}
/* Encode and decode 1st header set */
deflate(deflater, inflater, nva1, sizeof(nva1) / sizeof(nva1[0]));
/* Encode and decode 2nd header set, using differential encoding
using state after encoding 1st header set. */
deflate(deflater, inflater, nva2, sizeof(nva2) / sizeof(nva2[0]));
nghttp2_hd_inflate_del(inflater);
nghttp2_hd_deflate_del(deflater);
return 0;
}
static void deflate(nghttp2_hd_deflater *deflater,
nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva,
size_t nvlen) {
ssize_t rv;
uint8_t *buf;
size_t buflen;
size_t outlen;
size_t i;
size_t sum;
sum = 0;
for (i = 0; i < nvlen; ++i) {
sum += nva[i].namelen + nva[i].valuelen;
}
printf("Input (%zu byte(s)):\n\n", sum);
for (i = 0; i < nvlen; ++i) {
fwrite(nva[i].name, 1, nva[i].namelen, stdout);
printf(": ");
fwrite(nva[i].value, 1, nva[i].valuelen, stdout);
printf("\n");
}
buflen = nghttp2_hd_deflate_bound(deflater, nva, nvlen);
buf = malloc(buflen);
rv = nghttp2_hd_deflate_hd(deflater, buf, buflen, nva, nvlen);
if (rv < 0) {
fprintf(stderr, "nghttp2_hd_deflate_hd() failed with error: %s\n",
nghttp2_strerror((int)rv));
free(buf);
exit(EXIT_FAILURE);
}
outlen = (size_t)rv;
printf("\nDeflate (%zu byte(s), ratio %.02f):\n\n", outlen,
sum == 0 ? 0 : (double)outlen / (double)sum);
for (i = 0; i < outlen; ++i) {
if ((i & 0x0fu) == 0) {
printf("%08zX: ", i);
}
printf("%02X ", buf[i]);
if (((i + 1) & 0x0fu) == 0) {
printf("\n");
}
}
printf("\n\nInflate:\n\n");
/* We pass 1 to final parameter, because buf contains whole deflated
header data. */
rv = inflate_header_block(inflater, buf, outlen, 1);
if (rv != 0) {
free(buf);
exit(EXIT_FAILURE);
}
printf("\n-----------------------------------------------------------"
"--------------------\n");
free(buf);
}
int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
size_t inlen, int final) {
ssize_t rv;
for (;;) {
nghttp2_nv nv;
int inflate_flags = 0;
size_t proclen;
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, in, inlen, final);
if (rv < 0) {
fprintf(stderr, "inflate failed with error code %zd", rv);
return -1;
}
proclen = (size_t)rv;
in += proclen;
inlen -= proclen;
if (inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
fwrite(nv.name, 1, nv.namelen, stderr);
fprintf(stderr, ": ");
fwrite(nv.value, 1, nv.valuelen, stderr);
fprintf(stderr, "\n");
}
if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
nghttp2_hd_inflate_end_headers(inflater);
break;
}
if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
break;
}
}
return 0;
}
+625
View File
@@ -0,0 +1,625 @@
/*
* 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.
*/
#ifdef __sgi
# include <string.h>
# define errx(exitcode, format, args...) \
{ \
warnx(format, ##args); \
exit(exitcode); \
}
# define warnx(format, args...) fprintf(stderr, format "\n", ##args)
char *strndup(const char *s, size_t size);
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h>
#ifndef __sgi
# include <err.h>
#endif
#include <signal.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <event.h>
#include <event2/event.h>
#include <event2/bufferevent_ssl.h>
#include <event2/dns.h>
#include <nghttp2/nghttp2.h>
#include "url-parser/url_parser.h"
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
typedef struct {
/* The NULL-terminated URI string to retrieve. */
const char *uri;
/* Parsed result of the |uri| */
struct http_parser_url *u;
/* The authority portion of the |uri|, not NULL-terminated */
char *authority;
/* The path portion of the |uri|, including query, not
NULL-terminated */
char *path;
/* The length of the |authority| */
size_t authoritylen;
/* The length of the |path| */
size_t pathlen;
/* The stream ID of this stream */
int32_t stream_id;
} http2_stream_data;
typedef struct {
nghttp2_session *session;
struct evdns_base *dnsbase;
struct bufferevent *bev;
http2_stream_data *stream_data;
} http2_session_data;
static http2_stream_data *create_http2_stream_data(const char *uri,
struct http_parser_url *u) {
/* MAX 5 digits (max 65535) + 1 ':' + 1 NULL (because of snprintf) */
size_t extra = 7;
http2_stream_data *stream_data = malloc(sizeof(http2_stream_data));
stream_data->uri = uri;
stream_data->u = u;
stream_data->stream_id = -1;
stream_data->authoritylen = u->field_data[UF_HOST].len;
stream_data->authority = malloc(stream_data->authoritylen + extra);
memcpy(stream_data->authority, &uri[u->field_data[UF_HOST].off],
u->field_data[UF_HOST].len);
if (u->field_set & (1 << UF_PORT)) {
stream_data->authoritylen +=
(size_t)snprintf(stream_data->authority + u->field_data[UF_HOST].len,
extra, ":%u", u->port);
}
/* If we don't have path in URI, we use "/" as path. */
stream_data->pathlen = 1;
if (u->field_set & (1 << UF_PATH)) {
stream_data->pathlen = u->field_data[UF_PATH].len;
}
if (u->field_set & (1 << UF_QUERY)) {
/* +1 for '?' character */
stream_data->pathlen += (size_t)(u->field_data[UF_QUERY].len + 1);
}
stream_data->path = malloc(stream_data->pathlen);
if (u->field_set & (1 << UF_PATH)) {
memcpy(stream_data->path, &uri[u->field_data[UF_PATH].off],
u->field_data[UF_PATH].len);
} else {
stream_data->path[0] = '/';
}
if (u->field_set & (1 << UF_QUERY)) {
stream_data->path[stream_data->pathlen - u->field_data[UF_QUERY].len - 1] =
'?';
memcpy(stream_data->path + stream_data->pathlen -
u->field_data[UF_QUERY].len,
&uri[u->field_data[UF_QUERY].off], u->field_data[UF_QUERY].len);
}
return stream_data;
}
static void delete_http2_stream_data(http2_stream_data *stream_data) {
free(stream_data->path);
free(stream_data->authority);
free(stream_data);
}
/* Initializes |session_data| */
static http2_session_data *
create_http2_session_data(struct event_base *evbase) {
http2_session_data *session_data = malloc(sizeof(http2_session_data));
memset(session_data, 0, sizeof(http2_session_data));
session_data->dnsbase = evdns_base_new(evbase, 1);
return session_data;
}
static void delete_http2_session_data(http2_session_data *session_data) {
SSL *ssl = bufferevent_openssl_get_ssl(session_data->bev);
if (ssl) {
SSL_shutdown(ssl);
}
bufferevent_free(session_data->bev);
session_data->bev = NULL;
evdns_base_free(session_data->dnsbase, 1);
session_data->dnsbase = NULL;
nghttp2_session_del(session_data->session);
session_data->session = NULL;
if (session_data->stream_data) {
delete_http2_stream_data(session_data->stream_data);
session_data->stream_data = NULL;
}
free(session_data);
}
static void print_header(FILE *f, const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen) {
fwrite(name, 1, namelen, f);
fprintf(f, ": ");
fwrite(value, 1, valuelen, f);
fprintf(f, "\n");
}
/* Print HTTP headers to |f|. Please note that this function does not
take into account that header name and value are sequence of
octets, therefore they may contain non-printable characters. */
static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen) {
size_t i;
for (i = 0; i < nvlen; ++i) {
print_header(f, nva[i].name, nva[i].namelen, nva[i].value, nva[i].valuelen);
}
fprintf(f, "\n");
}
/* nghttp2_send_callback. Here we transmit the |data|, |length| bytes,
to the network. Because we are using libevent bufferevent, we just
write those bytes into bufferevent buffer. */
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
size_t length, int flags, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev;
(void)session;
(void)flags;
bufferevent_write(bev, data, length);
return (ssize_t)length;
}
/* nghttp2_on_header_callback: Called when nghttp2 library emits
single header name/value pair. */
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame, const uint8_t *name,
size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
(void)session;
(void)flags;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
/* Print response headers for the initiated request. */
print_header(stderr, name, namelen, value, valuelen);
break;
}
}
return 0;
}
/* nghttp2_on_begin_headers_callback: Called when nghttp2 library gets
started to receive header block. */
static int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
(void)session;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
fprintf(stderr, "Response headers for stream ID=%d:\n",
frame->hd.stream_id);
}
break;
}
return 0;
}
/* nghttp2_on_frame_recv_callback: Called when nghttp2 library
received a complete frame from the remote peer. */
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
(void)session;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
fprintf(stderr, "All headers received\n");
}
break;
}
return 0;
}
/* nghttp2_on_data_chunk_recv_callback: Called when DATA frame is
received from the remote peer. In this implementation, if the frame
is meant to the stream we initiated, print the received data in
stdout, so that the user can redirect its output to the file
easily. */
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
int32_t stream_id, const uint8_t *data,
size_t len, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
(void)session;
(void)flags;
if (session_data->stream_data->stream_id == stream_id) {
fwrite(data, 1, len, stdout);
}
return 0;
}
/* nghttp2_on_stream_close_callback: Called when a stream is about to
closed. This example program only deals with 1 HTTP request (1
stream), if it is closed, we send GOAWAY and tear down the
session */
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
int rv;
if (session_data->stream_data->stream_id == stream_id) {
fprintf(stderr, "Stream %d closed with error_code=%u\n", stream_id,
error_code);
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
if (rv != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
return 0;
}
#ifndef OPENSSL_NO_NEXTPROTONEG
/* NPN TLS extension client callback. We check that server advertised
the HTTP/2 protocol the nghttp2 library supports. If not, exit
the program. */
static int select_next_proto_cb(SSL *ssl, unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg) {
(void)ssl;
(void)arg;
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
}
return SSL_TLSEXT_ERR_OK;
}
#endif /* !OPENSSL_NO_NEXTPROTONEG */
/* Create SSL_CTX. */
static SSL_CTX *create_ssl_ctx(void) {
SSL_CTX *ssl_ctx;
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (!ssl_ctx) {
errx(1, "Could not create SSL/TLS context: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
return ssl_ctx;
}
/* Create SSL object */
static SSL *create_ssl(SSL_CTX *ssl_ctx) {
SSL *ssl;
ssl = SSL_new(ssl_ctx);
if (!ssl) {
errx(1, "Could not create SSL/TLS session object: %s",
ERR_error_string(ERR_get_error(), NULL));
}
return ssl;
}
static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_session_callbacks *callbacks;
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
callbacks, on_data_chunk_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
nghttp2_session_client_new(&session_data->session, callbacks, session_data);
nghttp2_session_callbacks_del(callbacks);
}
static void send_client_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = {
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
/* client 24 bytes magic string will be sent by nghttp2 library */
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv));
if (rv != 0) {
errx(1, "Could not submit SETTINGS: %s", nghttp2_strerror(rv));
}
}
#define MAKE_NV(NAME, VALUE, VALUELEN) \
{ \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, VALUELEN, \
NGHTTP2_NV_FLAG_NONE \
}
#define MAKE_NV2(NAME, VALUE) \
{ \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
/* Send HTTP request to the remote peer */
static void submit_request(http2_session_data *session_data) {
int32_t stream_id;
http2_stream_data *stream_data = session_data->stream_data;
const char *uri = stream_data->uri;
const struct http_parser_url *u = stream_data->u;
nghttp2_nv hdrs[] = {
MAKE_NV2(":method", "GET"),
MAKE_NV(":scheme", &uri[u->field_data[UF_SCHEMA].off],
u->field_data[UF_SCHEMA].len),
MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
MAKE_NV(":path", stream_data->path, stream_data->pathlen)};
fprintf(stderr, "Request headers:\n");
print_headers(stderr, hdrs, ARRLEN(hdrs));
stream_id = nghttp2_submit_request(session_data->session, NULL, hdrs,
ARRLEN(hdrs), NULL, stream_data);
if (stream_id < 0) {
errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id));
}
stream_data->stream_id = stream_id;
}
/* Serialize the frame and send (or buffer) the data to
bufferevent. */
static int session_send(http2_session_data *session_data) {
int rv;
rv = nghttp2_session_send(session_data->session);
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
return 0;
}
/* readcb for bufferevent. Here we get the data from the input buffer
of bufferevent and feed them to nghttp2 library. This may invoke
nghttp2 callbacks. It may also queues the frame in nghttp2 session
context. To send them, we call session_send() in the end. */
static void readcb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
ssize_t readlen;
struct evbuffer *input = bufferevent_get_input(bev);
size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
delete_http2_session_data(session_data);
return;
}
if (evbuffer_drain(input, (size_t)readlen) != 0) {
warnx("Fatal error: evbuffer_drain failed");
delete_http2_session_data(session_data);
return;
}
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
}
/* writecb for bufferevent. To greaceful shutdown after sending or
receiving GOAWAY, we check the some conditions on the nghttp2
library and output buffer of bufferevent. If it indicates we have
no business to this session, tear down the connection. */
static void writecb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
(void)bev;
if (nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0 &&
evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
delete_http2_session_data(session_data);
}
}
/* eventcb for bufferevent. For the purpose of simplicity and
readability of the example program, we omitted the certificate and
peer verification. After SSL/TLS handshake is over, initialize
nghttp2 library session, and send client connection header. Then
send HTTP request. */
static void eventcb(struct bufferevent *bev, short events, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (events & BEV_EVENT_CONNECTED) {
int fd = bufferevent_getfd(bev);
int val = 1;
const unsigned char *alpn = NULL;
unsigned int alpnlen = 0;
SSL *ssl;
fprintf(stderr, "Connected\n");
ssl = bufferevent_openssl_get_ssl(session_data->bev);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (alpn == NULL) {
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
fprintf(stderr, "h2 is not negotiated\n");
delete_http2_session_data(session_data);
return;
}
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
initialize_nghttp2_session(session_data);
send_client_connection_header(session_data);
submit_request(session_data);
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
}
return;
}
if (events & BEV_EVENT_EOF) {
warnx("Disconnected from the remote host");
} else if (events & BEV_EVENT_ERROR) {
warnx("Network error");
} else if (events & BEV_EVENT_TIMEOUT) {
warnx("Timeout");
}
delete_http2_session_data(session_data);
}
/* Start connecting to the remote peer |host:port| */
static void initiate_connection(struct event_base *evbase, SSL_CTX *ssl_ctx,
const char *host, uint16_t port,
http2_session_data *session_data) {
int rv;
struct bufferevent *bev;
SSL *ssl;
ssl = create_ssl(ssl_ctx);
bev = bufferevent_openssl_socket_new(
evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
bufferevent_enable(bev, EV_READ | EV_WRITE);
bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
AF_UNSPEC, host, port);
if (rv != 0) {
errx(1, "Could not connect to the remote host %s", host);
}
session_data->bev = bev;
}
/* Get resource denoted by the |uri|. The debug and error messages are
printed in stderr, while the response body is printed in stdout. */
static void run(const char *uri) {
struct http_parser_url u;
char *host;
uint16_t port;
int rv;
SSL_CTX *ssl_ctx;
struct event_base *evbase;
http2_session_data *session_data;
/* Parse the |uri| and stores its components in |u| */
rv = http_parser_parse_url(uri, strlen(uri), 0, &u);
if (rv != 0) {
errx(1, "Could not parse URI %s", uri);
}
host = strndup(&uri[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len);
if (!(u.field_set & (1 << UF_PORT))) {
port = 443;
} else {
port = u.port;
}
ssl_ctx = create_ssl_ctx();
evbase = event_base_new();
session_data = create_http2_session_data(evbase);
session_data->stream_data = create_http2_stream_data(uri, &u);
initiate_connection(evbase, ssl_ctx, host, port, session_data);
free(host);
host = NULL;
event_base_loop(evbase, 0);
event_base_free(evbase);
SSL_CTX_free(ssl_ctx);
}
int main(int argc, char **argv) {
struct sigaction act;
if (argc < 2) {
fprintf(stderr, "Usage: libevent-client HTTPS_URI\n");
exit(EXIT_FAILURE);
}
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, NULL);
SSL_load_error_strings();
SSL_library_init();
run(argv[1]);
return 0;
}
+817
View File
@@ -0,0 +1,817 @@
/*
* 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.
*/
#ifdef __sgi
# define errx(exitcode, format, args...) \
{ \
warnx(format, ##args); \
exit(exitcode); \
}
# define warn(format, args...) warnx(format ": %s", ##args, strerror(errno))
# define warnx(format, args...) fprintf(stderr, format "\n", ##args)
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif /* HAVE_NETDB_H */
#include <signal.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <sys/stat.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#include <ctype.h>
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#include <netinet/tcp.h>
#ifndef __sgi
# include <err.h>
#endif
#include <string.h>
#include <errno.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <event.h>
#include <event2/event.h>
#include <event2/bufferevent_ssl.h>
#include <event2/listener.h>
#include <nghttp2/nghttp2.h>
#define OUTPUT_WOULDBLOCK_THRESHOLD (1 << 16)
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
#define MAKE_NV(NAME, VALUE) \
{ \
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
struct app_context;
typedef struct app_context app_context;
typedef struct http2_stream_data {
struct http2_stream_data *prev, *next;
char *request_path;
int32_t stream_id;
int fd;
} http2_stream_data;
typedef struct http2_session_data {
struct http2_stream_data root;
struct bufferevent *bev;
app_context *app_ctx;
nghttp2_session *session;
char *client_addr;
} http2_session_data;
struct app_context {
SSL_CTX *ssl_ctx;
struct event_base *evbase;
};
static unsigned char next_proto_list[256];
static size_t next_proto_list_len;
#ifndef OPENSSL_NO_NEXTPROTONEG
static int next_proto_cb(SSL *ssl, const unsigned char **data,
unsigned int *len, void *arg) {
(void)ssl;
(void)arg;
*data = next_proto_list;
*len = (unsigned int)next_proto_list_len;
return SSL_TLSEXT_ERR_OK;
}
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg) {
int rv;
(void)ssl;
(void)arg;
rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen);
if (rv != 1) {
return SSL_TLSEXT_ERR_NOACK;
}
return SSL_TLSEXT_ERR_OK;
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
/* Create SSL_CTX. */
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
SSL_CTX *ssl_ctx;
EC_KEY *ecdh;
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if (!ssl_ctx) {
errx(1, "Could not create SSL/TLS context: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (!ecdh) {
errx(1, "EC_KEY_new_by_curv_name failed: %s",
ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
EC_KEY_free(ecdh);
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
errx(1, "Could not read private key file %s", key_file);
}
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
errx(1, "Could not read certificate file %s", cert_file);
}
next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID_LEN);
next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN;
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
return ssl_ctx;
}
/* Create SSL object */
static SSL *create_ssl(SSL_CTX *ssl_ctx) {
SSL *ssl;
ssl = SSL_new(ssl_ctx);
if (!ssl) {
errx(1, "Could not create SSL/TLS session object: %s",
ERR_error_string(ERR_get_error(), NULL));
}
return ssl;
}
static void add_stream(http2_session_data *session_data,
http2_stream_data *stream_data) {
stream_data->next = session_data->root.next;
session_data->root.next = stream_data;
stream_data->prev = &session_data->root;
if (stream_data->next) {
stream_data->next->prev = stream_data;
}
}
static void remove_stream(http2_session_data *session_data,
http2_stream_data *stream_data) {
(void)session_data;
stream_data->prev->next = stream_data->next;
if (stream_data->next) {
stream_data->next->prev = stream_data->prev;
}
}
static http2_stream_data *
create_http2_stream_data(http2_session_data *session_data, int32_t stream_id) {
http2_stream_data *stream_data;
stream_data = malloc(sizeof(http2_stream_data));
memset(stream_data, 0, sizeof(http2_stream_data));
stream_data->stream_id = stream_id;
stream_data->fd = -1;
add_stream(session_data, stream_data);
return stream_data;
}
static void delete_http2_stream_data(http2_stream_data *stream_data) {
if (stream_data->fd != -1) {
close(stream_data->fd);
}
free(stream_data->request_path);
free(stream_data);
}
static http2_session_data *create_http2_session_data(app_context *app_ctx,
int fd,
struct sockaddr *addr,
int addrlen) {
int rv;
http2_session_data *session_data;
SSL *ssl;
char host[NI_MAXHOST];
int val = 1;
ssl = create_ssl(app_ctx->ssl_ctx);
session_data = malloc(sizeof(http2_session_data));
memset(session_data, 0, sizeof(http2_session_data));
session_data->app_ctx = app_ctx;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
session_data->bev = bufferevent_openssl_socket_new(
app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
bufferevent_enable(session_data->bev, EV_READ | EV_WRITE);
rv = getnameinfo(addr, (socklen_t)addrlen, host, sizeof(host), NULL, 0,
NI_NUMERICHOST);
if (rv != 0) {
session_data->client_addr = strdup("(unknown)");
} else {
session_data->client_addr = strdup(host);
}
return session_data;
}
static void delete_http2_session_data(http2_session_data *session_data) {
http2_stream_data *stream_data;
SSL *ssl = bufferevent_openssl_get_ssl(session_data->bev);
fprintf(stderr, "%s disconnected\n", session_data->client_addr);
if (ssl) {
SSL_shutdown(ssl);
}
bufferevent_free(session_data->bev);
nghttp2_session_del(session_data->session);
for (stream_data = session_data->root.next; stream_data;) {
http2_stream_data *next = stream_data->next;
delete_http2_stream_data(stream_data);
stream_data = next;
}
free(session_data->client_addr);
free(session_data);
}
/* Serialize the frame and send (or buffer) the data to
bufferevent. */
static int session_send(http2_session_data *session_data) {
int rv;
rv = nghttp2_session_send(session_data->session);
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
return 0;
}
/* Read the data in the bufferevent and feed them into nghttp2 library
function. Invocation of nghttp2_session_mem_recv() may make
additional pending frames, so call session_send() at the end of the
function. */
static int session_recv(http2_session_data *session_data) {
ssize_t readlen;
struct evbuffer *input = bufferevent_get_input(session_data->bev);
size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
if (readlen < 0) {
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
return -1;
}
if (evbuffer_drain(input, (size_t)readlen) != 0) {
warnx("Fatal error: evbuffer_drain failed");
return -1;
}
if (session_send(session_data) != 0) {
return -1;
}
return 0;
}
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
size_t length, int flags, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
struct bufferevent *bev = session_data->bev;
(void)session;
(void)flags;
/* Avoid excessive buffering in server side. */
if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
OUTPUT_WOULDBLOCK_THRESHOLD) {
return NGHTTP2_ERR_WOULDBLOCK;
}
bufferevent_write(bev, data, length);
return (ssize_t)length;
}
/* Returns nonzero if the string |s| ends with the substring |sub| */
static int ends_with(const char *s, const char *sub) {
size_t slen = strlen(s);
size_t sublen = strlen(sub);
if (slen < sublen) {
return 0;
}
return memcmp(s + slen - sublen, sub, sublen) == 0;
}
/* Returns int value of hex string character |c| */
static uint8_t hex_to_uint(uint8_t c) {
if ('0' <= c && c <= '9') {
return (uint8_t)(c - '0');
}
if ('A' <= c && c <= 'F') {
return (uint8_t)(c - 'A' + 10);
}
if ('a' <= c && c <= 'f') {
return (uint8_t)(c - 'a' + 10);
}
return 0;
}
/* Decodes percent-encoded byte string |value| with length |valuelen|
and returns the decoded byte string in allocated buffer. The return
value is NULL terminated. The caller must free the returned
string. */
static char *percent_decode(const uint8_t *value, size_t valuelen) {
char *res;
res = malloc(valuelen + 1);
if (valuelen > 3) {
size_t i, j;
for (i = 0, j = 0; i < valuelen - 2;) {
if (value[i] != '%' || !isxdigit(value[i + 1]) ||
!isxdigit(value[i + 2])) {
res[j++] = (char)value[i++];
continue;
}
res[j++] =
(char)((hex_to_uint(value[i + 1]) << 4) + hex_to_uint(value[i + 2]));
i += 3;
}
memcpy(&res[j], &value[i], 2);
res[j + 2] = '\0';
} else {
memcpy(res, value, valuelen);
res[valuelen] = '\0';
}
return res;
}
static ssize_t file_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) {
int fd = source->fd;
ssize_t r;
(void)session;
(void)stream_id;
(void)user_data;
while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
;
if (r == -1) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if (r == 0) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
}
return r;
}
static int send_response(nghttp2_session *session, int32_t stream_id,
nghttp2_nv *nva, size_t nvlen, int fd) {
int rv;
nghttp2_data_provider data_prd;
data_prd.source.fd = fd;
data_prd.read_callback = file_read_callback;
rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd);
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
return 0;
}
static const char ERROR_HTML[] = "<html><head><title>404</title></head>"
"<body><h1>404 Not Found</h1></body></html>";
static int error_reply(nghttp2_session *session,
http2_stream_data *stream_data) {
int rv;
ssize_t writelen;
int pipefd[2];
nghttp2_nv hdrs[] = {MAKE_NV(":status", "404")};
rv = pipe(pipefd);
if (rv != 0) {
warn("Could not create pipe");
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
stream_data->stream_id,
NGHTTP2_INTERNAL_ERROR);
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
return 0;
}
writelen = write(pipefd[1], ERROR_HTML, sizeof(ERROR_HTML) - 1);
close(pipefd[1]);
if (writelen != sizeof(ERROR_HTML) - 1) {
close(pipefd[0]);
return -1;
}
stream_data->fd = pipefd[0];
if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs),
pipefd[0]) != 0) {
close(pipefd[0]);
return -1;
}
return 0;
}
/* nghttp2_on_header_callback: Called when nghttp2 library emits
single header name/value pair. */
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame, const uint8_t *name,
size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags, void *user_data) {
http2_stream_data *stream_data;
const char PATH[] = ":path";
(void)flags;
(void)user_data;
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
break;
}
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (!stream_data || stream_data->request_path) {
break;
}
if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
size_t j;
for (j = 0; j < valuelen && value[j] != '?'; ++j)
;
stream_data->request_path = percent_decode(value, j);
}
break;
}
return 0;
}
static int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
if (frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
stream_data = create_http2_stream_data(session_data, frame->hd.stream_id);
nghttp2_session_set_stream_user_data(session, frame->hd.stream_id,
stream_data);
return 0;
}
/* Minimum check for directory traversal. Returns nonzero if it is
safe. */
static int check_path(const char *path) {
/* We don't like '\' in url. */
return path[0] && path[0] == '/' && strchr(path, '\\') == NULL &&
strstr(path, "/../") == NULL && strstr(path, "/./") == NULL &&
!ends_with(path, "/..") && !ends_with(path, "/.");
}
static int on_request_recv(nghttp2_session *session,
http2_session_data *session_data,
http2_stream_data *stream_data) {
int fd;
nghttp2_nv hdrs[] = {MAKE_NV(":status", "200")};
char *rel_path;
if (!stream_data->request_path) {
if (error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
fprintf(stderr, "%s GET %s\n", session_data->client_addr,
stream_data->request_path);
if (!check_path(stream_data->request_path)) {
if (error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
for (rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path)
;
fd = open(rel_path, O_RDONLY);
if (fd == -1) {
if (error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
stream_data->fd = fd;
if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs), fd) !=
0) {
close(fd);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
switch (frame->hd.type) {
case NGHTTP2_DATA:
case NGHTTP2_HEADERS:
/* Check that the client request has finished */
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data =
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
/* For DATA and HEADERS frame, this callback may be called after
on_stream_close_callback. Check that stream still alive. */
if (!stream_data) {
return 0;
}
return on_request_recv(session, session_data, stream_data);
}
break;
default:
break;
}
return 0;
}
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *user_data) {
http2_session_data *session_data = (http2_session_data *)user_data;
http2_stream_data *stream_data;
(void)error_code;
stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
if (!stream_data) {
return 0;
}
remove_stream(session_data, stream_data);
delete_http2_stream_data(stream_data);
return 0;
}
static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_session_callbacks *callbacks;
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_stream_close_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
nghttp2_session_server_new(&session_data->session, callbacks, session_data);
nghttp2_session_callbacks_del(callbacks);
}
/* Send HTTP/2 client connection header, which includes 24 bytes
magic octets and SETTINGS frame */
static int send_server_connection_header(http2_session_data *session_data) {
nghttp2_settings_entry iv[1] = {
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv;
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv));
if (rv != 0) {
warnx("Fatal error: %s", nghttp2_strerror(rv));
return -1;
}
return 0;
}
/* readcb for bufferevent after client connection header was
checked. */
static void readcb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
(void)bev;
if (session_recv(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
}
/* writecb for bufferevent. To greaceful shutdown after sending or
receiving GOAWAY, we check the some conditions on the nghttp2
library and output buffer of bufferevent. If it indicates we have
no business to this session, tear down the connection. If the
connection is not going to shutdown, we call session_send() to
process pending data in the output buffer. This is necessary
because we have a threshold on the buffer size to avoid too much
buffering. See send_callback(). */
static void writecb(struct bufferevent *bev, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
return;
}
if (nghttp2_session_want_read(session_data->session) == 0 &&
nghttp2_session_want_write(session_data->session) == 0) {
delete_http2_session_data(session_data);
return;
}
if (session_send(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
}
/* eventcb for bufferevent */
static void eventcb(struct bufferevent *bev, short events, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
if (events & BEV_EVENT_CONNECTED) {
const unsigned char *alpn = NULL;
unsigned int alpnlen = 0;
SSL *ssl;
(void)bev;
fprintf(stderr, "%s connected\n", session_data->client_addr);
ssl = bufferevent_openssl_get_ssl(session_data->bev);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (alpn == NULL) {
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr);
delete_http2_session_data(session_data);
return;
}
initialize_nghttp2_session(session_data);
if (send_server_connection_header(session_data) != 0 ||
session_send(session_data) != 0) {
delete_http2_session_data(session_data);
return;
}
return;
}
if (events & BEV_EVENT_EOF) {
fprintf(stderr, "%s EOF\n", session_data->client_addr);
} else if (events & BEV_EVENT_ERROR) {
fprintf(stderr, "%s network error\n", session_data->client_addr);
} else if (events & BEV_EVENT_TIMEOUT) {
fprintf(stderr, "%s timeout\n", session_data->client_addr);
}
delete_http2_session_data(session_data);
}
/* callback for evconnlistener */
static void acceptcb(struct evconnlistener *listener, int fd,
struct sockaddr *addr, int addrlen, void *arg) {
app_context *app_ctx = (app_context *)arg;
http2_session_data *session_data;
(void)listener;
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data);
}
static void start_listen(struct event_base *evbase, const char *service,
app_context *app_ctx) {
int rv;
struct addrinfo hints;
struct addrinfo *res, *rp;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
#ifdef AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG;
#endif /* AI_ADDRCONFIG */
rv = getaddrinfo(NULL, service, &hints, &res);
if (rv != 0) {
errx(1, "Could not resolve server address");
}
for (rp = res; rp; rp = rp->ai_next) {
struct evconnlistener *listener;
listener = evconnlistener_new_bind(
evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
16, rp->ai_addr, (int)rp->ai_addrlen);
if (listener) {
freeaddrinfo(res);
return;
}
}
errx(1, "Could not start listener");
}
static void initialize_app_context(app_context *app_ctx, SSL_CTX *ssl_ctx,
struct event_base *evbase) {
memset(app_ctx, 0, sizeof(app_context));
app_ctx->ssl_ctx = ssl_ctx;
app_ctx->evbase = evbase;
}
static void run(const char *service, const char *key_file,
const char *cert_file) {
SSL_CTX *ssl_ctx;
app_context app_ctx;
struct event_base *evbase;
ssl_ctx = create_ssl_ctx(key_file, cert_file);
evbase = event_base_new();
initialize_app_context(&app_ctx, ssl_ctx, evbase);
start_listen(evbase, service, &app_ctx);
event_base_loop(evbase, 0);
event_base_free(evbase);
SSL_CTX_free(ssl_ctx);
}
int main(int argc, char **argv) {
struct sigaction act;
if (argc < 4) {
fprintf(stderr, "Usage: libevent-server PORT KEY_FILE CERT_FILE\n");
exit(EXIT_FAILURE);
}
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, NULL);
SSL_load_error_strings();
SSL_library_init();
run(argv[1], argv[2], argv[3]);
return 0;
}