Add stock 0.9.42 source.
This is from http://www.gnu.org/software/libmicrohttpd/ (and
was verified to match the source from a local mirror).
Bug: 23101922
Change-Id: I7efc9d5065b49b8957ce41bb6afd2ce1f39c7cac
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
new file mode 100644
index 0000000..eb165bd
--- /dev/null
+++ b/src/testcurl/Makefile.am
@@ -0,0 +1,310 @@
+# This Makefile.am is in the public domain
+SUBDIRS = .
+
+if USE_COVERAGE
+ AM_CFLAGS = -fprofile-arcs -ftest-coverage
+endif
+
+if ENABLE_HTTPS
+ SUBDIRS += https
+endif
+
+AM_CPPFLAGS = \
+-DCPU_COUNT=$(CPU_COUNT) \
+-I$(top_srcdir) \
+-I$(top_srcdir)/src/microhttpd \
+-I$(top_srcdir)/src/include \
+$(LIBCURL_CPPFLAGS)
+
+if !HAVE_W32
+PERF_GET_CONCURRENT=perf_get_concurrent
+TEST_CONCURRENT_STOP=test_concurrent_stop
+if HAVE_CURL_BINARY
+CURL_FORK_TEST = test_get_response_cleanup
+endif
+endif
+
+if HAVE_CURL
+check_PROGRAMS = \
+ test_start_stop \
+ test_get \
+ test_get_sendfile \
+ test_urlparse \
+ test_put \
+ $(TEST_CONCURRENT_STOP) \
+ test_process_headers \
+ test_process_arguments \
+ test_parse_cookies \
+ test_large_put \
+ test_get11 \
+ test_get_sendfile11 \
+ test_put11 \
+ test_large_put11 \
+ test_long_header \
+ test_long_header11 \
+ test_get_chunked \
+ test_put_chunked \
+ test_iplimit11 \
+ test_termination \
+ test_timeout \
+ test_callback \
+ $(CURL_FORK_TEST) \
+ perf_get $(PERF_GET_CONCURRENT)
+
+if HAVE_POSIX_THREADS
+check_PROGRAMS += \
+ test_quiesce
+endif
+
+if HAVE_POSTPROCESSOR
+ check_PROGRAMS += \
+ test_post \
+ test_postform \
+ test_post_loop \
+ test_post11 \
+ test_postform11 \
+ test_post_loop11
+endif
+
+noinst_PROGRAMS = \
+ test_options
+
+if ENABLE_DAUTH
+ check_PROGRAMS += \
+ test_digestauth test_digestauth_with_arguments
+endif
+
+TESTS = $(check_PROGRAMS)
+
+noinst_LIBRARIES = libcurl_version_check.a
+endif
+
+libcurl_version_check_a_SOURCES = \
+ curl_version_check.c
+
+test_start_stop_SOURCES = \
+ test_start_stop.c
+test_start_stop_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+
+test_concurrent_stop_SOURCES = \
+ test_concurrent_stop.c
+test_concurrent_stop_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_options_SOURCES = \
+ test_options.c
+test_options_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+
+test_get_SOURCES = \
+ test_get.c
+test_get_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_quiesce_SOURCES = \
+ test_quiesce.c
+test_quiesce_CFLAGS = \
+ $(PTHREAD_CFLAGS) $(AM_CFLAGS)
+test_quiesce_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(PTHREAD_LIBS) @LIBCURL@
+
+test_callback_SOURCES = \
+ test_callback.c
+test_callback_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+perf_get_SOURCES = \
+ perf_get.c \
+ gauger.h
+perf_get_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+perf_get_concurrent_SOURCES = \
+ perf_get_concurrent.c \
+ gauger.h
+perf_get_concurrent_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_digestauth_SOURCES = \
+ test_digestauth.c
+test_digestauth_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_digestauth_with_arguments_SOURCES = \
+ test_digestauth_with_arguments.c
+test_digestauth_with_arguments_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_get_sendfile_SOURCES = \
+ test_get_sendfile.c
+test_get_sendfile_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+test_get_sendfile_DEPENDENCIES =
+
+if HAVE_W32
+test_get_sendfile_LDADD += \
+ $(top_builddir)/src/platform/libplatform_interface.la
+test_get_sendfile_DEPENDENCIES += \
+ $(top_builddir)/src/platform/libplatform_interface.la
+endif
+
+test_urlparse_SOURCES = \
+ test_urlparse.c
+test_urlparse_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_get_response_cleanup_SOURCES = \
+ test_get_response_cleanup.c
+test_get_response_cleanup_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+
+test_get_chunked_SOURCES = \
+ test_get_chunked.c
+test_get_chunked_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_post_SOURCES = \
+ test_post.c
+test_post_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_process_headers_SOURCES = \
+ test_process_headers.c
+test_process_headers_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_parse_cookies_SOURCES = \
+ test_parse_cookies.c
+test_parse_cookies_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_process_arguments_SOURCES = \
+ test_process_arguments.c
+test_process_arguments_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_postform_SOURCES = \
+ test_postform.c
+test_postform_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_post_loop_SOURCES = \
+ test_post_loop.c
+test_post_loop_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_put_SOURCES = \
+ test_put.c
+test_put_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_put_chunked_SOURCES = \
+ test_put_chunked.c
+test_put_chunked_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_get11_SOURCES = \
+ test_get.c
+test_get11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_get_sendfile11_SOURCES = \
+ test_get_sendfile.c
+test_get_sendfile11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+test_get_sendfile11_DEPENDENCIES =
+
+if HAVE_W32
+test_get_sendfile11_LDADD += \
+ $(top_builddir)/src/platform/libplatform_interface.la
+test_get_sendfile11_DEPENDENCIES += \
+ $(top_builddir)/src/platform/libplatform_interface.la
+endif
+
+test_post11_SOURCES = \
+ test_post.c
+test_post11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_postform11_SOURCES = \
+ test_postform.c
+test_postform11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_post_loop11_SOURCES = \
+ test_post_loop.c
+test_post_loop11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_put11_SOURCES = \
+ test_put.c
+test_put11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_large_put_SOURCES = \
+ test_large_put.c
+test_large_put_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_large_put11_SOURCES = \
+ test_large_put.c
+test_large_put11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_long_header_SOURCES = \
+ test_long_header.c
+test_long_header_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_long_header11_SOURCES = \
+ test_long_header.c
+test_long_header11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_iplimit11_SOURCES = \
+ test_iplimit.c
+test_iplimit11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_termination_SOURCES = \
+ test_termination.c
+test_termination_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_timeout_SOURCES = \
+ test_timeout.c
+test_timeout_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
diff --git a/src/testcurl/Makefile.in b/src/testcurl/Makefile.in
new file mode 100644
index 0000000..937bf26
--- /dev/null
+++ b/src/testcurl/Makefile.in
@@ -0,0 +1,2059 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 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@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+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@
+@ENABLE_HTTPS_TRUE@am__append_1 = https
+@HAVE_CURL_TRUE@check_PROGRAMS = test_start_stop$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_get$(EXEEXT) test_get_sendfile$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_urlparse$(EXEEXT) test_put$(EXEEXT) \
+@HAVE_CURL_TRUE@ $(am__EXEEXT_1) test_process_headers$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_process_arguments$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_parse_cookies$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_large_put$(EXEEXT) test_get11$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_get_sendfile11$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_put11$(EXEEXT) test_large_put11$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_long_header$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_long_header11$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_get_chunked$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_put_chunked$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_iplimit11$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_termination$(EXEEXT) \
+@HAVE_CURL_TRUE@ test_timeout$(EXEEXT) test_callback$(EXEEXT) \
+@HAVE_CURL_TRUE@ $(am__EXEEXT_2) perf_get$(EXEEXT) \
+@HAVE_CURL_TRUE@ $(am__EXEEXT_3) $(am__EXEEXT_4) \
+@HAVE_CURL_TRUE@ $(am__EXEEXT_5) $(am__EXEEXT_6)
+@HAVE_CURL_TRUE@@HAVE_POSIX_THREADS_TRUE@am__append_2 = \
+@HAVE_CURL_TRUE@@HAVE_POSIX_THREADS_TRUE@ test_quiesce
+
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@am__append_3 = \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_post \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_postform \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_post_loop \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_post11 \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_postform11 \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_post_loop11
+
+@HAVE_CURL_TRUE@noinst_PROGRAMS = test_options$(EXEEXT)
+@ENABLE_DAUTH_TRUE@@HAVE_CURL_TRUE@am__append_4 = \
+@ENABLE_DAUTH_TRUE@@HAVE_CURL_TRUE@ test_digestauth test_digestauth_with_arguments
+
+@HAVE_W32_TRUE@am__append_5 = \
+@HAVE_W32_TRUE@ $(top_builddir)/src/platform/libplatform_interface.la
+
+@HAVE_W32_TRUE@am__append_6 = \
+@HAVE_W32_TRUE@ $(top_builddir)/src/platform/libplatform_interface.la
+
+@HAVE_W32_TRUE@am__append_7 = \
+@HAVE_W32_TRUE@ $(top_builddir)/src/platform/libplatform_interface.la
+
+@HAVE_W32_TRUE@am__append_8 = \
+@HAVE_W32_TRUE@ $(top_builddir)/src/platform/libplatform_interface.la
+
+subdir = src/testcurl
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(top_srcdir)/test-driver
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_compile_flags.m4 \
+ $(top_srcdir)/m4/ax_append_flag.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_count_cpus.m4 \
+ $(top_srcdir)/m4/ax_have_epoll.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_require_defined.m4 \
+ $(top_srcdir)/m4/libcurl.m4 $(top_srcdir)/m4/libgcrypt.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)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/MHD_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libcurl_version_check_a_AR = $(AR) $(ARFLAGS)
+libcurl_version_check_a_LIBADD =
+am_libcurl_version_check_a_OBJECTS = curl_version_check.$(OBJEXT)
+libcurl_version_check_a_OBJECTS = \
+ $(am_libcurl_version_check_a_OBJECTS)
+@HAVE_W32_FALSE@am__EXEEXT_1 = test_concurrent_stop$(EXEEXT)
+@HAVE_CURL_BINARY_TRUE@@HAVE_W32_FALSE@am__EXEEXT_2 = test_get_response_cleanup$(EXEEXT)
+@HAVE_W32_FALSE@am__EXEEXT_3 = perf_get_concurrent$(EXEEXT)
+@HAVE_CURL_TRUE@@HAVE_POSIX_THREADS_TRUE@am__EXEEXT_4 = test_quiesce$(EXEEXT)
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@am__EXEEXT_5 = \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_post$(EXEEXT) \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_postform$(EXEEXT) \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_post_loop$(EXEEXT) \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_post11$(EXEEXT) \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_postform11$(EXEEXT) \
+@HAVE_CURL_TRUE@@HAVE_POSTPROCESSOR_TRUE@ test_post_loop11$(EXEEXT)
+@ENABLE_DAUTH_TRUE@@HAVE_CURL_TRUE@am__EXEEXT_6 = \
+@ENABLE_DAUTH_TRUE@@HAVE_CURL_TRUE@ test_digestauth$(EXEEXT) \
+@ENABLE_DAUTH_TRUE@@HAVE_CURL_TRUE@ test_digestauth_with_arguments$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+am_perf_get_OBJECTS = perf_get.$(OBJEXT)
+perf_get_OBJECTS = $(am_perf_get_OBJECTS)
+perf_get_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+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_perf_get_concurrent_OBJECTS = perf_get_concurrent.$(OBJEXT)
+perf_get_concurrent_OBJECTS = $(am_perf_get_concurrent_OBJECTS)
+perf_get_concurrent_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_callback_OBJECTS = test_callback.$(OBJEXT)
+test_callback_OBJECTS = $(am_test_callback_OBJECTS)
+test_callback_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_concurrent_stop_OBJECTS = test_concurrent_stop.$(OBJEXT)
+test_concurrent_stop_OBJECTS = $(am_test_concurrent_stop_OBJECTS)
+test_concurrent_stop_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_digestauth_OBJECTS = test_digestauth.$(OBJEXT)
+test_digestauth_OBJECTS = $(am_test_digestauth_OBJECTS)
+test_digestauth_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_digestauth_with_arguments_OBJECTS = \
+ test_digestauth_with_arguments.$(OBJEXT)
+test_digestauth_with_arguments_OBJECTS = \
+ $(am_test_digestauth_with_arguments_OBJECTS)
+test_digestauth_with_arguments_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_get_OBJECTS = test_get.$(OBJEXT)
+test_get_OBJECTS = $(am_test_get_OBJECTS)
+test_get_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_get11_OBJECTS = test_get.$(OBJEXT)
+test_get11_OBJECTS = $(am_test_get11_OBJECTS)
+test_get11_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_get_chunked_OBJECTS = test_get_chunked.$(OBJEXT)
+test_get_chunked_OBJECTS = $(am_test_get_chunked_OBJECTS)
+test_get_chunked_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_get_response_cleanup_OBJECTS = \
+ test_get_response_cleanup.$(OBJEXT)
+test_get_response_cleanup_OBJECTS = \
+ $(am_test_get_response_cleanup_OBJECTS)
+test_get_response_cleanup_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_get_sendfile_OBJECTS = test_get_sendfile.$(OBJEXT)
+test_get_sendfile_OBJECTS = $(am_test_get_sendfile_OBJECTS)
+am_test_get_sendfile11_OBJECTS = test_get_sendfile.$(OBJEXT)
+test_get_sendfile11_OBJECTS = $(am_test_get_sendfile11_OBJECTS)
+am_test_iplimit11_OBJECTS = test_iplimit.$(OBJEXT)
+test_iplimit11_OBJECTS = $(am_test_iplimit11_OBJECTS)
+test_iplimit11_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_large_put_OBJECTS = test_large_put.$(OBJEXT)
+test_large_put_OBJECTS = $(am_test_large_put_OBJECTS)
+test_large_put_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_large_put11_OBJECTS = test_large_put.$(OBJEXT)
+test_large_put11_OBJECTS = $(am_test_large_put11_OBJECTS)
+test_large_put11_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_long_header_OBJECTS = test_long_header.$(OBJEXT)
+test_long_header_OBJECTS = $(am_test_long_header_OBJECTS)
+test_long_header_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_long_header11_OBJECTS = test_long_header.$(OBJEXT)
+test_long_header11_OBJECTS = $(am_test_long_header11_OBJECTS)
+test_long_header11_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_options_OBJECTS = test_options.$(OBJEXT)
+test_options_OBJECTS = $(am_test_options_OBJECTS)
+test_options_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_parse_cookies_OBJECTS = test_parse_cookies.$(OBJEXT)
+test_parse_cookies_OBJECTS = $(am_test_parse_cookies_OBJECTS)
+test_parse_cookies_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_post_OBJECTS = test_post.$(OBJEXT)
+test_post_OBJECTS = $(am_test_post_OBJECTS)
+test_post_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_post11_OBJECTS = test_post.$(OBJEXT)
+test_post11_OBJECTS = $(am_test_post11_OBJECTS)
+test_post11_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_post_loop_OBJECTS = test_post_loop.$(OBJEXT)
+test_post_loop_OBJECTS = $(am_test_post_loop_OBJECTS)
+test_post_loop_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_post_loop11_OBJECTS = test_post_loop.$(OBJEXT)
+test_post_loop11_OBJECTS = $(am_test_post_loop11_OBJECTS)
+test_post_loop11_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_postform_OBJECTS = test_postform.$(OBJEXT)
+test_postform_OBJECTS = $(am_test_postform_OBJECTS)
+test_postform_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_postform11_OBJECTS = test_postform.$(OBJEXT)
+test_postform11_OBJECTS = $(am_test_postform11_OBJECTS)
+test_postform11_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_process_arguments_OBJECTS = test_process_arguments.$(OBJEXT)
+test_process_arguments_OBJECTS = $(am_test_process_arguments_OBJECTS)
+test_process_arguments_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_process_headers_OBJECTS = test_process_headers.$(OBJEXT)
+test_process_headers_OBJECTS = $(am_test_process_headers_OBJECTS)
+test_process_headers_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_put_OBJECTS = test_put.$(OBJEXT)
+test_put_OBJECTS = $(am_test_put_OBJECTS)
+test_put_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_put11_OBJECTS = test_put.$(OBJEXT)
+test_put11_OBJECTS = $(am_test_put11_OBJECTS)
+test_put11_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_put_chunked_OBJECTS = test_put_chunked.$(OBJEXT)
+test_put_chunked_OBJECTS = $(am_test_put_chunked_OBJECTS)
+test_put_chunked_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_quiesce_OBJECTS = test_quiesce-test_quiesce.$(OBJEXT)
+test_quiesce_OBJECTS = $(am_test_quiesce_OBJECTS)
+am__DEPENDENCIES_1 =
+test_quiesce_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1)
+test_quiesce_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(test_quiesce_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+am_test_start_stop_OBJECTS = test_start_stop.$(OBJEXT)
+test_start_stop_OBJECTS = $(am_test_start_stop_OBJECTS)
+test_start_stop_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_termination_OBJECTS = test_termination.$(OBJEXT)
+test_termination_OBJECTS = $(am_test_termination_OBJECTS)
+test_termination_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_timeout_OBJECTS = test_timeout.$(OBJEXT)
+test_timeout_OBJECTS = $(am_test_timeout_OBJECTS)
+test_timeout_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+am_test_urlparse_OBJECTS = test_urlparse.$(OBJEXT)
+test_urlparse_OBJECTS = $(am_test_urlparse_OBJECTS)
+test_urlparse_DEPENDENCIES = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.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__depfiles_maybe = depfiles
+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 =
+SOURCES = $(libcurl_version_check_a_SOURCES) $(perf_get_SOURCES) \
+ $(perf_get_concurrent_SOURCES) $(test_callback_SOURCES) \
+ $(test_concurrent_stop_SOURCES) $(test_digestauth_SOURCES) \
+ $(test_digestauth_with_arguments_SOURCES) $(test_get_SOURCES) \
+ $(test_get11_SOURCES) $(test_get_chunked_SOURCES) \
+ $(test_get_response_cleanup_SOURCES) \
+ $(test_get_sendfile_SOURCES) $(test_get_sendfile11_SOURCES) \
+ $(test_iplimit11_SOURCES) $(test_large_put_SOURCES) \
+ $(test_large_put11_SOURCES) $(test_long_header_SOURCES) \
+ $(test_long_header11_SOURCES) $(test_options_SOURCES) \
+ $(test_parse_cookies_SOURCES) $(test_post_SOURCES) \
+ $(test_post11_SOURCES) $(test_post_loop_SOURCES) \
+ $(test_post_loop11_SOURCES) $(test_postform_SOURCES) \
+ $(test_postform11_SOURCES) $(test_process_arguments_SOURCES) \
+ $(test_process_headers_SOURCES) $(test_put_SOURCES) \
+ $(test_put11_SOURCES) $(test_put_chunked_SOURCES) \
+ $(test_quiesce_SOURCES) $(test_start_stop_SOURCES) \
+ $(test_termination_SOURCES) $(test_timeout_SOURCES) \
+ $(test_urlparse_SOURCES)
+DIST_SOURCES = $(libcurl_version_check_a_SOURCES) $(perf_get_SOURCES) \
+ $(perf_get_concurrent_SOURCES) $(test_callback_SOURCES) \
+ $(test_concurrent_stop_SOURCES) $(test_digestauth_SOURCES) \
+ $(test_digestauth_with_arguments_SOURCES) $(test_get_SOURCES) \
+ $(test_get11_SOURCES) $(test_get_chunked_SOURCES) \
+ $(test_get_response_cleanup_SOURCES) \
+ $(test_get_sendfile_SOURCES) $(test_get_sendfile11_SOURCES) \
+ $(test_iplimit11_SOURCES) $(test_large_put_SOURCES) \
+ $(test_large_put11_SOURCES) $(test_long_header_SOURCES) \
+ $(test_long_header11_SOURCES) $(test_options_SOURCES) \
+ $(test_parse_cookies_SOURCES) $(test_post_SOURCES) \
+ $(test_post11_SOURCES) $(test_post_loop_SOURCES) \
+ $(test_post_loop11_SOURCES) $(test_postform_SOURCES) \
+ $(test_postform11_SOURCES) $(test_process_arguments_SOURCES) \
+ $(test_process_headers_SOURCES) $(test_put_SOURCES) \
+ $(test_put11_SOURCES) $(test_put_chunked_SOURCES) \
+ $(test_quiesce_SOURCES) $(test_start_stop_SOURCES) \
+ $(test_termination_SOURCES) $(test_timeout_SOURCES) \
+ $(test_urlparse_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ check recheck distdir
+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__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red='[0;31m'; \
+ grn='[0;32m'; \
+ lgn='[1;32m'; \
+ blu='[1;34m'; \
+ mgn='[0;35m'; \
+ brg='[1m'; \
+ std='[m'; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+DIST_SUBDIRS = . https
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPU_COUNT = @CPU_COUNT@
+CYGPATH_W = @CYGPATH_W@
+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@
+FGREP = @FGREP@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_CPPFLAGS = @GNUTLS_CPPFLAGS@
+GNUTLS_LDFLAGS = @GNUTLS_LDFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+HAVE_CURL_BINARY = @HAVE_CURL_BINARY@
+HAVE_MAKEINFO_BINARY = @HAVE_MAKEINFO_BINARY@
+HIDDEN_VISIBILITY_CFLAGS = @HIDDEN_VISIBILITY_CFLAGS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSPDY_VERSION_AGE = @LIBSPDY_VERSION_AGE@
+LIBSPDY_VERSION_CURRENT = @LIBSPDY_VERSION_CURRENT@
+LIBSPDY_VERSION_REVISION = @LIBSPDY_VERSION_REVISION@
+LIBTOOL = @LIBTOOL@
+LIB_VERSION_AGE = @LIB_VERSION_AGE@
+LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@
+LIB_VERSION_REVISION = @LIB_VERSION_REVISION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MHD_LIBDEPS = @MHD_LIBDEPS@
+MHD_LIBDEPS_PKGCFG = @MHD_LIBDEPS_PKGCFG@
+MHD_LIB_CFLAGS = @MHD_LIB_CFLAGS@
+MHD_LIB_CPPFLAGS = @MHD_LIB_CPPFLAGS@
+MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@
+MHD_REQ_PRIVATE = @MHD_REQ_PRIVATE@
+MKDIR_P = @MKDIR_P@
+MS_LIB_TOOL = @MS_LIB_TOOL@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+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_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_SUBMINOR = @PACKAGE_VERSION_SUBMINOR@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPDY_LIBDEPS = @SPDY_LIBDEPS@
+SPDY_LIB_CFLAGS = @SPDY_LIB_CFLAGS@
+SPDY_LIB_CPPFLAGS = @SPDY_LIB_CPPFLAGS@
+SPDY_LIB_LDFLAGS = @SPDY_LIB_LDFLAGS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+_libcurl_config = @_libcurl_config@
+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_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@
+ax_pthread_config = @ax_pthread_config@
+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@
+have_socat = @have_socat@
+have_zzuf = @have_zzuf@
+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@
+lt_cv_objdir = @lt_cv_objdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# This Makefile.am is in the public domain
+SUBDIRS = . $(am__append_1)
+@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage
+AM_CPPFLAGS = \
+-DCPU_COUNT=$(CPU_COUNT) \
+-I$(top_srcdir) \
+-I$(top_srcdir)/src/microhttpd \
+-I$(top_srcdir)/src/include \
+$(LIBCURL_CPPFLAGS)
+
+@HAVE_W32_FALSE@PERF_GET_CONCURRENT = perf_get_concurrent
+@HAVE_W32_FALSE@TEST_CONCURRENT_STOP = test_concurrent_stop
+@HAVE_CURL_BINARY_TRUE@@HAVE_W32_FALSE@CURL_FORK_TEST = test_get_response_cleanup
+@HAVE_CURL_TRUE@TESTS = $(check_PROGRAMS)
+@HAVE_CURL_TRUE@noinst_LIBRARIES = libcurl_version_check.a
+libcurl_version_check_a_SOURCES = \
+ curl_version_check.c
+
+test_start_stop_SOURCES = \
+ test_start_stop.c
+
+test_start_stop_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+
+test_concurrent_stop_SOURCES = \
+ test_concurrent_stop.c
+
+test_concurrent_stop_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_options_SOURCES = \
+ test_options.c
+
+test_options_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+
+test_get_SOURCES = \
+ test_get.c
+
+test_get_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_quiesce_SOURCES = \
+ test_quiesce.c
+
+test_quiesce_CFLAGS = \
+ $(PTHREAD_CFLAGS) $(AM_CFLAGS)
+
+test_quiesce_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(PTHREAD_LIBS) @LIBCURL@
+
+test_callback_SOURCES = \
+ test_callback.c
+
+test_callback_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+perf_get_SOURCES = \
+ perf_get.c \
+ gauger.h
+
+perf_get_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+perf_get_concurrent_SOURCES = \
+ perf_get_concurrent.c \
+ gauger.h
+
+perf_get_concurrent_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_digestauth_SOURCES = \
+ test_digestauth.c
+
+test_digestauth_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_digestauth_with_arguments_SOURCES = \
+ test_digestauth_with_arguments.c
+
+test_digestauth_with_arguments_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_get_sendfile_SOURCES = \
+ test_get_sendfile.c
+
+test_get_sendfile_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la @LIBCURL@ \
+ $(am__append_5)
+test_get_sendfile_DEPENDENCIES = $(am__append_6)
+test_urlparse_SOURCES = \
+ test_urlparse.c
+
+test_urlparse_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_get_response_cleanup_SOURCES = \
+ test_get_response_cleanup.c
+
+test_get_response_cleanup_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+
+test_get_chunked_SOURCES = \
+ test_get_chunked.c
+
+test_get_chunked_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_post_SOURCES = \
+ test_post.c
+
+test_post_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_process_headers_SOURCES = \
+ test_process_headers.c
+
+test_process_headers_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_parse_cookies_SOURCES = \
+ test_parse_cookies.c
+
+test_parse_cookies_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_process_arguments_SOURCES = \
+ test_process_arguments.c
+
+test_process_arguments_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_postform_SOURCES = \
+ test_postform.c
+
+test_postform_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_post_loop_SOURCES = \
+ test_post_loop.c
+
+test_post_loop_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_put_SOURCES = \
+ test_put.c
+
+test_put_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_put_chunked_SOURCES = \
+ test_put_chunked.c
+
+test_put_chunked_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_get11_SOURCES = \
+ test_get.c
+
+test_get11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_get_sendfile11_SOURCES = \
+ test_get_sendfile.c
+
+test_get_sendfile11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la @LIBCURL@ \
+ $(am__append_7)
+test_get_sendfile11_DEPENDENCIES = $(am__append_8)
+test_post11_SOURCES = \
+ test_post.c
+
+test_post11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_postform11_SOURCES = \
+ test_postform.c
+
+test_postform11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_post_loop11_SOURCES = \
+ test_post_loop.c
+
+test_post_loop11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_put11_SOURCES = \
+ test_put.c
+
+test_put11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_large_put_SOURCES = \
+ test_large_put.c
+
+test_large_put_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_large_put11_SOURCES = \
+ test_large_put.c
+
+test_large_put11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_long_header_SOURCES = \
+ test_long_header.c
+
+test_long_header_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_long_header11_SOURCES = \
+ test_long_header.c
+
+test_long_header11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_iplimit11_SOURCES = \
+ test_iplimit.c
+
+test_iplimit11_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_termination_SOURCES = \
+ test_termination.c
+
+test_termination_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+test_timeout_SOURCES = \
+ test_timeout.c
+
+test_timeout_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ @LIBCURL@
+
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(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 src/testcurl/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/testcurl/Makefile
+.PRECIOUS: 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__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ 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-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libcurl_version_check.a: $(libcurl_version_check_a_OBJECTS) $(libcurl_version_check_a_DEPENDENCIES) $(EXTRA_libcurl_version_check_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libcurl_version_check.a
+ $(AM_V_AR)$(libcurl_version_check_a_AR) libcurl_version_check.a $(libcurl_version_check_a_OBJECTS) $(libcurl_version_check_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libcurl_version_check.a
+
+clean-checkPROGRAMS:
+ @list='$(check_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
+
+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
+
+perf_get$(EXEEXT): $(perf_get_OBJECTS) $(perf_get_DEPENDENCIES) $(EXTRA_perf_get_DEPENDENCIES)
+ @rm -f perf_get$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(perf_get_OBJECTS) $(perf_get_LDADD) $(LIBS)
+
+perf_get_concurrent$(EXEEXT): $(perf_get_concurrent_OBJECTS) $(perf_get_concurrent_DEPENDENCIES) $(EXTRA_perf_get_concurrent_DEPENDENCIES)
+ @rm -f perf_get_concurrent$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(perf_get_concurrent_OBJECTS) $(perf_get_concurrent_LDADD) $(LIBS)
+
+test_callback$(EXEEXT): $(test_callback_OBJECTS) $(test_callback_DEPENDENCIES) $(EXTRA_test_callback_DEPENDENCIES)
+ @rm -f test_callback$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_callback_OBJECTS) $(test_callback_LDADD) $(LIBS)
+
+test_concurrent_stop$(EXEEXT): $(test_concurrent_stop_OBJECTS) $(test_concurrent_stop_DEPENDENCIES) $(EXTRA_test_concurrent_stop_DEPENDENCIES)
+ @rm -f test_concurrent_stop$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_concurrent_stop_OBJECTS) $(test_concurrent_stop_LDADD) $(LIBS)
+
+test_digestauth$(EXEEXT): $(test_digestauth_OBJECTS) $(test_digestauth_DEPENDENCIES) $(EXTRA_test_digestauth_DEPENDENCIES)
+ @rm -f test_digestauth$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_digestauth_OBJECTS) $(test_digestauth_LDADD) $(LIBS)
+
+test_digestauth_with_arguments$(EXEEXT): $(test_digestauth_with_arguments_OBJECTS) $(test_digestauth_with_arguments_DEPENDENCIES) $(EXTRA_test_digestauth_with_arguments_DEPENDENCIES)
+ @rm -f test_digestauth_with_arguments$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_digestauth_with_arguments_OBJECTS) $(test_digestauth_with_arguments_LDADD) $(LIBS)
+
+test_get$(EXEEXT): $(test_get_OBJECTS) $(test_get_DEPENDENCIES) $(EXTRA_test_get_DEPENDENCIES)
+ @rm -f test_get$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_get_OBJECTS) $(test_get_LDADD) $(LIBS)
+
+test_get11$(EXEEXT): $(test_get11_OBJECTS) $(test_get11_DEPENDENCIES) $(EXTRA_test_get11_DEPENDENCIES)
+ @rm -f test_get11$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_get11_OBJECTS) $(test_get11_LDADD) $(LIBS)
+
+test_get_chunked$(EXEEXT): $(test_get_chunked_OBJECTS) $(test_get_chunked_DEPENDENCIES) $(EXTRA_test_get_chunked_DEPENDENCIES)
+ @rm -f test_get_chunked$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_get_chunked_OBJECTS) $(test_get_chunked_LDADD) $(LIBS)
+
+test_get_response_cleanup$(EXEEXT): $(test_get_response_cleanup_OBJECTS) $(test_get_response_cleanup_DEPENDENCIES) $(EXTRA_test_get_response_cleanup_DEPENDENCIES)
+ @rm -f test_get_response_cleanup$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_get_response_cleanup_OBJECTS) $(test_get_response_cleanup_LDADD) $(LIBS)
+
+test_get_sendfile$(EXEEXT): $(test_get_sendfile_OBJECTS) $(test_get_sendfile_DEPENDENCIES) $(EXTRA_test_get_sendfile_DEPENDENCIES)
+ @rm -f test_get_sendfile$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_get_sendfile_OBJECTS) $(test_get_sendfile_LDADD) $(LIBS)
+
+test_get_sendfile11$(EXEEXT): $(test_get_sendfile11_OBJECTS) $(test_get_sendfile11_DEPENDENCIES) $(EXTRA_test_get_sendfile11_DEPENDENCIES)
+ @rm -f test_get_sendfile11$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_get_sendfile11_OBJECTS) $(test_get_sendfile11_LDADD) $(LIBS)
+
+test_iplimit11$(EXEEXT): $(test_iplimit11_OBJECTS) $(test_iplimit11_DEPENDENCIES) $(EXTRA_test_iplimit11_DEPENDENCIES)
+ @rm -f test_iplimit11$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_iplimit11_OBJECTS) $(test_iplimit11_LDADD) $(LIBS)
+
+test_large_put$(EXEEXT): $(test_large_put_OBJECTS) $(test_large_put_DEPENDENCIES) $(EXTRA_test_large_put_DEPENDENCIES)
+ @rm -f test_large_put$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_large_put_OBJECTS) $(test_large_put_LDADD) $(LIBS)
+
+test_large_put11$(EXEEXT): $(test_large_put11_OBJECTS) $(test_large_put11_DEPENDENCIES) $(EXTRA_test_large_put11_DEPENDENCIES)
+ @rm -f test_large_put11$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_large_put11_OBJECTS) $(test_large_put11_LDADD) $(LIBS)
+
+test_long_header$(EXEEXT): $(test_long_header_OBJECTS) $(test_long_header_DEPENDENCIES) $(EXTRA_test_long_header_DEPENDENCIES)
+ @rm -f test_long_header$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_long_header_OBJECTS) $(test_long_header_LDADD) $(LIBS)
+
+test_long_header11$(EXEEXT): $(test_long_header11_OBJECTS) $(test_long_header11_DEPENDENCIES) $(EXTRA_test_long_header11_DEPENDENCIES)
+ @rm -f test_long_header11$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_long_header11_OBJECTS) $(test_long_header11_LDADD) $(LIBS)
+
+test_options$(EXEEXT): $(test_options_OBJECTS) $(test_options_DEPENDENCIES) $(EXTRA_test_options_DEPENDENCIES)
+ @rm -f test_options$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_options_OBJECTS) $(test_options_LDADD) $(LIBS)
+
+test_parse_cookies$(EXEEXT): $(test_parse_cookies_OBJECTS) $(test_parse_cookies_DEPENDENCIES) $(EXTRA_test_parse_cookies_DEPENDENCIES)
+ @rm -f test_parse_cookies$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_parse_cookies_OBJECTS) $(test_parse_cookies_LDADD) $(LIBS)
+
+test_post$(EXEEXT): $(test_post_OBJECTS) $(test_post_DEPENDENCIES) $(EXTRA_test_post_DEPENDENCIES)
+ @rm -f test_post$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_post_OBJECTS) $(test_post_LDADD) $(LIBS)
+
+test_post11$(EXEEXT): $(test_post11_OBJECTS) $(test_post11_DEPENDENCIES) $(EXTRA_test_post11_DEPENDENCIES)
+ @rm -f test_post11$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_post11_OBJECTS) $(test_post11_LDADD) $(LIBS)
+
+test_post_loop$(EXEEXT): $(test_post_loop_OBJECTS) $(test_post_loop_DEPENDENCIES) $(EXTRA_test_post_loop_DEPENDENCIES)
+ @rm -f test_post_loop$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_post_loop_OBJECTS) $(test_post_loop_LDADD) $(LIBS)
+
+test_post_loop11$(EXEEXT): $(test_post_loop11_OBJECTS) $(test_post_loop11_DEPENDENCIES) $(EXTRA_test_post_loop11_DEPENDENCIES)
+ @rm -f test_post_loop11$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_post_loop11_OBJECTS) $(test_post_loop11_LDADD) $(LIBS)
+
+test_postform$(EXEEXT): $(test_postform_OBJECTS) $(test_postform_DEPENDENCIES) $(EXTRA_test_postform_DEPENDENCIES)
+ @rm -f test_postform$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_postform_OBJECTS) $(test_postform_LDADD) $(LIBS)
+
+test_postform11$(EXEEXT): $(test_postform11_OBJECTS) $(test_postform11_DEPENDENCIES) $(EXTRA_test_postform11_DEPENDENCIES)
+ @rm -f test_postform11$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_postform11_OBJECTS) $(test_postform11_LDADD) $(LIBS)
+
+test_process_arguments$(EXEEXT): $(test_process_arguments_OBJECTS) $(test_process_arguments_DEPENDENCIES) $(EXTRA_test_process_arguments_DEPENDENCIES)
+ @rm -f test_process_arguments$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_process_arguments_OBJECTS) $(test_process_arguments_LDADD) $(LIBS)
+
+test_process_headers$(EXEEXT): $(test_process_headers_OBJECTS) $(test_process_headers_DEPENDENCIES) $(EXTRA_test_process_headers_DEPENDENCIES)
+ @rm -f test_process_headers$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_process_headers_OBJECTS) $(test_process_headers_LDADD) $(LIBS)
+
+test_put$(EXEEXT): $(test_put_OBJECTS) $(test_put_DEPENDENCIES) $(EXTRA_test_put_DEPENDENCIES)
+ @rm -f test_put$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_put_OBJECTS) $(test_put_LDADD) $(LIBS)
+
+test_put11$(EXEEXT): $(test_put11_OBJECTS) $(test_put11_DEPENDENCIES) $(EXTRA_test_put11_DEPENDENCIES)
+ @rm -f test_put11$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_put11_OBJECTS) $(test_put11_LDADD) $(LIBS)
+
+test_put_chunked$(EXEEXT): $(test_put_chunked_OBJECTS) $(test_put_chunked_DEPENDENCIES) $(EXTRA_test_put_chunked_DEPENDENCIES)
+ @rm -f test_put_chunked$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_put_chunked_OBJECTS) $(test_put_chunked_LDADD) $(LIBS)
+
+test_quiesce$(EXEEXT): $(test_quiesce_OBJECTS) $(test_quiesce_DEPENDENCIES) $(EXTRA_test_quiesce_DEPENDENCIES)
+ @rm -f test_quiesce$(EXEEXT)
+ $(AM_V_CCLD)$(test_quiesce_LINK) $(test_quiesce_OBJECTS) $(test_quiesce_LDADD) $(LIBS)
+
+test_start_stop$(EXEEXT): $(test_start_stop_OBJECTS) $(test_start_stop_DEPENDENCIES) $(EXTRA_test_start_stop_DEPENDENCIES)
+ @rm -f test_start_stop$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_start_stop_OBJECTS) $(test_start_stop_LDADD) $(LIBS)
+
+test_termination$(EXEEXT): $(test_termination_OBJECTS) $(test_termination_DEPENDENCIES) $(EXTRA_test_termination_DEPENDENCIES)
+ @rm -f test_termination$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_termination_OBJECTS) $(test_termination_LDADD) $(LIBS)
+
+test_timeout$(EXEEXT): $(test_timeout_OBJECTS) $(test_timeout_DEPENDENCIES) $(EXTRA_test_timeout_DEPENDENCIES)
+ @rm -f test_timeout$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_timeout_OBJECTS) $(test_timeout_LDADD) $(LIBS)
+
+test_urlparse$(EXEEXT): $(test_urlparse_OBJECTS) $(test_urlparse_DEPENDENCIES) $(EXTRA_test_urlparse_DEPENDENCIES)
+ @rm -f test_urlparse$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_urlparse_OBJECTS) $(test_urlparse_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/curl_version_check.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_get.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_get_concurrent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_callback.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_concurrent_stop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_digestauth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_digestauth_with_arguments.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_get.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_get_chunked.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_get_response_cleanup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_get_sendfile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_iplimit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_large_put.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_long_header.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_options.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_parse_cookies.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_post.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_post_loop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_postform.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_process_arguments.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_process_headers.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_put.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_put_chunked.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_quiesce-test_quiesce.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_start_stop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_termination.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_timeout.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_urlparse.Po@am__quote@
+
+.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 $@ $<
+
+test_quiesce-test_quiesce.o: test_quiesce.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_quiesce_CFLAGS) $(CFLAGS) -MT test_quiesce-test_quiesce.o -MD -MP -MF $(DEPDIR)/test_quiesce-test_quiesce.Tpo -c -o test_quiesce-test_quiesce.o `test -f 'test_quiesce.c' || echo '$(srcdir)/'`test_quiesce.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_quiesce-test_quiesce.Tpo $(DEPDIR)/test_quiesce-test_quiesce.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test_quiesce.c' object='test_quiesce-test_quiesce.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_quiesce_CFLAGS) $(CFLAGS) -c -o test_quiesce-test_quiesce.o `test -f 'test_quiesce.c' || echo '$(srcdir)/'`test_quiesce.c
+
+test_quiesce-test_quiesce.obj: test_quiesce.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_quiesce_CFLAGS) $(CFLAGS) -MT test_quiesce-test_quiesce.obj -MD -MP -MF $(DEPDIR)/test_quiesce-test_quiesce.Tpo -c -o test_quiesce-test_quiesce.obj `if test -f 'test_quiesce.c'; then $(CYGPATH_W) 'test_quiesce.c'; else $(CYGPATH_W) '$(srcdir)/test_quiesce.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_quiesce-test_quiesce.Tpo $(DEPDIR)/test_quiesce-test_quiesce.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test_quiesce.c' object='test_quiesce-test_quiesce.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_quiesce_CFLAGS) $(CFLAGS) -c -o test_quiesce-test_quiesce.obj `if test -f 'test_quiesce.c'; then $(CYGPATH_W) 'test_quiesce.c'; else $(CYGPATH_W) '$(srcdir)/test_quiesce.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(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-recursive
+
+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-recursive
+
+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
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ else \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+test_start_stop.log: test_start_stop$(EXEEXT)
+ @p='test_start_stop$(EXEEXT)'; \
+ b='test_start_stop'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_get.log: test_get$(EXEEXT)
+ @p='test_get$(EXEEXT)'; \
+ b='test_get'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_get_sendfile.log: test_get_sendfile$(EXEEXT)
+ @p='test_get_sendfile$(EXEEXT)'; \
+ b='test_get_sendfile'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_urlparse.log: test_urlparse$(EXEEXT)
+ @p='test_urlparse$(EXEEXT)'; \
+ b='test_urlparse'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_put.log: test_put$(EXEEXT)
+ @p='test_put$(EXEEXT)'; \
+ b='test_put'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_concurrent_stop.log: test_concurrent_stop$(EXEEXT)
+ @p='test_concurrent_stop$(EXEEXT)'; \
+ b='test_concurrent_stop'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_process_headers.log: test_process_headers$(EXEEXT)
+ @p='test_process_headers$(EXEEXT)'; \
+ b='test_process_headers'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_process_arguments.log: test_process_arguments$(EXEEXT)
+ @p='test_process_arguments$(EXEEXT)'; \
+ b='test_process_arguments'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_parse_cookies.log: test_parse_cookies$(EXEEXT)
+ @p='test_parse_cookies$(EXEEXT)'; \
+ b='test_parse_cookies'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_large_put.log: test_large_put$(EXEEXT)
+ @p='test_large_put$(EXEEXT)'; \
+ b='test_large_put'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_get11.log: test_get11$(EXEEXT)
+ @p='test_get11$(EXEEXT)'; \
+ b='test_get11'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_get_sendfile11.log: test_get_sendfile11$(EXEEXT)
+ @p='test_get_sendfile11$(EXEEXT)'; \
+ b='test_get_sendfile11'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_put11.log: test_put11$(EXEEXT)
+ @p='test_put11$(EXEEXT)'; \
+ b='test_put11'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_large_put11.log: test_large_put11$(EXEEXT)
+ @p='test_large_put11$(EXEEXT)'; \
+ b='test_large_put11'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_long_header.log: test_long_header$(EXEEXT)
+ @p='test_long_header$(EXEEXT)'; \
+ b='test_long_header'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_long_header11.log: test_long_header11$(EXEEXT)
+ @p='test_long_header11$(EXEEXT)'; \
+ b='test_long_header11'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_get_chunked.log: test_get_chunked$(EXEEXT)
+ @p='test_get_chunked$(EXEEXT)'; \
+ b='test_get_chunked'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_put_chunked.log: test_put_chunked$(EXEEXT)
+ @p='test_put_chunked$(EXEEXT)'; \
+ b='test_put_chunked'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_iplimit11.log: test_iplimit11$(EXEEXT)
+ @p='test_iplimit11$(EXEEXT)'; \
+ b='test_iplimit11'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_termination.log: test_termination$(EXEEXT)
+ @p='test_termination$(EXEEXT)'; \
+ b='test_termination'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_timeout.log: test_timeout$(EXEEXT)
+ @p='test_timeout$(EXEEXT)'; \
+ b='test_timeout'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_callback.log: test_callback$(EXEEXT)
+ @p='test_callback$(EXEEXT)'; \
+ b='test_callback'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_get_response_cleanup.log: test_get_response_cleanup$(EXEEXT)
+ @p='test_get_response_cleanup$(EXEEXT)'; \
+ b='test_get_response_cleanup'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+perf_get.log: perf_get$(EXEEXT)
+ @p='perf_get$(EXEEXT)'; \
+ b='perf_get'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+perf_get_concurrent.log: perf_get_concurrent$(EXEEXT)
+ @p='perf_get_concurrent$(EXEEXT)'; \
+ b='perf_get_concurrent'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_quiesce.log: test_quiesce$(EXEEXT)
+ @p='test_quiesce$(EXEEXT)'; \
+ b='test_quiesce'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_post.log: test_post$(EXEEXT)
+ @p='test_post$(EXEEXT)'; \
+ b='test_post'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_postform.log: test_postform$(EXEEXT)
+ @p='test_postform$(EXEEXT)'; \
+ b='test_postform'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_post_loop.log: test_post_loop$(EXEEXT)
+ @p='test_post_loop$(EXEEXT)'; \
+ b='test_post_loop'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_post11.log: test_post11$(EXEEXT)
+ @p='test_post11$(EXEEXT)'; \
+ b='test_post11'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_postform11.log: test_postform11$(EXEEXT)
+ @p='test_postform11$(EXEEXT)'; \
+ b='test_postform11'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_post_loop11.log: test_post_loop11$(EXEEXT)
+ @p='test_post_loop11$(EXEEXT)'; \
+ b='test_post_loop11'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_digestauth.log: test_digestauth$(EXEEXT)
+ @p='test_digestauth$(EXEEXT)'; \
+ b='test_digestauth'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_digestauth_with_arguments.log: test_digestauth_with_arguments$(EXEEXT)
+ @p='test_digestauth_with_arguments$(EXEEXT)'; \
+ b='test_digestauth_with_arguments'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(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
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(LIBRARIES) $(PROGRAMS)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+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:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+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-recursive
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-noinstLIBRARIES clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-TESTS check-am clean clean-checkPROGRAMS clean-generic \
+ clean-libtool clean-noinstLIBRARIES 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 installdirs-am \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am recheck tags tags-am uninstall \
+ uninstall-am
+
+
+# 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:
diff --git a/src/testcurl/curl_version_check.c b/src/testcurl/curl_version_check.c
new file mode 100644
index 0000000..518cb86
--- /dev/null
+++ b/src/testcurl/curl_version_check.c
@@ -0,0 +1,176 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file curl_version_check.c
+ * @brief verify required cURL version is available to run tests
+ * @author Sagie Amir
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+static int
+parse_version_number (const char **s)
+{
+ int i = 0;
+ char num[17];
+
+ while (i < 16 && ((**s >= '0') & (**s <= '9')))
+ {
+ num[i] = **s;
+ (*s)++;
+ i++;
+ }
+
+ num[i] = '\0';
+
+ return atoi (num);
+}
+
+const char *
+parse_version_string (const char *s, int *major, int *minor, int *micro)
+{
+ if (!s)
+ return NULL;
+ *major = parse_version_number (&s);
+ if (*s != '.')
+ return NULL;
+ s++;
+ *minor = parse_version_number (&s);
+ if (*s != '.')
+ return NULL;
+ s++;
+ *micro = parse_version_number (&s);
+ return s;
+}
+
+#if HTTPS_SUPPORT
+int
+curl_uses_nss_ssl()
+{
+ return (strstr(curl_version(), " NSS/") != NULL) ? 0 : -1;
+}
+#endif
+
+/*
+ * check local libcurl version matches required version
+ */
+int
+curl_check_version (const char *req_version)
+{
+ const char *ver;
+ const char *curl_ver;
+#if HTTPS_SUPPORT
+ const char *ssl_ver;
+ const char *req_ssl_ver;
+#endif
+
+ int loc_major, loc_minor, loc_micro;
+ int rq_major, rq_minor, rq_micro;
+
+ ver = curl_version ();
+#if HAVE_MESSAGES
+ fprintf (stderr, "curl version: %s\n", ver);
+#endif
+ /*
+ * this call relies on the cURL string to be of the exact following format :
+ * 'libcurl/7.16.4 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/0.6.5' OR
+ * 'libcurl/7.18.2 GnuTLS/2.4.0 zlib/1.2.3.3 libidn/0.6.5'
+ */
+ curl_ver = strchr (ver, '/');
+ if (curl_ver == NULL)
+ return -1;
+ curl_ver++;
+ /* Parse version numbers */
+ if ( (NULL == parse_version_string (req_version, &rq_major, &rq_minor, &rq_micro)) ||
+ (NULL == parse_version_string (curl_ver, &loc_major, &loc_minor, &loc_micro)) )
+ return -1;
+
+ /* Compare version numbers. */
+ if ((loc_major > rq_major
+ || (loc_major == rq_major && loc_minor > rq_minor)
+ || (loc_major == rq_major && loc_minor == rq_minor
+ && loc_micro > rq_micro) || (loc_major == rq_major
+ && loc_minor == rq_minor
+ && loc_micro == rq_micro)) == 0)
+ {
+ fprintf (stderr,
+ "Error: running curl test depends on local libcurl version > %s\n",
+ req_version);
+ return -1;
+ }
+
+ /*
+ * enforce required gnutls/openssl version.
+ * TODO use curl version string to assert use of gnutls
+ */
+#if HTTPS_SUPPORT
+ ssl_ver = strchr (curl_ver, ' ');
+ if (ssl_ver == NULL)
+ return -1;
+ ssl_ver++;
+ if (strncmp ("GnuTLS", ssl_ver, strlen ("GNUtls")) == 0)
+ {
+ ssl_ver = strchr (ssl_ver, '/');
+ req_ssl_ver = MHD_REQ_CURL_GNUTLS_VERSION;
+ }
+ else if (strncmp ("OpenSSL", ssl_ver, strlen ("OpenSSL")) == 0)
+ {
+ ssl_ver = strchr (ssl_ver, '/');
+ req_ssl_ver = MHD_REQ_CURL_OPENSSL_VERSION;
+ }
+ else if (strncmp ("NSS", ssl_ver, strlen ("NSS")) == 0)
+ {
+ ssl_ver = strchr (ssl_ver, '/');
+ req_ssl_ver = MHD_REQ_CURL_NSS_VERSION;
+ }
+ else
+ {
+ fprintf (stderr, "Error: unrecognized curl ssl library\n");
+ return -1;
+ }
+ if (ssl_ver == NULL)
+ return -1;
+ ssl_ver++;
+ if ( (NULL == parse_version_string (req_ssl_ver, &rq_major, &rq_minor, &rq_micro)) ||
+ (NULL == parse_version_string (ssl_ver, &loc_major, &loc_minor, &loc_micro)) )
+ return -1;
+
+ if ((loc_major > rq_major
+ || (loc_major == rq_major && loc_minor > rq_minor)
+ || (loc_major == rq_major && loc_minor == rq_minor
+ && loc_micro > rq_micro) || (loc_major == rq_major
+ && loc_minor == rq_minor
+ && loc_micro == rq_micro)) == 0)
+ {
+ fprintf (stderr,
+ "Error: running curl test depends on local libcurl SSL version > %s\n",
+ req_ssl_ver);
+ return -1;
+ }
+#endif
+ return 0;
+}
diff --git a/src/testcurl/gauger.h b/src/testcurl/gauger.h
new file mode 100644
index 0000000..3a0dd22
--- /dev/null
+++ b/src/testcurl/gauger.h
@@ -0,0 +1,86 @@
+/** ---------------------------------------------------------------------------
+ * This software is in the public domain, furnished "as is", without technical
+ * support, and with no warranty, express or implied, as to its usefulness for
+ * any purpose.
+ *
+ * gauger.h
+ * Interface for C programs to log remotely to a gauger server
+ *
+ * Author: Bartlomiej Polot
+ * -------------------------------------------------------------------------*/
+#ifndef __GAUGER_H__
+#define __GAUGER_H__
+
+#ifndef WINDOWS
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/wait.h>
+
+#define GAUGER(category, counter, value, unit)\
+{\
+ const char * __gauger_v[10]; \
+ char __gauger_s[32];\
+ pid_t __gauger_p;\
+ if(!(__gauger_p=fork())){\
+ if(!fork()){ \
+ sprintf(__gauger_s,"%Lf", (long double) (value));\
+ __gauger_v[0] = "gauger";\
+ __gauger_v[1] = "-n";\
+ __gauger_v[2] = counter; \
+ __gauger_v[3] = "-d";\
+ __gauger_v[4] = __gauger_s;\
+ __gauger_v[5] = "-u";\
+ __gauger_v[6] = unit; \
+ __gauger_v[7] = "-c";\
+ __gauger_v[8] = category; \
+ __gauger_v[9] = (char *)NULL;\
+ execvp("gauger", (char*const*) __gauger_v); \
+ _exit(1);\
+ }else{\
+ _exit(0);\
+ }\
+ }else{\
+ waitpid(__gauger_p,NULL,0);\
+ }\
+}
+
+#define GAUGER_ID(category, counter, value, unit, id)\
+{\
+ char* __gauger_v[12];\
+ char __gauger_s[32];\
+ pid_t __gauger_p;\
+ if(!(__gauger_p=fork())){\
+ if(!fork()){\
+ sprintf(__gauger_s,"%Lf", (long double) (value));\
+ __gauger_v[0] = "gauger";\
+ __gauger_v[1] = "-n";\
+ __gauger_v[2] = counter;\
+ __gauger_v[3] = "-d";\
+ __gauger_v[4] = __gauger_s;\
+ __gauger_v[5] = "-u";\
+ __gauger_v[6] = unit;\
+ __gauger_v[7] = "-i";\
+ __gauger_v[8] = id;\
+ __gauger_v[9] = "-c";\
+ __gauger_v[10] = category;\
+ __gauger_v[11] = (char *)NULL;\
+ execvp("gauger",__gauger_v);\
+ perror("gauger");\
+ _exit(1);\
+ }else{\
+ _exit(0);\
+ }\
+ }else{\
+ waitpid(__gauger_p,NULL,0);\
+ }\
+}
+
+#else
+
+#define GAUGER_ID(category, counter, value, unit, id) {}
+#define GAUGER(category, counter, value, unit) {}
+
+#endif // WINDOWS
+
+#endif
diff --git a/src/testcurl/https/Makefile.am b/src/testcurl/https/Makefile.am
new file mode 100644
index 0000000..47deb70
--- /dev/null
+++ b/src/testcurl/https/Makefile.am
@@ -0,0 +1,153 @@
+# This Makefile.am is in the public domain
+SUBDIRS = .
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage
+endif
+
+if HAVE_GNUTLS_SNI
+ TEST_HTTPS_SNI = test_https_sni
+endif
+
+if HAVE_POSIX_THREADS
+ HTTPS_PARALLEL_TESTS = test_https_get_parallel \
+ test_https_get_parallel_threads
+endif
+
+CPU_COUNT_DEF = -DCPU_COUNT=$(CPU_COUNT)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/include \
+ -I$(top_srcdir)/src/microhttpd \
+ -I$(top_srcdir)/src/platform \
+ $(LIBCURL_CPPFLAGS) $(GNUTLS_CPPFLAGS)
+
+check_PROGRAMS = \
+ test_tls_options \
+ test_tls_authentication \
+ test_https_multi_daemon \
+ test_https_get \
+ $(TEST_HTTPS_SNI) \
+ test_https_get_select \
+ $(HTTPS_PARALLEL_TESTS) \
+ test_https_session_info \
+ test_https_time_out \
+ test_empty_response
+
+EXTRA_DIST = cert.pem key.pem tls_test_keys.h tls_test_common.h \
+ host1.crt host1.key host2.crt host2.key
+
+TESTS = \
+ test_tls_options \
+ test_https_multi_daemon \
+ test_https_get \
+ $(TEST_HTTPS_SNI) \
+ test_https_get_select \
+ $(HTTPS_PARALLEL_TESTS) \
+ test_https_session_info \
+ test_https_time_out \
+ test_tls_authentication \
+ test_empty_response
+
+
+test_https_time_out_SOURCES = \
+ test_https_time_out.c \
+ tls_test_common.c
+test_https_time_out_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_tls_options_SOURCES = \
+ test_tls_options.c \
+ tls_test_common.c
+test_tls_options_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_get_parallel_SOURCES = \
+ test_https_get_parallel.c \
+ tls_test_common.c
+test_https_get_parallel_CPPFLAGS = \
+ $(AM_CPPFLAGS) $(CPU_COUNT_DEF)
+test_https_get_parallel_CFLAGS = \
+ $(PTHREAD_CFLAGS) $(AM_CFLAGS)
+test_https_get_parallel_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(PTHREAD_LIBS) $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_empty_response_SOURCES = \
+ test_empty_response.c \
+ tls_test_common.c
+test_empty_response_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_get_parallel_threads_SOURCES = \
+ test_https_get_parallel_threads.c \
+ tls_test_common.c
+test_https_get_parallel_threads_CPPFLAGS = \
+ $(AM_CPPFLAGS) $(CPU_COUNT_DEF)
+test_https_get_parallel_threads_CFLAGS = \
+ $(PTHREAD_CFLAGS) $(AM_CFLAGS)
+test_https_get_parallel_threads_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(PTHREAD_LIBS) $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_tls_authentication_SOURCES = \
+ test_tls_authentication.c \
+ tls_test_common.c
+test_tls_authentication_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_session_info_SOURCES = \
+ test_https_session_info.c \
+ tls_test_common.c
+test_https_session_info_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_multi_daemon_SOURCES = \
+ test_https_multi_daemon.c \
+ tls_test_common.c
+test_https_multi_daemon_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_get_SOURCES = \
+ test_https_get.c \
+ tls_test_common.c
+test_https_get_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+if HAVE_GNUTLS_SNI
+test_https_sni_SOURCES = \
+ test_https_sni.c \
+ tls_test_common.c
+test_https_sni_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DABS_SRCDIR=\"$(abs_srcdir)\"
+test_https_sni_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+endif
+
+test_https_get_select_SOURCES = \
+ test_https_get_select.c \
+ tls_test_common.c
+test_https_get_select_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
diff --git a/src/testcurl/https/Makefile.in b/src/testcurl/https/Makefile.in
new file mode 100644
index 0000000..8815b21
--- /dev/null
+++ b/src/testcurl/https/Makefile.in
@@ -0,0 +1,1578 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 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@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+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@
+check_PROGRAMS = test_tls_options$(EXEEXT) \
+ test_tls_authentication$(EXEEXT) \
+ test_https_multi_daemon$(EXEEXT) test_https_get$(EXEEXT) \
+ $(am__EXEEXT_1) test_https_get_select$(EXEEXT) $(am__EXEEXT_2) \
+ test_https_session_info$(EXEEXT) test_https_time_out$(EXEEXT) \
+ test_empty_response$(EXEEXT)
+TESTS = test_tls_options$(EXEEXT) test_https_multi_daemon$(EXEEXT) \
+ test_https_get$(EXEEXT) $(am__EXEEXT_1) \
+ test_https_get_select$(EXEEXT) $(am__EXEEXT_2) \
+ test_https_session_info$(EXEEXT) test_https_time_out$(EXEEXT) \
+ test_tls_authentication$(EXEEXT) test_empty_response$(EXEEXT)
+subdir = src/testcurl/https
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(top_srcdir)/test-driver
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_compile_flags.m4 \
+ $(top_srcdir)/m4/ax_append_flag.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_count_cpus.m4 \
+ $(top_srcdir)/m4/ax_have_epoll.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_require_defined.m4 \
+ $(top_srcdir)/m4/libcurl.m4 $(top_srcdir)/m4/libgcrypt.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)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/MHD_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_GNUTLS_SNI_TRUE@am__EXEEXT_1 = test_https_sni$(EXEEXT)
+@HAVE_POSIX_THREADS_TRUE@am__EXEEXT_2 = \
+@HAVE_POSIX_THREADS_TRUE@ test_https_get_parallel$(EXEEXT) \
+@HAVE_POSIX_THREADS_TRUE@ test_https_get_parallel_threads$(EXEEXT)
+am_test_empty_response_OBJECTS = test_empty_response.$(OBJEXT) \
+ tls_test_common.$(OBJEXT)
+test_empty_response_OBJECTS = $(am_test_empty_response_OBJECTS)
+am__DEPENDENCIES_1 =
+test_empty_response_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+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_test_https_get_OBJECTS = test_https_get.$(OBJEXT) \
+ tls_test_common.$(OBJEXT)
+test_https_get_OBJECTS = $(am_test_https_get_OBJECTS)
+test_https_get_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_test_https_get_parallel_OBJECTS = \
+ test_https_get_parallel-test_https_get_parallel.$(OBJEXT) \
+ test_https_get_parallel-tls_test_common.$(OBJEXT)
+test_https_get_parallel_OBJECTS = \
+ $(am_test_https_get_parallel_OBJECTS)
+test_https_get_parallel_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+test_https_get_parallel_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(test_https_get_parallel_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am_test_https_get_parallel_threads_OBJECTS = test_https_get_parallel_threads-test_https_get_parallel_threads.$(OBJEXT) \
+ test_https_get_parallel_threads-tls_test_common.$(OBJEXT)
+test_https_get_parallel_threads_OBJECTS = \
+ $(am_test_https_get_parallel_threads_OBJECTS)
+test_https_get_parallel_threads_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+test_https_get_parallel_threads_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(test_https_get_parallel_threads_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+am_test_https_get_select_OBJECTS = test_https_get_select.$(OBJEXT) \
+ tls_test_common.$(OBJEXT)
+test_https_get_select_OBJECTS = $(am_test_https_get_select_OBJECTS)
+test_https_get_select_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_test_https_multi_daemon_OBJECTS = \
+ test_https_multi_daemon.$(OBJEXT) tls_test_common.$(OBJEXT)
+test_https_multi_daemon_OBJECTS = \
+ $(am_test_https_multi_daemon_OBJECTS)
+test_https_multi_daemon_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_test_https_session_info_OBJECTS = \
+ test_https_session_info.$(OBJEXT) tls_test_common.$(OBJEXT)
+test_https_session_info_OBJECTS = \
+ $(am_test_https_session_info_OBJECTS)
+test_https_session_info_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__test_https_sni_SOURCES_DIST = test_https_sni.c tls_test_common.c
+@HAVE_GNUTLS_SNI_TRUE@am_test_https_sni_OBJECTS = \
+@HAVE_GNUTLS_SNI_TRUE@ test_https_sni-test_https_sni.$(OBJEXT) \
+@HAVE_GNUTLS_SNI_TRUE@ test_https_sni-tls_test_common.$(OBJEXT)
+test_https_sni_OBJECTS = $(am_test_https_sni_OBJECTS)
+@HAVE_GNUTLS_SNI_TRUE@test_https_sni_DEPENDENCIES = $(top_builddir)/src/testcurl/libcurl_version_check.a \
+@HAVE_GNUTLS_SNI_TRUE@ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+@HAVE_GNUTLS_SNI_TRUE@ $(am__DEPENDENCIES_1) \
+@HAVE_GNUTLS_SNI_TRUE@ $(am__DEPENDENCIES_1)
+am_test_https_time_out_OBJECTS = test_https_time_out.$(OBJEXT) \
+ tls_test_common.$(OBJEXT)
+test_https_time_out_OBJECTS = $(am_test_https_time_out_OBJECTS)
+test_https_time_out_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_test_tls_authentication_OBJECTS = \
+ test_tls_authentication.$(OBJEXT) tls_test_common.$(OBJEXT)
+test_tls_authentication_OBJECTS = \
+ $(am_test_tls_authentication_OBJECTS)
+test_tls_authentication_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_test_tls_options_OBJECTS = test_tls_options.$(OBJEXT) \
+ tls_test_common.$(OBJEXT)
+test_tls_options_OBJECTS = $(am_test_tls_options_OBJECTS)
+test_tls_options_DEPENDENCIES = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+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__depfiles_maybe = depfiles
+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 =
+SOURCES = $(test_empty_response_SOURCES) $(test_https_get_SOURCES) \
+ $(test_https_get_parallel_SOURCES) \
+ $(test_https_get_parallel_threads_SOURCES) \
+ $(test_https_get_select_SOURCES) \
+ $(test_https_multi_daemon_SOURCES) \
+ $(test_https_session_info_SOURCES) $(test_https_sni_SOURCES) \
+ $(test_https_time_out_SOURCES) \
+ $(test_tls_authentication_SOURCES) $(test_tls_options_SOURCES)
+DIST_SOURCES = $(test_empty_response_SOURCES) \
+ $(test_https_get_SOURCES) $(test_https_get_parallel_SOURCES) \
+ $(test_https_get_parallel_threads_SOURCES) \
+ $(test_https_get_select_SOURCES) \
+ $(test_https_multi_daemon_SOURCES) \
+ $(test_https_session_info_SOURCES) \
+ $(am__test_https_sni_SOURCES_DIST) \
+ $(test_https_time_out_SOURCES) \
+ $(test_tls_authentication_SOURCES) $(test_tls_options_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ check recheck distdir
+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__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red='[0;31m'; \
+ grn='[0;32m'; \
+ lgn='[1;32m'; \
+ blu='[1;34m'; \
+ mgn='[0;35m'; \
+ brg='[1m'; \
+ std='[m'; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPU_COUNT = @CPU_COUNT@
+CYGPATH_W = @CYGPATH_W@
+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@
+FGREP = @FGREP@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_CPPFLAGS = @GNUTLS_CPPFLAGS@
+GNUTLS_LDFLAGS = @GNUTLS_LDFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+HAVE_CURL_BINARY = @HAVE_CURL_BINARY@
+HAVE_MAKEINFO_BINARY = @HAVE_MAKEINFO_BINARY@
+HIDDEN_VISIBILITY_CFLAGS = @HIDDEN_VISIBILITY_CFLAGS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSPDY_VERSION_AGE = @LIBSPDY_VERSION_AGE@
+LIBSPDY_VERSION_CURRENT = @LIBSPDY_VERSION_CURRENT@
+LIBSPDY_VERSION_REVISION = @LIBSPDY_VERSION_REVISION@
+LIBTOOL = @LIBTOOL@
+LIB_VERSION_AGE = @LIB_VERSION_AGE@
+LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@
+LIB_VERSION_REVISION = @LIB_VERSION_REVISION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MHD_LIBDEPS = @MHD_LIBDEPS@
+MHD_LIBDEPS_PKGCFG = @MHD_LIBDEPS_PKGCFG@
+MHD_LIB_CFLAGS = @MHD_LIB_CFLAGS@
+MHD_LIB_CPPFLAGS = @MHD_LIB_CPPFLAGS@
+MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@
+MHD_REQ_PRIVATE = @MHD_REQ_PRIVATE@
+MKDIR_P = @MKDIR_P@
+MS_LIB_TOOL = @MS_LIB_TOOL@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+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_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_SUBMINOR = @PACKAGE_VERSION_SUBMINOR@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPDY_LIBDEPS = @SPDY_LIBDEPS@
+SPDY_LIB_CFLAGS = @SPDY_LIB_CFLAGS@
+SPDY_LIB_CPPFLAGS = @SPDY_LIB_CPPFLAGS@
+SPDY_LIB_LDFLAGS = @SPDY_LIB_LDFLAGS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+_libcurl_config = @_libcurl_config@
+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_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@
+ax_pthread_config = @ax_pthread_config@
+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@
+have_socat = @have_socat@
+have_zzuf = @have_zzuf@
+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@
+lt_cv_objdir = @lt_cv_objdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# This Makefile.am is in the public domain
+SUBDIRS = .
+@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage
+@HAVE_GNUTLS_SNI_TRUE@TEST_HTTPS_SNI = test_https_sni
+@HAVE_POSIX_THREADS_TRUE@HTTPS_PARALLEL_TESTS = test_https_get_parallel \
+@HAVE_POSIX_THREADS_TRUE@ test_https_get_parallel_threads
+
+CPU_COUNT_DEF = -DCPU_COUNT=$(CPU_COUNT)
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/include \
+ -I$(top_srcdir)/src/microhttpd \
+ -I$(top_srcdir)/src/platform \
+ $(LIBCURL_CPPFLAGS) $(GNUTLS_CPPFLAGS)
+
+EXTRA_DIST = cert.pem key.pem tls_test_keys.h tls_test_common.h \
+ host1.crt host1.key host2.crt host2.key
+
+test_https_time_out_SOURCES = \
+ test_https_time_out.c \
+ tls_test_common.c
+
+test_https_time_out_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_tls_options_SOURCES = \
+ test_tls_options.c \
+ tls_test_common.c
+
+test_tls_options_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_get_parallel_SOURCES = \
+ test_https_get_parallel.c \
+ tls_test_common.c
+
+test_https_get_parallel_CPPFLAGS = \
+ $(AM_CPPFLAGS) $(CPU_COUNT_DEF)
+
+test_https_get_parallel_CFLAGS = \
+ $(PTHREAD_CFLAGS) $(AM_CFLAGS)
+
+test_https_get_parallel_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(PTHREAD_LIBS) $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_empty_response_SOURCES = \
+ test_empty_response.c \
+ tls_test_common.c
+
+test_empty_response_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_get_parallel_threads_SOURCES = \
+ test_https_get_parallel_threads.c \
+ tls_test_common.c
+
+test_https_get_parallel_threads_CPPFLAGS = \
+ $(AM_CPPFLAGS) $(CPU_COUNT_DEF)
+
+test_https_get_parallel_threads_CFLAGS = \
+ $(PTHREAD_CFLAGS) $(AM_CFLAGS)
+
+test_https_get_parallel_threads_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(PTHREAD_LIBS) $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_tls_authentication_SOURCES = \
+ test_tls_authentication.c \
+ tls_test_common.c
+
+test_tls_authentication_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_session_info_SOURCES = \
+ test_https_session_info.c \
+ tls_test_common.c
+
+test_https_session_info_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_multi_daemon_SOURCES = \
+ test_https_multi_daemon.c \
+ tls_test_common.c
+
+test_https_multi_daemon_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_get_SOURCES = \
+ test_https_get.c \
+ tls_test_common.c
+
+test_https_get_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+@HAVE_GNUTLS_SNI_TRUE@test_https_sni_SOURCES = \
+@HAVE_GNUTLS_SNI_TRUE@ test_https_sni.c \
+@HAVE_GNUTLS_SNI_TRUE@ tls_test_common.c
+
+@HAVE_GNUTLS_SNI_TRUE@test_https_sni_CPPFLAGS = \
+@HAVE_GNUTLS_SNI_TRUE@ $(AM_CPPFLAGS) \
+@HAVE_GNUTLS_SNI_TRUE@ -DABS_SRCDIR=\"$(abs_srcdir)\"
+
+@HAVE_GNUTLS_SNI_TRUE@test_https_sni_LDADD = \
+@HAVE_GNUTLS_SNI_TRUE@ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+@HAVE_GNUTLS_SNI_TRUE@ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+@HAVE_GNUTLS_SNI_TRUE@ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+test_https_get_select_SOURCES = \
+ test_https_get_select.c \
+ tls_test_common.c
+
+test_https_get_select_LDADD = \
+ $(top_builddir)/src/testcurl/libcurl_version_check.a \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+ $(GNUTLS_LDFLAGS) $(GNUTLS_LIBS) @LIBGCRYPT_LIBS@ @LIBCURL@
+
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(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 src/testcurl/https/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/testcurl/https/Makefile
+.PRECIOUS: 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__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ 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-checkPROGRAMS:
+ @list='$(check_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
+
+test_empty_response$(EXEEXT): $(test_empty_response_OBJECTS) $(test_empty_response_DEPENDENCIES) $(EXTRA_test_empty_response_DEPENDENCIES)
+ @rm -f test_empty_response$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_empty_response_OBJECTS) $(test_empty_response_LDADD) $(LIBS)
+
+test_https_get$(EXEEXT): $(test_https_get_OBJECTS) $(test_https_get_DEPENDENCIES) $(EXTRA_test_https_get_DEPENDENCIES)
+ @rm -f test_https_get$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_https_get_OBJECTS) $(test_https_get_LDADD) $(LIBS)
+
+test_https_get_parallel$(EXEEXT): $(test_https_get_parallel_OBJECTS) $(test_https_get_parallel_DEPENDENCIES) $(EXTRA_test_https_get_parallel_DEPENDENCIES)
+ @rm -f test_https_get_parallel$(EXEEXT)
+ $(AM_V_CCLD)$(test_https_get_parallel_LINK) $(test_https_get_parallel_OBJECTS) $(test_https_get_parallel_LDADD) $(LIBS)
+
+test_https_get_parallel_threads$(EXEEXT): $(test_https_get_parallel_threads_OBJECTS) $(test_https_get_parallel_threads_DEPENDENCIES) $(EXTRA_test_https_get_parallel_threads_DEPENDENCIES)
+ @rm -f test_https_get_parallel_threads$(EXEEXT)
+ $(AM_V_CCLD)$(test_https_get_parallel_threads_LINK) $(test_https_get_parallel_threads_OBJECTS) $(test_https_get_parallel_threads_LDADD) $(LIBS)
+
+test_https_get_select$(EXEEXT): $(test_https_get_select_OBJECTS) $(test_https_get_select_DEPENDENCIES) $(EXTRA_test_https_get_select_DEPENDENCIES)
+ @rm -f test_https_get_select$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_https_get_select_OBJECTS) $(test_https_get_select_LDADD) $(LIBS)
+
+test_https_multi_daemon$(EXEEXT): $(test_https_multi_daemon_OBJECTS) $(test_https_multi_daemon_DEPENDENCIES) $(EXTRA_test_https_multi_daemon_DEPENDENCIES)
+ @rm -f test_https_multi_daemon$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_https_multi_daemon_OBJECTS) $(test_https_multi_daemon_LDADD) $(LIBS)
+
+test_https_session_info$(EXEEXT): $(test_https_session_info_OBJECTS) $(test_https_session_info_DEPENDENCIES) $(EXTRA_test_https_session_info_DEPENDENCIES)
+ @rm -f test_https_session_info$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_https_session_info_OBJECTS) $(test_https_session_info_LDADD) $(LIBS)
+
+test_https_sni$(EXEEXT): $(test_https_sni_OBJECTS) $(test_https_sni_DEPENDENCIES) $(EXTRA_test_https_sni_DEPENDENCIES)
+ @rm -f test_https_sni$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_https_sni_OBJECTS) $(test_https_sni_LDADD) $(LIBS)
+
+test_https_time_out$(EXEEXT): $(test_https_time_out_OBJECTS) $(test_https_time_out_DEPENDENCIES) $(EXTRA_test_https_time_out_DEPENDENCIES)
+ @rm -f test_https_time_out$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_https_time_out_OBJECTS) $(test_https_time_out_LDADD) $(LIBS)
+
+test_tls_authentication$(EXEEXT): $(test_tls_authentication_OBJECTS) $(test_tls_authentication_DEPENDENCIES) $(EXTRA_test_tls_authentication_DEPENDENCIES)
+ @rm -f test_tls_authentication$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_tls_authentication_OBJECTS) $(test_tls_authentication_LDADD) $(LIBS)
+
+test_tls_options$(EXEEXT): $(test_tls_options_OBJECTS) $(test_tls_options_DEPENDENCIES) $(EXTRA_test_tls_options_DEPENDENCIES)
+ @rm -f test_tls_options$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_tls_options_OBJECTS) $(test_tls_options_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_empty_response.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_get.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_get_parallel-test_https_get_parallel.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_get_parallel-tls_test_common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_get_parallel_threads-test_https_get_parallel_threads.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_get_parallel_threads-tls_test_common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_get_select.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_multi_daemon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_session_info.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_sni-test_https_sni.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_sni-tls_test_common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https_time_out.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_tls_authentication.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_tls_options.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test_common.Po@am__quote@
+
+.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 $@ $<
+
+test_https_get_parallel-test_https_get_parallel.o: test_https_get_parallel.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_CFLAGS) $(CFLAGS) -MT test_https_get_parallel-test_https_get_parallel.o -MD -MP -MF $(DEPDIR)/test_https_get_parallel-test_https_get_parallel.Tpo -c -o test_https_get_parallel-test_https_get_parallel.o `test -f 'test_https_get_parallel.c' || echo '$(srcdir)/'`test_https_get_parallel.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_get_parallel-test_https_get_parallel.Tpo $(DEPDIR)/test_https_get_parallel-test_https_get_parallel.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test_https_get_parallel.c' object='test_https_get_parallel-test_https_get_parallel.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_CFLAGS) $(CFLAGS) -c -o test_https_get_parallel-test_https_get_parallel.o `test -f 'test_https_get_parallel.c' || echo '$(srcdir)/'`test_https_get_parallel.c
+
+test_https_get_parallel-test_https_get_parallel.obj: test_https_get_parallel.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_CFLAGS) $(CFLAGS) -MT test_https_get_parallel-test_https_get_parallel.obj -MD -MP -MF $(DEPDIR)/test_https_get_parallel-test_https_get_parallel.Tpo -c -o test_https_get_parallel-test_https_get_parallel.obj `if test -f 'test_https_get_parallel.c'; then $(CYGPATH_W) 'test_https_get_parallel.c'; else $(CYGPATH_W) '$(srcdir)/test_https_get_parallel.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_get_parallel-test_https_get_parallel.Tpo $(DEPDIR)/test_https_get_parallel-test_https_get_parallel.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test_https_get_parallel.c' object='test_https_get_parallel-test_https_get_parallel.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_CFLAGS) $(CFLAGS) -c -o test_https_get_parallel-test_https_get_parallel.obj `if test -f 'test_https_get_parallel.c'; then $(CYGPATH_W) 'test_https_get_parallel.c'; else $(CYGPATH_W) '$(srcdir)/test_https_get_parallel.c'; fi`
+
+test_https_get_parallel-tls_test_common.o: tls_test_common.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_CFLAGS) $(CFLAGS) -MT test_https_get_parallel-tls_test_common.o -MD -MP -MF $(DEPDIR)/test_https_get_parallel-tls_test_common.Tpo -c -o test_https_get_parallel-tls_test_common.o `test -f 'tls_test_common.c' || echo '$(srcdir)/'`tls_test_common.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_get_parallel-tls_test_common.Tpo $(DEPDIR)/test_https_get_parallel-tls_test_common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls_test_common.c' object='test_https_get_parallel-tls_test_common.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_CFLAGS) $(CFLAGS) -c -o test_https_get_parallel-tls_test_common.o `test -f 'tls_test_common.c' || echo '$(srcdir)/'`tls_test_common.c
+
+test_https_get_parallel-tls_test_common.obj: tls_test_common.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_CFLAGS) $(CFLAGS) -MT test_https_get_parallel-tls_test_common.obj -MD -MP -MF $(DEPDIR)/test_https_get_parallel-tls_test_common.Tpo -c -o test_https_get_parallel-tls_test_common.obj `if test -f 'tls_test_common.c'; then $(CYGPATH_W) 'tls_test_common.c'; else $(CYGPATH_W) '$(srcdir)/tls_test_common.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_get_parallel-tls_test_common.Tpo $(DEPDIR)/test_https_get_parallel-tls_test_common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls_test_common.c' object='test_https_get_parallel-tls_test_common.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_CFLAGS) $(CFLAGS) -c -o test_https_get_parallel-tls_test_common.obj `if test -f 'tls_test_common.c'; then $(CYGPATH_W) 'tls_test_common.c'; else $(CYGPATH_W) '$(srcdir)/tls_test_common.c'; fi`
+
+test_https_get_parallel_threads-test_https_get_parallel_threads.o: test_https_get_parallel_threads.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_threads_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_threads_CFLAGS) $(CFLAGS) -MT test_https_get_parallel_threads-test_https_get_parallel_threads.o -MD -MP -MF $(DEPDIR)/test_https_get_parallel_threads-test_https_get_parallel_threads.Tpo -c -o test_https_get_parallel_threads-test_https_get_parallel_threads.o `test -f 'test_https_get_parallel_threads.c' || echo '$(srcdir)/'`test_https_get_parallel_threads.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_get_parallel_threads-test_https_get_parallel_threads.Tpo $(DEPDIR)/test_https_get_parallel_threads-test_https_get_parallel_threads.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test_https_get_parallel_threads.c' object='test_https_get_parallel_threads-test_https_get_parallel_threads.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_threads_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_threads_CFLAGS) $(CFLAGS) -c -o test_https_get_parallel_threads-test_https_get_parallel_threads.o `test -f 'test_https_get_parallel_threads.c' || echo '$(srcdir)/'`test_https_get_parallel_threads.c
+
+test_https_get_parallel_threads-test_https_get_parallel_threads.obj: test_https_get_parallel_threads.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_threads_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_threads_CFLAGS) $(CFLAGS) -MT test_https_get_parallel_threads-test_https_get_parallel_threads.obj -MD -MP -MF $(DEPDIR)/test_https_get_parallel_threads-test_https_get_parallel_threads.Tpo -c -o test_https_get_parallel_threads-test_https_get_parallel_threads.obj `if test -f 'test_https_get_parallel_threads.c'; then $(CYGPATH_W) 'test_https_get_parallel_threads.c'; else $(CYGPATH_W) '$(srcdir)/test_https_get_parallel_threads.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_get_parallel_threads-test_https_get_parallel_threads.Tpo $(DEPDIR)/test_https_get_parallel_threads-test_https_get_parallel_threads.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test_https_get_parallel_threads.c' object='test_https_get_parallel_threads-test_https_get_parallel_threads.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_threads_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_threads_CFLAGS) $(CFLAGS) -c -o test_https_get_parallel_threads-test_https_get_parallel_threads.obj `if test -f 'test_https_get_parallel_threads.c'; then $(CYGPATH_W) 'test_https_get_parallel_threads.c'; else $(CYGPATH_W) '$(srcdir)/test_https_get_parallel_threads.c'; fi`
+
+test_https_get_parallel_threads-tls_test_common.o: tls_test_common.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_threads_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_threads_CFLAGS) $(CFLAGS) -MT test_https_get_parallel_threads-tls_test_common.o -MD -MP -MF $(DEPDIR)/test_https_get_parallel_threads-tls_test_common.Tpo -c -o test_https_get_parallel_threads-tls_test_common.o `test -f 'tls_test_common.c' || echo '$(srcdir)/'`tls_test_common.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_get_parallel_threads-tls_test_common.Tpo $(DEPDIR)/test_https_get_parallel_threads-tls_test_common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls_test_common.c' object='test_https_get_parallel_threads-tls_test_common.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_threads_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_threads_CFLAGS) $(CFLAGS) -c -o test_https_get_parallel_threads-tls_test_common.o `test -f 'tls_test_common.c' || echo '$(srcdir)/'`tls_test_common.c
+
+test_https_get_parallel_threads-tls_test_common.obj: tls_test_common.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_threads_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_threads_CFLAGS) $(CFLAGS) -MT test_https_get_parallel_threads-tls_test_common.obj -MD -MP -MF $(DEPDIR)/test_https_get_parallel_threads-tls_test_common.Tpo -c -o test_https_get_parallel_threads-tls_test_common.obj `if test -f 'tls_test_common.c'; then $(CYGPATH_W) 'tls_test_common.c'; else $(CYGPATH_W) '$(srcdir)/tls_test_common.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_get_parallel_threads-tls_test_common.Tpo $(DEPDIR)/test_https_get_parallel_threads-tls_test_common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls_test_common.c' object='test_https_get_parallel_threads-tls_test_common.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_get_parallel_threads_CPPFLAGS) $(CPPFLAGS) $(test_https_get_parallel_threads_CFLAGS) $(CFLAGS) -c -o test_https_get_parallel_threads-tls_test_common.obj `if test -f 'tls_test_common.c'; then $(CYGPATH_W) 'tls_test_common.c'; else $(CYGPATH_W) '$(srcdir)/tls_test_common.c'; fi`
+
+test_https_sni-test_https_sni.o: test_https_sni.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_sni_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_https_sni-test_https_sni.o -MD -MP -MF $(DEPDIR)/test_https_sni-test_https_sni.Tpo -c -o test_https_sni-test_https_sni.o `test -f 'test_https_sni.c' || echo '$(srcdir)/'`test_https_sni.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_sni-test_https_sni.Tpo $(DEPDIR)/test_https_sni-test_https_sni.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test_https_sni.c' object='test_https_sni-test_https_sni.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_sni_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_https_sni-test_https_sni.o `test -f 'test_https_sni.c' || echo '$(srcdir)/'`test_https_sni.c
+
+test_https_sni-test_https_sni.obj: test_https_sni.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_sni_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_https_sni-test_https_sni.obj -MD -MP -MF $(DEPDIR)/test_https_sni-test_https_sni.Tpo -c -o test_https_sni-test_https_sni.obj `if test -f 'test_https_sni.c'; then $(CYGPATH_W) 'test_https_sni.c'; else $(CYGPATH_W) '$(srcdir)/test_https_sni.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_sni-test_https_sni.Tpo $(DEPDIR)/test_https_sni-test_https_sni.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test_https_sni.c' object='test_https_sni-test_https_sni.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_sni_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_https_sni-test_https_sni.obj `if test -f 'test_https_sni.c'; then $(CYGPATH_W) 'test_https_sni.c'; else $(CYGPATH_W) '$(srcdir)/test_https_sni.c'; fi`
+
+test_https_sni-tls_test_common.o: tls_test_common.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_sni_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_https_sni-tls_test_common.o -MD -MP -MF $(DEPDIR)/test_https_sni-tls_test_common.Tpo -c -o test_https_sni-tls_test_common.o `test -f 'tls_test_common.c' || echo '$(srcdir)/'`tls_test_common.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_sni-tls_test_common.Tpo $(DEPDIR)/test_https_sni-tls_test_common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls_test_common.c' object='test_https_sni-tls_test_common.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_sni_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_https_sni-tls_test_common.o `test -f 'tls_test_common.c' || echo '$(srcdir)/'`tls_test_common.c
+
+test_https_sni-tls_test_common.obj: tls_test_common.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_sni_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_https_sni-tls_test_common.obj -MD -MP -MF $(DEPDIR)/test_https_sni-tls_test_common.Tpo -c -o test_https_sni-tls_test_common.obj `if test -f 'tls_test_common.c'; then $(CYGPATH_W) 'tls_test_common.c'; else $(CYGPATH_W) '$(srcdir)/tls_test_common.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_https_sni-tls_test_common.Tpo $(DEPDIR)/test_https_sni-tls_test_common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls_test_common.c' object='test_https_sni-tls_test_common.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_https_sni_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_https_sni-tls_test_common.obj `if test -f 'tls_test_common.c'; then $(CYGPATH_W) 'tls_test_common.c'; else $(CYGPATH_W) '$(srcdir)/tls_test_common.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(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-recursive
+
+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-recursive
+
+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
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ else \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+test_tls_options.log: test_tls_options$(EXEEXT)
+ @p='test_tls_options$(EXEEXT)'; \
+ b='test_tls_options'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_https_multi_daemon.log: test_https_multi_daemon$(EXEEXT)
+ @p='test_https_multi_daemon$(EXEEXT)'; \
+ b='test_https_multi_daemon'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_https_get.log: test_https_get$(EXEEXT)
+ @p='test_https_get$(EXEEXT)'; \
+ b='test_https_get'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_https_sni.log: test_https_sni$(EXEEXT)
+ @p='test_https_sni$(EXEEXT)'; \
+ b='test_https_sni'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_https_get_select.log: test_https_get_select$(EXEEXT)
+ @p='test_https_get_select$(EXEEXT)'; \
+ b='test_https_get_select'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_https_get_parallel.log: test_https_get_parallel$(EXEEXT)
+ @p='test_https_get_parallel$(EXEEXT)'; \
+ b='test_https_get_parallel'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_https_get_parallel_threads.log: test_https_get_parallel_threads$(EXEEXT)
+ @p='test_https_get_parallel_threads$(EXEEXT)'; \
+ b='test_https_get_parallel_threads'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_https_session_info.log: test_https_session_info$(EXEEXT)
+ @p='test_https_session_info$(EXEEXT)'; \
+ b='test_https_session_info'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_https_time_out.log: test_https_time_out$(EXEEXT)
+ @p='test_https_time_out$(EXEEXT)'; \
+ b='test_https_time_out'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_tls_authentication.log: test_tls_authentication$(EXEEXT)
+ @p='test_tls_authentication$(EXEEXT)'; \
+ b='test_tls_authentication'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_empty_response.log: test_empty_response$(EXEEXT)
+ @p='test_empty_response$(EXEEXT)'; \
+ b='test_empty_response'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(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
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+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:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+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-recursive
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-TESTS check-am clean clean-checkPROGRAMS clean-generic \
+ clean-libtool 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 \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
+ uninstall uninstall-am
+
+
+# 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:
diff --git a/src/testcurl/https/cert.pem b/src/testcurl/https/cert.pem
new file mode 100644
index 0000000..2c766df
--- /dev/null
+++ b/src/testcurl/https/cert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICpjCCAZCgAwIBAgIESEPtjjALBgkqhkiG9w0BAQUwADAeFw0wODA2MDIxMjU0
+MzhaFw0wOTA2MDIxMjU0NDZaMAAwggEfMAsGCSqGSIb3DQEBAQOCAQ4AMIIBCQKC
+AQC03TyUvK5HmUAirRp067taIEO4bibh5nqolUoUdo/LeblMQV+qnrv/RNAMTx5X
+fNLZ45/kbM9geF8qY0vsPyQvP4jumzK0LOJYuIwmHaUm9vbXnYieILiwCuTgjaud
+3VkZDoQ9fteIo+6we9UTpVqZpxpbLulBMh/VsvX0cPJ1VFC7rT59o9hAUlFf9jX/
+GmKdYI79MtgVx0OPBjmmSD6kicBBfmfgkO7bIGwlRtsIyMznxbHu6VuoX/eVxrTv
+rmCwgEXLWRZ6ru8MQl5YfqeGXXRVwMeXU961KefbuvmEPccgCxm8FZ1C1cnDHFXh
+siSgAzMBjC/b6KVhNQ4KnUdZAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0O
+BBYEFJcUvpjvE5fF/yzUshkWDpdYiQh/MAsGCSqGSIb3DQEBBQOCAQEARP7eKSB2
+RNd6XjEjK0SrxtoTnxS3nw9sfcS7/qD1+XHdObtDFqGNSjGYFB3Gpx8fpQhCXdoN
+8QUs3/5ZVa5yjZMQewWBgz8kNbnbH40F2y81MHITxxCe1Y+qqHWwVaYLsiOTqj2/
+0S3QjEJ9tvklmg7JX09HC4m5QRYfWBeQLD1u8ZjA1Sf1xJriomFVyRLI2VPO2bNe
+JDMXWuP+8kMC7gEvUnJ7A92Y2yrhu3QI3bjPk8uSpHea19Q77tul1UVBJ5g+zpH3
+OsF5p0MyaVf09GTzcLds5nE/osTdXGUyHJapWReVmPm3Zn6gqYlnzD99z+DPIgIV
+RhZvQx74NQnS6g==
+-----END CERTIFICATE-----
diff --git a/src/testcurl/https/host1.crt b/src/testcurl/https/host1.crt
new file mode 100644
index 0000000..d9b8b99
--- /dev/null
+++ b/src/testcurl/https/host1.crt
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICWTCCAcICCQDc4McLp7j56DANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJa
+WjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMQ4wDAYDVQQDDAVob3N0MTEZMBcGCSqGSIb3DQEJARYKdGVzdEBo
+b3N0MTAgFw0xMzExMTcxNTE2MzdaGA8yMTEzMTAyNDE1MTYzN1owcDELMAkGA1UE
+BhMCWloxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp
+ZGdpdHMgUHR5IEx0ZDEOMAwGA1UEAwwFaG9zdDExGTAXBgkqhkiG9w0BCQEWCnRl
+c3RAaG9zdDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKxYiRUzfQnekQn3
+6e+hP/mt/JEkiFzX5TV+E19ue2v4tc7lf+SoLEk2dVt5tGQkHjIGeFFNwCLrgXoi
+h3KfP4R1IYe7NFbM+lFVwPceF3inJ75dZD80BxaXQANeh0yC/DhaVJUFNaof2S4+
+7xd8zTL6M11gME+XmR8uaDvW7EBtAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAf62m
+Nstj9p9u8T5A5fRnJWfoglH/zfm7IHzht0Wi047O3NFZJ0pOPqV97HuErUA5oBGg
+qswnyRGyGMcvL08Bki7Q6NkY7K0ON3lq+ofTkIAHlOKMF+Y/otbjuIDHBfo63tmE
+uOcr8XDQGu9R0cfh+qLgicJQd/8cFBhxsL0ls6I=
+-----END CERTIFICATE-----
diff --git a/src/testcurl/https/host1.key b/src/testcurl/https/host1.key
new file mode 100644
index 0000000..f549a4d
--- /dev/null
+++ b/src/testcurl/https/host1.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCsWIkVM30J3pEJ9+nvoT/5rfyRJIhc1+U1fhNfbntr+LXO5X/k
+qCxJNnVbebRkJB4yBnhRTcAi64F6Iodynz+EdSGHuzRWzPpRVcD3Hhd4pye+XWQ/
+NAcWl0ADXodMgvw4WlSVBTWqH9kuPu8XfM0y+jNdYDBPl5kfLmg71uxAbQIDAQAB
+AoGBAJvq9QmjLSnymtCj4pYSEai2iNpebKdiAlEkoC4j67DArupgohWhN398ryt0
+rYgzTMYBKHSVnI969AYkmtlNzM1yNckRQb/G/tWrkl9re28y2nbAExtHbvLoTk2C
+a/EEl1Op+JZNzLoSje7IQMVZoArD3d4aUbfux4XzlO2eRNmZAkEA2pV49QgcOTOJ
+PrR5cgekonNdeMtkbZm9dhxgDk9IsYkC0iOxjn/IbeCQN3wuTQ5/yLoiiQ/CQ8w5
+JndF/XpICwJBAMnY37BSRb+XKZeJWP0yjqyFJwzHXkh6IsoSF2OOXSixdiMpthLh
+IPzvo6Qxsnha4VvwuDxljHzQFPgMT//CTGcCQQDMs9S+LKU50JDEX4Goj43X8RBl
+cp0Poz3yYap3XDqowLYalADRgcvzUq3cuHgoA98Z3W9ASrjUg2o2ItcyBhV3AkAK
+bCBgwl7Hnc6P/I+Tw2CKl/WEO2cq5uOU+4opodg9maw39JdqMiW56cXRXJ+Sh17L
+mIpq0/OFHll21WvsEORRAkAnDDn/vmW25PSxPVY7tKKJCCkmtBeLQpySfpDgBF+O
+QvvokKs2COivc50rmOYNvD1WSsAOspdaSoZUgFw5ikti
+-----END RSA PRIVATE KEY-----
diff --git a/src/testcurl/https/host2.crt b/src/testcurl/https/host2.crt
new file mode 100644
index 0000000..ac28b0e
--- /dev/null
+++ b/src/testcurl/https/host2.crt
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICWTCCAcICCQCJ9nhDYTUBKjANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJa
+WjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMQ4wDAYDVQQDDAVob3N0MjEZMBcGCSqGSIb3DQEJARYKdGVzdEBo
+b3N0MjAgFw0xMzExMTcxNTE2NDNaGA8yMTEzMTAyNDE1MTY0M1owcDELMAkGA1UE
+BhMCWloxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp
+ZGdpdHMgUHR5IEx0ZDEOMAwGA1UEAwwFaG9zdDIxGTAXBgkqhkiG9w0BCQEWCnRl
+c3RAaG9zdDIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALVK8QKMvU96iNL2
+66PKm6xXw9NPHDn+o1TLF1CQRxXMrBYUrObk0961+3n3Z3BXOFHKfSV4E55CpVyz
+D1Wcadlt3B9z3ke3HOi0lEa1xNJTMQK/QT3Fx/NURmNg5s9HAsqY4ocb9KHaF5Ex
+0TgC0L0aRP0cK1x2TgPEHBNcgGl9AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEXOi
+9rSmVrTN5olIdowctr1vWbGwRCjCnAFXDsqakcDASNthr15LB5kr/mrA3olJjbZh
+o+JDvWMY6FN8r1QXW0RL9/obbHxtJpwvAmYVMY9jrR8Rpo38p4RfXlN85g3q9PVx
+5IGLaOqLf4hSnKArFL/fzXwxX9b5HBCKlXfiuqM=
+-----END CERTIFICATE-----
diff --git a/src/testcurl/https/host2.key b/src/testcurl/https/host2.key
new file mode 100644
index 0000000..4bbd617
--- /dev/null
+++ b/src/testcurl/https/host2.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQC1SvECjL1PeojS9uujypusV8PTTxw5/qNUyxdQkEcVzKwWFKzm
+5NPetft592dwVzhRyn0leBOeQqVcsw9VnGnZbdwfc95HtxzotJRGtcTSUzECv0E9
+xcfzVEZjYObPRwLKmOKHG/Sh2heRMdE4AtC9GkT9HCtcdk4DxBwTXIBpfQIDAQAB
+AoGAR5Do6TfDt69IefdNeCAQKg2PWUg+fUpfEacGciAyX5GnUSQiSReF58HxHumi
+ZL+ZlPgZRQRMwknO23Q4FnSjd66A3E9iHLqkWxRFJWME6E7zgtBrIjctnNu9uYM9
+cw4R6qmXOL7C5sK00KXF2ep8+s+JjrZz61o85QnGGRYA94ECQQDbG6f1B8NKY9T1
+1GDR/++rJbdTVQlZQcKSXMumpU6V3mEV0O9GkYaZzoYvWa3kx6c0np4karrm3QWa
+u5E0q1YdAkEA09FPcmzVvIR0+sMWca8QJ/tJUxD6qYo8vLOpO4wt4iTPhGBEU+Q5
+cgXmde3/plVsp0vYxK/NG5XZkoC1fbuC4QJATRGxRlLwsl3jLoUBeVxY5Q5jKYCj
+xS2ITwss5vUGa1jJNW9EesH9YmRudoFI1UwU2EFixtRz4Xik3ARV0vzhUQJAfabT
+50ASxqMYtczW2peMEPurMqCG4d4ES7iUMqPkcBuAErn8rntbbH19igWmOyi/rLp8
+m6jiFnQdPiAmCbEbYQJAFAKiQl2ZOe3gkSh8MaQilD8Ppog6rod4SQiSmRNsDWPi
+IxqXneaGDWhzynC9xr4SwuJ9D5VxW1phNyiveDuYXw==
+-----END RSA PRIVATE KEY-----
diff --git a/src/testcurl/https/key.pem b/src/testcurl/https/key.pem
new file mode 100644
index 0000000..a5848ee
--- /dev/null
+++ b/src/testcurl/https/key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAtN08lLyuR5lAIq0adOu7WiBDuG4m4eZ6qJVKFHaPy3m5TEFf
+qp67/0TQDE8eV3zS2eOf5GzPYHhfKmNL7D8kLz+I7psytCziWLiMJh2lJvb2152I
+niC4sArk4I2rnd1ZGQ6EPX7XiKPusHvVE6VamacaWy7pQTIf1bL19HDydVRQu60+
+faPYQFJRX/Y1/xpinWCO/TLYFcdDjwY5pkg+pInAQX5n4JDu2yBsJUbbCMjM58Wx
+7ulbqF/3lca0765gsIBFy1kWeq7vDEJeWH6nhl10VcDHl1PetSnn27r5hD3HIAsZ
+vBWdQtXJwxxV4bIkoAMzAYwv2+ilYTUOCp1HWQIDAQABAoIBAArOQv3R7gmqDspj
+lDaTFOz0C4e70QfjGMX0sWnakYnDGn6DU19iv3GnX1S072ejtgc9kcJ4e8VUO79R
+EmqpdRR7k8dJr3RTUCyjzf/C+qiCzcmhCFYGN3KRHA6MeEnkvRuBogX4i5EG1k5l
+/5t+YBTZBnqXKWlzQLKoUAiMLPg0eRWh+6q7H4N7kdWWBmTpako7TEqpIwuEnPGx
+u3EPuTR+LN6lF55WBePbCHccUHUQaXuav18NuDkcJmCiMArK9SKb+h0RqLD6oMI/
+dKD6n8cZXeMBkK+C8U/K0sN2hFHACsu30b9XfdnljgP9v+BP8GhnB0nCB6tNBCPo
+32srOwECgYEAxWh3iBT4lWqL6bZavVbnhmvtif4nHv2t2/hOs/CAq8iLAw0oWGZc
++JEZTUDMvFRlulr0kcaWra+4fN3OmJnjeuFXZq52lfMgXBIKBmoSaZpIh2aDY1Rd
+RbEse7nQl9hTEPmYspiXLGtnAXW7HuWqVfFFP3ya8rUS3t4d07Hig8ECgYEA6ou6
+OHiBRTbtDqLIv8NghARc/AqwNWgEc9PelCPe5bdCOLBEyFjqKiT2MttnSSUc2Zob
+XhYkHC6zN1Mlq30N0e3Q61YK9LxMdU1vsluXxNq2rfK1Scb1oOlOOtlbV3zA3VRF
+hV3t1nOA9tFmUrwZi0CUMWJE/zbPAyhwWotKyZkCgYEAh0kFicPdbABdrCglXVae
+SnfSjVwYkVuGd5Ze0WADvjYsVkYBHTvhgRNnRJMg+/vWz3Sf4Ps4rgUbqK8Vc20b
+AU5G6H6tlCvPRGm0ZxrwTWDHTcuKRVs+pJE8C/qWoklE/AAhjluWVoGwUMbPGuiH
+6Gf1bgHF6oj/Sq7rv/VLZ8ECgYBeq7ml05YyLuJutuwa4yzQ/MXfghzv4aVyb0F3
+QCdXR6o2IYgR6jnSewrZKlA9aPqFJrwHNR6sNXlnSmt5Fcf/RWO/qgJQGLUv3+rG
+7kuLTNDR05azSdiZc7J89ID3Bkb+z2YkV+6JUiPq/Ei1+nDBEXb/m+/HqALU/nyj
+P3gXeQKBgBusb8Rbd+KgxSA0hwY6aoRTPRt8LNvXdsB9vRcKKHUFQvxUWiUSS+L9
+/Qu1sJbrUquKOHqksV5wCnWnAKyJNJlhHuBToqQTgKXjuNmVdYSe631saiI7PHyC
+eRJ6DxULPxABytJrYCRrNqmXi5TCiqR2mtfalEMOPxz8rUU8dYyx
+-----END RSA PRIVATE KEY-----
diff --git a/src/testcurl/https/test_empty_response.c b/src/testcurl/https/test_empty_response.c
new file mode 100644
index 0000000..f9f8001
--- /dev/null
+++ b/src/testcurl/https/test_empty_response.c
@@ -0,0 +1,201 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2013 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file test_empty_response.c
+ * @brief Testcase for libmicrohttpd HTTPS GET operations with emtpy reply
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "microhttpd.h"
+#include <limits.h>
+#include <sys/stat.h>
+#include <curl/curl.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+
+extern const char srv_key_pem[];
+extern const char srv_self_signed_cert_pem[];
+extern const char srv_signed_cert_pem[];
+extern const char srv_signed_key_pem[];
+
+static int oneone;
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ struct MHD_Response *response;
+ int ret;
+
+ response = MHD_create_response_from_buffer (0, NULL,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+static int
+testInternalSelectGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL | MHD_USE_SELECT_INTERNALLY,
+ 1082, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+
+ char *aes256_sha = "AES256-SHA";
+ if (curl_uses_nss_ssl() == 0)
+ {
+ aes256_sha = "rsa_aes_256_sha";
+ }
+
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1:1082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ /* TLS options */
+ curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+ curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, aes256_sha);
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != 0)
+ return 8192;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error: %s\n", strerror (errno));
+ return -1;
+ }
+ if (0 != (errorCount = testInternalSelectGet ()))
+ fprintf (stderr, "Fail: %d\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0;
+}
diff --git a/src/testcurl/https/test_https_get.c b/src/testcurl/https/test_https_get.c
new file mode 100644
index 0000000..f7957c3
--- /dev/null
+++ b/src/testcurl/https/test_https_get.c
@@ -0,0 +1,130 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_https_get.c
+ * @brief Testcase for libmicrohttpd HTTPS GET operations
+ * @author Sagie Amir
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <limits.h>
+#include <sys/stat.h>
+#include <curl/curl.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+
+extern const char srv_key_pem[];
+extern const char srv_self_signed_cert_pem[];
+extern const char srv_signed_cert_pem[];
+extern const char srv_signed_key_pem[];
+
+
+static int
+test_cipher_option (FILE * test_fd,
+ const char *cipher_suite,
+ int proto_version)
+{
+
+ int ret;
+ struct MHD_Daemon *d;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL |
+ MHD_USE_DEBUG, 4233,
+ NULL, NULL, &http_ahc, NULL,
+ MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
+ MHD_OPTION_END);
+
+ if (d == NULL)
+ {
+ fprintf (stderr, MHD_E_SERVER_INIT);
+ return -1;
+ }
+
+ ret = test_https_transfer (test_fd, cipher_suite, proto_version);
+
+ MHD_stop_daemon (d);
+ return ret;
+}
+
+
+/* perform a HTTP GET request via SSL/TLS */
+static int
+test_secure_get (FILE * test_fd,
+ const char *cipher_suite,
+ int proto_version)
+{
+ int ret;
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL |
+ MHD_USE_DEBUG, 4233,
+ NULL, NULL, &http_ahc, NULL,
+ MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
+ MHD_OPTION_END);
+
+ if (d == NULL)
+ {
+ fprintf (stderr, MHD_E_SERVER_INIT);
+ return -1;
+ }
+
+ ret = test_https_transfer (test_fd, cipher_suite, proto_version);
+
+ MHD_stop_daemon (d);
+ return ret;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+ const char *aes256_sha_tlsv1 = "AES256-SHA";
+ const char *des_cbc3_sha_tlsv1 = "DES-CBC3-SHA";
+
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error: %s\n", strerror (errno));
+ return -1;
+ }
+
+ if (curl_uses_nss_ssl() == 0)
+ {
+ aes256_sha_tlsv1 = "rsa_aes_256_sha";
+ des_cbc3_sha_tlsv1 = "rsa_aes_128_sha";
+ }
+
+ errorCount +=
+ test_secure_get (NULL, aes256_sha_tlsv1, CURL_SSLVERSION_TLSv1);
+ errorCount +=
+ test_cipher_option (NULL, des_cbc3_sha_tlsv1, CURL_SSLVERSION_TLSv1);
+ print_test_result (errorCount, argv[0]);
+
+ curl_global_cleanup ();
+
+ return errorCount != 0;
+}
diff --git a/src/testcurl/https/test_https_get_parallel.c b/src/testcurl/https/test_https_get_parallel.c
new file mode 100644
index 0000000..166e400
--- /dev/null
+++ b/src/testcurl/https/test_https_get_parallel.c
@@ -0,0 +1,185 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_https_get_parallel.c
+ * @brief Testcase for libmicrohttpd HTTPS GET operations
+ * @author Sagie Amir
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <sys/stat.h>
+#include <limits.h>
+#include <curl/curl.h>
+#include <pthread.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 4
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 4
+#endif
+
+extern const char srv_key_pem[];
+extern const char srv_self_signed_cert_pem[];
+
+int curl_check_version (const char *req_version, ...);
+
+
+/**
+ * used when spawning multiple threads executing curl server requests
+ *
+ */
+static void *
+https_transfer_thread_adapter (void *args)
+{
+ static int nonnull;
+ struct https_test_data *cargs = args;
+ int ret;
+
+ /* time spread incomming requests */
+ usleep ((useconds_t) 10.0 * ((double) rand ()) / ((double) RAND_MAX));
+ ret = test_https_transfer (NULL,
+ cargs->cipher_suite, cargs->proto_version);
+ if (ret == 0)
+ return NULL;
+ return &nonnull;
+}
+
+
+/**
+ * Test non-parallel requests.
+ *
+ * @return: 0 upon all client requests returning '0', -1 otherwise.
+ *
+ * TODO : make client_count a parameter - number of curl client threads to spawn
+ */
+static int
+test_single_client (void *cls, const char *cipher_suite,
+ int curl_proto_version)
+{
+ void *client_thread_ret;
+ struct https_test_data client_args =
+ { NULL, cipher_suite, curl_proto_version };
+
+ client_thread_ret = https_transfer_thread_adapter (&client_args);
+ if (client_thread_ret != NULL)
+ return -1;
+ return 0;
+}
+
+
+/**
+ * Test parallel request handling.
+ *
+ * @return: 0 upon all client requests returning '0', -1 otherwise.
+ *
+ * TODO : make client_count a parameter - numver of curl client threads to spawn
+ */
+static int
+test_parallel_clients (void * cls, const char *cipher_suite,
+ int curl_proto_version)
+{
+ int i;
+ int client_count = (CPU_COUNT - 1);
+ void *client_thread_ret;
+ pthread_t client_arr[client_count];
+ struct https_test_data client_args =
+ { NULL, cipher_suite, curl_proto_version };
+
+ for (i = 0; i < client_count; ++i)
+ {
+ if (pthread_create (&client_arr[i], NULL,
+ &https_transfer_thread_adapter, &client_args) != 0)
+ {
+ fprintf (stderr, "Error: failed to spawn test client threads.\n");
+ return -1;
+ }
+ }
+
+ /* check all client requests fulfilled correctly */
+ for (i = 0; i < client_count; ++i)
+ {
+ if ((pthread_join (client_arr[i], &client_thread_ret) != 0) ||
+ (client_thread_ret != NULL))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+ const char *aes256_sha = "AES256-SHA";
+
+ /* initialize random seed used by curl clients */
+ unsigned int iseed = (unsigned int) time (NULL);
+ srand (iseed);
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error: %s\n", strerror (errno));
+ return -1;
+ }
+
+ if (curl_uses_nss_ssl() == 0)
+ aes256_sha = "rsa_aes_256_sha";
+#if EPOLL_SUPPORT
+ errorCount +=
+ test_wrap ("single threaded daemon, single client, epoll", &test_single_client,
+ NULL,
+ MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG | MHD_USE_EPOLL_LINUX_ONLY,
+ aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
+ srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
+ srv_self_signed_cert_pem, MHD_OPTION_END);
+#endif
+ errorCount +=
+ test_wrap ("single threaded daemon, single client", &test_single_client,
+ NULL,
+ MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG,
+ aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
+ srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
+ srv_self_signed_cert_pem, MHD_OPTION_END);
+#if EPOLL_SUPPORT
+ errorCount +=
+ test_wrap ("single threaded daemon, parallel clients, epoll",
+ &test_parallel_clients, NULL,
+ MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG | MHD_USE_EPOLL_LINUX_ONLY,
+ aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
+ srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
+ srv_self_signed_cert_pem, MHD_OPTION_END);
+#endif
+ errorCount +=
+ test_wrap ("single threaded daemon, parallel clients",
+ &test_parallel_clients, NULL,
+ MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG,
+ aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
+ srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
+ srv_self_signed_cert_pem, MHD_OPTION_END);
+
+ curl_global_cleanup ();
+ return errorCount != 0;
+}
diff --git a/src/testcurl/https/test_https_get_parallel_threads.c b/src/testcurl/https/test_https_get_parallel_threads.c
new file mode 100644
index 0000000..4cb2128
--- /dev/null
+++ b/src/testcurl/https/test_https_get_parallel_threads.c
@@ -0,0 +1,191 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file tls_thread_mode_test.c
+ * @brief Testcase for libmicrohttpd HTTPS GET operations
+ * @author Sagie Amir
+ * @author Christian Grothoff
+ *
+ * TODO: add test for external select!
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <sys/stat.h>
+#include <limits.h>
+#include <curl/curl.h>
+#include <pthread.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 4
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 4
+#endif
+
+extern const char srv_key_pem[];
+extern const char srv_self_signed_cert_pem[];
+
+int curl_check_version (const char *req_version, ...);
+
+/**
+ * used when spawning multiple threads executing curl server requests
+ *
+ */
+static void *
+https_transfer_thread_adapter (void *args)
+{
+ static int nonnull;
+ struct https_test_data *cargs = args;
+ int ret;
+
+ /* time spread incomming requests */
+ usleep ((useconds_t) 10.0 * ((double) rand ()) / ((double) RAND_MAX));
+ ret = test_https_transfer (cargs->cls,
+ cargs->cipher_suite, cargs->proto_version);
+ if (ret == 0)
+ return NULL;
+ return &nonnull;
+}
+
+/**
+ * Test non-parallel requests.
+ *
+ * @return: 0 upon all client requests returning '0', -1 otherwise.
+ *
+ * TODO : make client_count a parameter - numver of curl client threads to spawn
+ */
+static int
+test_single_client (void *cls, const char *cipher_suite,
+ int curl_proto_version)
+{
+ void *client_thread_ret;
+ struct https_test_data client_args =
+ { NULL, cipher_suite, curl_proto_version };
+
+ client_thread_ret = https_transfer_thread_adapter (&client_args);
+ if (client_thread_ret != NULL)
+ return -1;
+ return 0;
+}
+
+
+/**
+ * Test parallel request handling.
+ *
+ * @return: 0 upon all client requests returning '0', -1 otherwise.
+ *
+ * TODO : make client_count a parameter - numver of curl client threads to spawn
+ */
+static int
+test_parallel_clients (void *cls, const char *cipher_suite,
+ int curl_proto_version)
+{
+ int i;
+ int client_count = (CPU_COUNT - 1);
+ void *client_thread_ret;
+ pthread_t client_arr[client_count];
+ struct https_test_data client_args =
+ { NULL, cipher_suite, curl_proto_version };
+
+ for (i = 0; i < client_count; ++i)
+ {
+ if (pthread_create (&client_arr[i], NULL,
+ &https_transfer_thread_adapter, &client_args) != 0)
+ {
+ fprintf (stderr, "Error: failed to spawn test client threads.\n");
+
+ return -1;
+ }
+ }
+
+ /* check all client requests fulfilled correctly */
+ for (i = 0; i < client_count; ++i)
+ {
+ if ((pthread_join (client_arr[i], &client_thread_ret) != 0) ||
+ (client_thread_ret != NULL))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+ const char *ssl_version;
+
+ /* initialize random seed used by curl clients */
+ unsigned int iseed = (unsigned int) time (NULL);
+
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+ srand (iseed);
+ ssl_version = curl_version_info (CURLVERSION_NOW)->ssl_version;
+ if (NULL == ssl_version)
+ {
+ fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n");
+ return 0;
+ }
+ if (0 != strncmp (ssl_version, "GnuTLS", 6))
+ {
+ fprintf (stderr, "This test can be run only with libcurl-gnutls.\n");
+ return 0;
+ }
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error: %s\n", strerror (errno));
+ return -1;
+ }
+
+ char *aes256_sha = "AES256-SHA";
+ if (curl_uses_nss_ssl() == 0)
+ {
+ aes256_sha = "rsa_aes_256_sha";
+ }
+
+ errorCount +=
+ test_wrap ("multi threaded daemon, single client", &test_single_client,
+ NULL,
+ MHD_USE_SSL | MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION,
+ aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
+ srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
+ srv_self_signed_cert_pem, MHD_OPTION_END);
+
+ errorCount +=
+ test_wrap ("multi threaded daemon, parallel client",
+ &test_parallel_clients, NULL,
+ MHD_USE_SSL | MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION,
+ aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
+ srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
+ srv_self_signed_cert_pem, MHD_OPTION_END);
+
+ if (errorCount != 0)
+ fprintf (stderr, "Failed test: %s.\n", argv[0]);
+
+ curl_global_cleanup ();
+ return errorCount != 0;
+}
diff --git a/src/testcurl/https/test_https_get_select.c b/src/testcurl/https/test_https_get_select.c
new file mode 100644
index 0000000..9f9ba99
--- /dev/null
+++ b/src/testcurl/https/test_https_get_select.c
@@ -0,0 +1,228 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file test_https_get_select.c
+ * @brief Testcase for libmicrohttpd HTTPS GET operations
+ * @author Sagie Amir
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <limits.h>
+#include <sys/stat.h>
+#include <curl/curl.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+
+extern const char srv_key_pem[];
+extern const char srv_self_signed_cert_pem[];
+extern const char srv_signed_cert_pem[];
+extern const char srv_signed_key_pem[];
+
+static int oneone;
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static int
+testExternalGet (int flags)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+ const char *aes256_sha = "AES256-SHA";
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL | flags,
+ 1082, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+
+ if (curl_uses_nss_ssl() == 0)
+ aes256_sha = "rsa_aes_256_sha";
+
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1:1082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ /* TLS options */
+ curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+ curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, aes256_sha);
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error: %s\n", strerror (errno));
+ return -1;
+ }
+#if EPOLL_SUPPORT
+ if (0 != (errorCount = testExternalGet (MHD_USE_EPOLL_LINUX_ONLY)))
+ fprintf (stderr, "Fail: %d\n", errorCount);
+#endif
+ if (0 != (errorCount = testExternalGet (0)))
+ fprintf (stderr, "Fail: %d\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0;
+}
diff --git a/src/testcurl/https/test_https_multi_daemon.c b/src/testcurl/https/test_https_multi_daemon.c
new file mode 100644
index 0000000..293aff4
--- /dev/null
+++ b/src/testcurl/https/test_https_multi_daemon.c
@@ -0,0 +1,134 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file mhds_multi_daemon_test.c
+ * @brief Testcase for libmicrohttpd multiple HTTPS daemon scenario
+ * @author Sagie Amir
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <curl/curl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+
+extern int curl_check_version (const char *req_version, ...);
+extern const char srv_key_pem[];
+extern const char srv_self_signed_cert_pem[];
+
+/*
+ * assert initiating two separate daemons and having one shut down
+ * doesn't affect the other
+ */
+static int
+test_concurent_daemon_pair (void *cls,
+ const char *cipher_suite,
+ int proto_version)
+{
+
+ int ret;
+ struct MHD_Daemon *d1;
+ struct MHD_Daemon *d2;
+
+ d1 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL |
+ MHD_USE_DEBUG, DEAMON_TEST_PORT,
+ NULL, NULL, &http_ahc, NULL,
+ MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
+ MHD_OPTION_END);
+
+ if (d1 == NULL)
+ {
+ fprintf (stderr, MHD_E_SERVER_INIT);
+ return -1;
+ }
+
+ d2 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL |
+ MHD_USE_DEBUG, DEAMON_TEST_PORT + 1,
+ NULL, NULL, &http_ahc, NULL,
+ MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
+ MHD_OPTION_END);
+
+ if (d2 == NULL)
+ {
+ MHD_stop_daemon (d1);
+ fprintf (stderr, MHD_E_SERVER_INIT);
+ return -1;
+ }
+
+ ret =
+ test_daemon_get (NULL, cipher_suite, proto_version, DEAMON_TEST_PORT, 0);
+ ret +=
+ test_daemon_get (NULL, cipher_suite, proto_version,
+ DEAMON_TEST_PORT + 1, 0);
+
+ MHD_stop_daemon (d2);
+ ret +=
+ test_daemon_get (NULL, cipher_suite, proto_version, DEAMON_TEST_PORT, 0);
+ MHD_stop_daemon (d1);
+ return ret;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+ FILE *cert;
+
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error (code: %u). l:%d f:%s\n", errorCount, __LINE__,
+ __FUNCTION__);
+ return -1;
+ }
+ if ((cert = setup_ca_cert ()) == NULL)
+ {
+ fprintf (stderr, MHD_E_TEST_FILE_CREAT);
+ return -1;
+ }
+
+ const char *aes256_sha = "AES256-SHA";
+ if (curl_uses_nss_ssl() == 0)
+ {
+ aes256_sha = "rsa_aes_256_sha";
+ }
+
+ errorCount +=
+ test_concurent_daemon_pair (NULL, aes256_sha, CURL_SSLVERSION_TLSv1);
+
+ print_test_result (errorCount, "concurent_daemon_pair");
+
+ curl_global_cleanup ();
+ fclose (cert);
+ if (0 != remove (ca_cert_file_name))
+ fprintf (stderr,
+ "Failed to remove `%s'\n",
+ ca_cert_file_name);
+ return errorCount != 0;
+}
diff --git a/src/testcurl/https/test_https_session_info.c b/src/testcurl/https/test_https_session_info.c
new file mode 100644
index 0000000..8dac253
--- /dev/null
+++ b/src/testcurl/https/test_https_session_info.c
@@ -0,0 +1,186 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file mhds_session_info_test.c
+ * @brief Testcase for libmicrohttpd HTTPS connection querying operations
+ * @author Sagie Amir
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <curl/curl.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+
+extern int curl_check_version (const char *req_version, ...);
+extern const char srv_key_pem[];
+extern const char srv_self_signed_cert_pem[];
+
+struct MHD_Daemon *d;
+
+/*
+ * HTTP access handler call back
+ * used to query negotiated security parameters
+ */
+static int
+query_session_ahc (void *cls, struct MHD_Connection *connection,
+ const char *url, const char *method,
+ const char *upload_data, const char *version,
+ size_t *upload_data_size, void **ptr)
+{
+ struct MHD_Response *response;
+ int ret;
+
+ if (NULL == *ptr)
+ {
+ *ptr = &query_session_ahc;
+ return MHD_YES;
+ }
+
+ if (GNUTLS_TLS1_1 !=
+ (ret = MHD_get_connection_info
+ (connection,
+ MHD_CONNECTION_INFO_PROTOCOL)->protocol))
+ {
+ if (GNUTLS_TLS1_2 == ret)
+ {
+ /* as usual, TLS implementations sometimes don't
+ quite do what was asked, just mildly complain... */
+ fprintf (stderr,
+ "Warning: requested TLS 1.1, got TLS 1.2\n");
+ }
+ else
+ {
+ /* really different version... */
+ fprintf (stderr,
+ "Error: requested protocol mismatch (wanted %d, got %d)\n",
+ GNUTLS_TLS1_1,
+ ret);
+ return -1;
+ }
+ }
+
+ response = MHD_create_response_from_buffer (strlen (EMPTY_PAGE),
+ (void *) EMPTY_PAGE,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+/**
+ * negotiate a secure connection with server & query negotiated security parameters
+ */
+static int
+test_query_session ()
+{
+ CURL *c;
+ struct CBC cbc;
+ CURLcode errornum;
+ char url[256];
+
+ if (NULL == (cbc.buf = malloc (sizeof (char) * 255)))
+ return 16;
+ cbc.size = 255;
+ cbc.pos = 0;
+
+ gen_test_file_url (url, DEAMON_TEST_PORT);
+
+ /* setup test */
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL |
+ MHD_USE_DEBUG, DEAMON_TEST_PORT,
+ NULL, NULL, &query_session_ahc, NULL,
+ MHD_OPTION_HTTPS_PRIORITIES, "NORMAL:+ARCFOUR-128",
+ MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
+ MHD_OPTION_END);
+
+ if (d == NULL)
+ return 2;
+
+ const char *aes256_sha = "AES256-SHA";
+ if (curl_uses_nss_ssl() == 0)
+ {
+ aes256_sha = "rsa_aes_256_sha";
+ }
+
+ c = curl_easy_init ();
+#if DEBUG_HTTPS_TEST
+ curl_easy_setopt (c, CURLOPT_VERBOSE, 1);
+#endif
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_FILE, &cbc);
+ /* TLS options */
+ curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
+ curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, aes256_sha);
+ /* currently skip any peer authentication */
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr, "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+
+ MHD_stop_daemon (d);
+ curl_easy_cleanup (c);
+ free (cbc.buf);
+ return -1;
+ }
+
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ free (cbc.buf);
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ return -1;
+ }
+ errorCount += test_query_session ();
+ print_test_result (errorCount, argv[0]);
+ curl_global_cleanup ();
+ if (errorCount > 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ return errorCount;
+}
diff --git a/src/testcurl/https/test_https_sni.c b/src/testcurl/https/test_https_sni.c
new file mode 100644
index 0000000..8c4dea6
--- /dev/null
+++ b/src/testcurl/https/test_https_sni.c
@@ -0,0 +1,291 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2013 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_https_sni.c
+ * @brief Testcase for libmicrohttpd HTTPS with SNI operations
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "microhttpd.h"
+#include <limits.h>
+#include <sys/stat.h>
+#include <curl/curl.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+#include <gnutls/gnutls.h>
+
+/* This test only works with GnuTLS >= 3.0 */
+#if GNUTLS_VERSION_MAJOR >= 3
+
+#include <gnutls/abstract.h>
+
+/**
+ * A hostname, server key and certificate.
+ */
+struct Hosts
+{
+ struct Hosts *next;
+ const char *hostname;
+ gnutls_pcert_st pcrt;
+ gnutls_privkey_t key;
+};
+
+
+/**
+ * Linked list of supported TLDs and respective certificates.
+ */
+static struct Hosts *hosts;
+
+/* Load the certificate and the private key.
+ * (This code is largely taken from GnuTLS).
+ */
+static void
+load_keys(const char *hostname,
+ const char *CERT_FILE,
+ const char *KEY_FILE)
+{
+ int ret;
+ gnutls_datum_t data;
+ struct Hosts *host;
+
+ host = malloc (sizeof (struct Hosts));
+ if (NULL == host)
+ abort ();
+ host->hostname = hostname;
+ host->next = hosts;
+ hosts = host;
+
+ ret = gnutls_load_file (CERT_FILE, &data);
+ if (ret < 0)
+ {
+ fprintf (stderr,
+ "*** Error loading certificate file %s.\n",
+ CERT_FILE);
+ exit (1);
+ }
+ ret =
+ gnutls_pcert_import_x509_raw (&host->pcrt, &data, GNUTLS_X509_FMT_PEM,
+ 0);
+ if (ret < 0)
+ {
+ fprintf (stderr,
+ "*** Error loading certificate file: %s\n",
+ gnutls_strerror (ret));
+ exit (1);
+ }
+ gnutls_free (data.data);
+
+ ret = gnutls_load_file (KEY_FILE, &data);
+ if (ret < 0)
+ {
+ fprintf (stderr,
+ "*** Error loading key file %s.\n",
+ KEY_FILE);
+ exit (1);
+ }
+
+ gnutls_privkey_init (&host->key);
+ ret =
+ gnutls_privkey_import_x509_raw (host->key,
+ &data, GNUTLS_X509_FMT_PEM,
+ NULL, 0);
+ if (ret < 0)
+ {
+ fprintf (stderr,
+ "*** Error loading key file: %s\n",
+ gnutls_strerror (ret));
+ exit (1);
+ }
+ gnutls_free (data.data);
+}
+
+
+
+/**
+ * @param session the session we are giving a cert for
+ * @param req_ca_dn NULL on server side
+ * @param nreqs length of req_ca_dn, and thus 0 on server side
+ * @param pk_algos NULL on server side
+ * @param pk_algos_length 0 on server side
+ * @param pcert list of certificates (to be set)
+ * @param pcert_length length of pcert (to be set)
+ * @param pkey the private key (to be set)
+ */
+static int
+sni_callback (gnutls_session_t session,
+ const gnutls_datum_t* req_ca_dn,
+ int nreqs,
+ const gnutls_pk_algorithm_t* pk_algos,
+ int pk_algos_length,
+ gnutls_pcert_st** pcert,
+ unsigned int *pcert_length,
+ gnutls_privkey_t * pkey)
+{
+ char name[256];
+ size_t name_len;
+ struct Hosts *host;
+ unsigned int type;
+
+ name_len = sizeof (name);
+ if (GNUTLS_E_SUCCESS !=
+ gnutls_server_name_get (session,
+ name,
+ &name_len,
+ &type,
+ 0 /* index */))
+ return -1;
+ for (host = hosts; NULL != host; host = host->next)
+ if (0 == strncmp (name, host->hostname, name_len))
+ break;
+ if (NULL == host)
+ {
+ fprintf (stderr,
+ "Need certificate for %.*s\n",
+ (int) name_len,
+ name);
+ return -1;
+ }
+#if 0
+ fprintf (stderr,
+ "Returning certificate for %.*s\n",
+ (int) name_len,
+ name);
+#endif
+ *pkey = host->key;
+ *pcert_length = 1;
+ *pcert = &host->pcrt;
+ return 0;
+}
+
+
+/* perform a HTTP GET request via SSL/TLS */
+static int
+do_get (const char *url)
+{
+ CURL *c;
+ struct CBC cbc;
+ CURLcode errornum;
+ size_t len;
+ struct curl_slist *dns_info;
+
+ len = strlen (test_data);
+ if (NULL == (cbc.buf = malloc (sizeof (char) * len)))
+ {
+ fprintf (stderr, MHD_E_MEM);
+ return -1;
+ }
+ cbc.size = len;
+ cbc.pos = 0;
+
+ c = curl_easy_init ();
+#if DEBUG_HTTPS_TEST
+ curl_easy_setopt (c, CURLOPT_VERBOSE, 1);
+#endif
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_FILE, &cbc);
+
+ /* perform peer authentication */
+ /* TODO merge into send_curl_req */
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 2);
+ dns_info = curl_slist_append (NULL, "host1:4233:127.0.0.1");
+ dns_info = curl_slist_append (dns_info, "host2:4233:127.0.0.1");
+ curl_easy_setopt (c, CURLOPT_RESOLVE, dns_info);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr, "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ free (cbc.buf);
+ curl_slist_free_all (dns_info);
+ return errornum;
+ }
+
+ curl_easy_cleanup (c);
+ curl_slist_free_all (dns_info);
+ if (memcmp (cbc.buf, test_data, len) != 0)
+ {
+ fprintf (stderr, "Error: local file & received file differ.\n");
+ free (cbc.buf);
+ return -1;
+ }
+
+ free (cbc.buf);
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int error_count = 0;
+ struct MHD_Daemon *d;
+
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error: %s\n", strerror (errno));
+ return -1;
+ }
+ load_keys ("host1", ABS_SRCDIR "/host1.crt", ABS_SRCDIR "/host1.key");
+ load_keys ("host2", ABS_SRCDIR "/host2.crt", ABS_SRCDIR "/host2.key");
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | MHD_USE_DEBUG,
+ 4233,
+ NULL, NULL,
+ &http_ahc, NULL,
+ MHD_OPTION_HTTPS_CERT_CALLBACK, &sni_callback,
+ MHD_OPTION_END);
+ if (d == NULL)
+ {
+ fprintf (stderr, MHD_E_SERVER_INIT);
+ return -1;
+ }
+ error_count += do_get ("https://host1:4233/");
+ error_count += do_get ("https://host2:4233/");
+
+ MHD_stop_daemon (d);
+ curl_global_cleanup ();
+ return error_count != 0;
+}
+
+
+#else
+
+int main ()
+{
+ fprintf (stderr,
+ "SNI not supported by GnuTLS < 3.0\n");
+ return 0;
+}
+#endif
diff --git a/src/testcurl/https/test_https_time_out.c b/src/testcurl/https/test_https_time_out.c
new file mode 100644
index 0000000..124a280
--- /dev/null
+++ b/src/testcurl/https/test_https_time_out.c
@@ -0,0 +1,146 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file mhds_get_test.c
+ * @brief: daemon TLS alert response test-case
+ *
+ * @author Sagie Amir
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include "internal.h"
+#include "tls_test_common.h"
+#include <gcrypt.h>
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif /* !WIN32_LEAN_AND_MEAN */
+#include <windows.h>
+#endif
+
+extern const char srv_key_pem[];
+extern const char srv_self_signed_cert_pem[];
+
+static const int TIME_OUT = 3;
+
+static int
+test_tls_session_time_out (gnutls_session_t session)
+{
+ int ret;
+ MHD_socket sd;
+ struct sockaddr_in sa;
+
+ sd = socket (AF_INET, SOCK_STREAM, 0);
+ if (sd == -1)
+ {
+ fprintf (stderr, "Failed to create socket: %s\n", strerror (errno));
+ return -1;
+ }
+
+ memset (&sa, '\0', sizeof (struct sockaddr_in));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (DEAMON_TEST_PORT);
+ sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) (intptr_t) sd);
+
+ ret = connect (sd, &sa, sizeof (struct sockaddr_in));
+
+ if (ret < 0)
+ {
+ fprintf (stderr, "Error: %s\n", MHD_E_FAILED_TO_CONNECT);
+ close (sd);
+ return -1;
+ }
+
+ ret = gnutls_handshake (session);
+ if (ret < 0)
+ {
+ fprintf (stderr, "Handshake failed\n");
+ close (sd);
+ return -1;
+ }
+
+ sleep (TIME_OUT + 1);
+
+ /* check that server has closed the connection */
+ /* TODO better RST trigger */
+ if (send (sd, "", 1, 0) == 0)
+ {
+ fprintf (stderr, "Connection failed to time-out\n");
+ close (sd);
+ return -1;
+ }
+
+ close (sd);
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ int errorCount = 0;;
+ struct MHD_Daemon *d;
+ gnutls_session_t session;
+ gnutls_datum_t key;
+ gnutls_datum_t cert;
+ gnutls_certificate_credentials_t xcred;
+
+
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+ gnutls_global_init ();
+ gnutls_global_set_log_level (11);
+
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL |
+ MHD_USE_DEBUG, DEAMON_TEST_PORT,
+ NULL, NULL, &http_dummy_ahc, NULL,
+ MHD_OPTION_CONNECTION_TIMEOUT, TIME_OUT,
+ MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
+ MHD_OPTION_END);
+
+ if (d == NULL)
+ {
+ fprintf (stderr, MHD_E_SERVER_INIT);
+ return -1;
+ }
+
+ if (0 != setup_session (&session, &key, &cert, &xcred))
+ {
+ fprintf (stderr, "failed to setup session\n");
+ return 1;
+ }
+ errorCount += test_tls_session_time_out (session);
+ teardown_session (session, &key, &cert, xcred);
+
+ print_test_result (errorCount, argv[0]);
+
+ MHD_stop_daemon (d);
+ gnutls_global_deinit ();
+
+ return errorCount != 0;
+}
diff --git a/src/testcurl/https/test_tls_authentication.c b/src/testcurl/https/test_tls_authentication.c
new file mode 100644
index 0000000..cc9c76d
--- /dev/null
+++ b/src/testcurl/https/test_tls_authentication.c
@@ -0,0 +1,110 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file tls_authentication_test.c
+ * @brief Testcase for libmicrohttpd HTTPS GET operations
+ * @author Sagie Amir
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <curl/curl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+
+extern int curl_check_version (const char *req_version, ...);
+extern const char test_file_data[];
+
+extern const char ca_key_pem[];
+extern const char ca_cert_pem[];
+extern const char srv_signed_cert_pem[];
+extern const char srv_signed_key_pem[];
+
+
+
+/* perform a HTTP GET request via SSL/TLS */
+static int
+test_secure_get (void * cls, char *cipher_suite, int proto_version)
+{
+ int ret;
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL |
+ MHD_USE_DEBUG, DEAMON_TEST_PORT,
+ NULL, NULL, &http_ahc, NULL,
+ MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
+ MHD_OPTION_END);
+
+ if (d == NULL)
+ {
+ fprintf (stderr, MHD_E_SERVER_INIT);
+ return -1;
+ }
+
+ ret = test_daemon_get (NULL, cipher_suite, proto_version, DEAMON_TEST_PORT, 0);
+
+ MHD_stop_daemon (d);
+ return ret;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+ if (setup_ca_cert () == NULL)
+ {
+ fprintf (stderr, MHD_E_TEST_FILE_CREAT);
+ return -1;
+ }
+
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ return -1;
+ }
+
+ char *aes256_sha = "AES256-SHA";
+ if (curl_uses_nss_ssl() == 0)
+ {
+ aes256_sha = "rsa_aes_256_sha";
+ }
+
+ errorCount +=
+ test_secure_get (NULL, aes256_sha, CURL_SSLVERSION_TLSv1);
+
+ print_test_result (errorCount, argv[0]);
+
+ curl_global_cleanup ();
+ if (0 != remove (ca_cert_file_name))
+ fprintf (stderr,
+ "Failed to remove `%s'\n",
+ ca_cert_file_name);
+ return errorCount != 0;
+}
diff --git a/src/testcurl/https/test_tls_options.c b/src/testcurl/https/test_tls_options.c
new file mode 100644
index 0000000..7dd01a7
--- /dev/null
+++ b/src/testcurl/https/test_tls_options.c
@@ -0,0 +1,155 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2010 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file tls_daemon_options_test.c
+ * @brief Testcase for libmicrohttpd HTTPS GET operations
+ * @author Sagie Amir
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <sys/stat.h>
+#include <limits.h>
+#include <gcrypt.h>
+#include "tls_test_common.h"
+
+extern const char srv_key_pem[];
+extern const char srv_self_signed_cert_pem[];
+
+int curl_check_version (const char *req_version, ...);
+
+/**
+ * test server refuses to negotiate connections with unsupported protocol versions
+ *
+ */
+static int
+test_unmatching_ssl_version (void * cls, const char *cipher_suite,
+ int curl_req_ssl_version)
+{
+ struct CBC cbc;
+ if (NULL == (cbc.buf = malloc (sizeof (char) * 256)))
+ {
+ fprintf (stderr, "Error: failed to allocate: %s\n",
+ strerror (errno));
+ return -1;
+ }
+ cbc.size = 256;
+ cbc.pos = 0;
+
+ char url[255];
+ if (gen_test_file_url (url, DEAMON_TEST_PORT))
+ {
+ free (cbc.buf);
+ fprintf (stderr, "Internal error in gen_test_file_url\n");
+ return -1;
+ }
+
+ /* assert daemon *rejected* request */
+ if (CURLE_OK ==
+ send_curl_req (url, &cbc, cipher_suite, curl_req_ssl_version))
+ {
+ free (cbc.buf);
+ fprintf (stderr, "cURL failed to reject request despite SSL version missmatch!\n");
+ return -1;
+ }
+
+ free (cbc.buf);
+ return 0;
+}
+
+
+/* setup a temporary transfer test file */
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+ const char *ssl_version;
+ int daemon_flags =
+ MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | MHD_USE_DEBUG;
+
+ gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+ if (curl_check_version (MHD_REQ_CURL_VERSION))
+ {
+ return 0;
+ }
+ ssl_version = curl_version_info (CURLVERSION_NOW)->ssl_version;
+ if (NULL == ssl_version)
+ {
+ fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n");
+ return 0;
+ }
+ if (0 != strncmp (ssl_version, "GnuTLS", 6))
+ {
+ fprintf (stderr, "This test can be run only with libcurl-gnutls.\n");
+ return 0;
+ }
+
+ if (0 != curl_global_init (CURL_GLOBAL_ALL))
+ {
+ fprintf (stderr, "Error: %s\n", strerror (errno));
+ return 0;
+ }
+
+ const char *aes128_sha = "AES128-SHA";
+ const char *aes256_sha = "AES256-SHA";
+ if (curl_uses_nss_ssl() == 0)
+ {
+ aes128_sha = "rsa_aes_128_sha";
+ aes256_sha = "rsa_aes_256_sha";
+ }
+
+
+ if (0 !=
+ test_wrap ("TLS1.0-AES-SHA1",
+ &test_https_transfer, NULL, daemon_flags,
+ aes128_sha,
+ CURL_SSLVERSION_TLSv1,
+ MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
+ MHD_OPTION_HTTPS_PRIORITIES, "NONE:+VERS-TLS1.0:+AES-128-CBC:+SHA1:+RSA:+COMP-NULL",
+ MHD_OPTION_END))
+ {
+ fprintf (stderr, "TLS1.0-AES-SHA1 test failed\n");
+ errorCount++;
+ }
+ fprintf (stderr,
+ "The following handshake should fail (and print an error message)...\n");
+ if (0 !=
+ test_wrap ("TLS1.0 vs SSL3",
+ &test_unmatching_ssl_version, NULL, daemon_flags,
+ aes256_sha,
+ CURL_SSLVERSION_SSLv3,
+ MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
+ MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
+ MHD_OPTION_HTTPS_PRIORITIES, "NONE:+VERS-TLS1.0:+AES-256-CBC:+SHA1:+RSA:+COMP-NULL",
+ MHD_OPTION_END))
+ {
+ fprintf (stderr, "TLS1.0 vs SSL3 test failed\n");
+ errorCount++;
+ }
+ curl_global_cleanup ();
+
+ return errorCount != 0;
+}
diff --git a/src/testcurl/https/tls_test_common.c b/src/testcurl/https/tls_test_common.c
new file mode 100644
index 0000000..f917582
--- /dev/null
+++ b/src/testcurl/https/tls_test_common.c
@@ -0,0 +1,484 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file tls_test_common.c
+ * @brief Common tls test functions
+ * @author Sagie Amir
+ */
+#include "tls_test_common.h"
+#include "tls_test_keys.h"
+
+
+int curl_check_version (const char *req_version, ...);
+
+FILE *
+setup_ca_cert ()
+{
+ FILE *cert_fd;
+
+ if (NULL == (cert_fd = fopen (ca_cert_file_name, "wb+")))
+ {
+ fprintf (stderr, "Error: failed to open `%s': %s\n",
+ ca_cert_file_name, strerror (errno));
+ return NULL;
+ }
+ if (fwrite (ca_cert_pem, sizeof (char), strlen (ca_cert_pem) + 1, cert_fd)
+ != strlen (ca_cert_pem) + 1)
+ {
+ fprintf (stderr, "Error: failed to write `%s. %s'\n",
+ ca_cert_file_name, strerror (errno));
+ fclose (cert_fd);
+ return NULL;
+ }
+ if (fflush (cert_fd))
+ {
+ fprintf (stderr, "Error: failed to flush ca cert file stream. %s\n",
+ strerror (errno));
+ fclose (cert_fd);
+ return NULL;
+ }
+ return cert_fd;
+}
+
+
+/*
+ * test HTTPS transfer
+ */
+int
+test_daemon_get (void *cls,
+ const char *cipher_suite, int proto_version,
+ int port,
+ int ver_peer)
+{
+ CURL *c;
+ struct CBC cbc;
+ CURLcode errornum;
+ char url[255];
+ size_t len;
+
+ len = strlen (test_data);
+ if (NULL == (cbc.buf = malloc (sizeof (char) * len)))
+ {
+ fprintf (stderr, MHD_E_MEM);
+ return -1;
+ }
+ cbc.size = len;
+ cbc.pos = 0;
+
+ /* construct url - this might use doc_path */
+ gen_test_file_url (url, port);
+
+ c = curl_easy_init ();
+#if DEBUG_HTTPS_TEST
+ curl_easy_setopt (c, CURLOPT_VERBOSE, 1);
+#endif
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_FILE, &cbc);
+
+ /* TLS options */
+ curl_easy_setopt (c, CURLOPT_SSLVERSION, proto_version);
+ curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite);
+
+ /* perform peer authentication */
+ /* TODO merge into send_curl_req */
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, ver_peer);
+ curl_easy_setopt (c, CURLOPT_CAINFO, ca_cert_file_name);
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr, "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ free (cbc.buf);
+ return errornum;
+ }
+
+ curl_easy_cleanup (c);
+
+ if (memcmp (cbc.buf, test_data, len) != 0)
+ {
+ fprintf (stderr, "Error: local file & received file differ.\n");
+ free (cbc.buf);
+ return -1;
+ }
+
+ free (cbc.buf);
+ return 0;
+}
+
+
+void
+print_test_result (int test_outcome, char *test_name)
+{
+#if 0
+ if (test_outcome != 0)
+ fprintf (stderr, "running test: %s [fail]\n", test_name);
+ else
+ fprintf (stdout, "running test: %s [pass]\n", test_name);
+#endif
+}
+
+size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+/**
+ * HTTP access handler call back
+ */
+int
+http_ahc (void *cls, struct MHD_Connection *connection,
+ const char *url, const char *method, const char *upload_data,
+ const char *version, size_t *upload_data_size, void **ptr)
+{
+ static int aptr;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
+ return MHD_NO; /* unexpected method */
+ if (&aptr != *ptr)
+ {
+ /* do never respond on first call */
+ *ptr = &aptr;
+ return MHD_YES;
+ }
+ *ptr = NULL; /* reset when done */
+ response = MHD_create_response_from_buffer (strlen (test_data),
+ (void *) test_data,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+/* HTTP access handler call back */
+int
+http_dummy_ahc (void *cls, struct MHD_Connection *connection,
+ const char *url, const char *method, const char *upload_data,
+ const char *version, size_t *upload_data_size,
+ void **ptr)
+{
+ return 0;
+}
+
+/**
+ * send a test http request to the daemon
+ * @param url
+ * @param cbc - may be null
+ * @param cipher_suite
+ * @param proto_version
+ * @return
+ */
+/* TODO have test wrap consider a NULL cbc */
+int
+send_curl_req (char *url, struct CBC * cbc, const char *cipher_suite,
+ int proto_version)
+{
+ CURL *c;
+ CURLcode errornum;
+ c = curl_easy_init ();
+#if DEBUG_HTTPS_TEST
+ curl_easy_setopt (c, CURLOPT_VERBOSE, CURL_VERBOS_LEVEL);
+#endif
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 60L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 60L);
+
+ if (cbc != NULL)
+ {
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_FILE, cbc);
+ }
+
+ /* TLS options */
+ curl_easy_setopt (c, CURLOPT_SSLVERSION, proto_version);
+ curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite);
+
+ /* currently skip any peer authentication */
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0);
+
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr, "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ return errornum;
+ }
+ curl_easy_cleanup (c);
+
+ return CURLE_OK;
+}
+
+
+/**
+ * compile test file url pointing to the current running directory path
+ *
+ * @param url - char buffer into which the url is compiled
+ * @param port port to use for the test
+ * @return -1 on error
+ */
+int
+gen_test_file_url (char *url, int port)
+{
+ int ret = 0;
+ char *doc_path;
+ size_t doc_path_len;
+ /* setup test file path, url */
+ doc_path_len = PATH_MAX > 4096 ? 4096 : PATH_MAX;
+ if (NULL == (doc_path = malloc (doc_path_len)))
+ {
+ fprintf (stderr, MHD_E_MEM);
+ return -1;
+ }
+ if (getcwd (doc_path, doc_path_len) == NULL)
+ {
+ fprintf (stderr, "Error: failed to get working directory. %s\n",
+ strerror (errno));
+ ret = -1;
+ }
+#ifdef WINDOWS
+ {
+ int i;
+ for (i = 0; i < doc_path_len; i++)
+ {
+ if (doc_path[i] == 0)
+ break;
+ if (doc_path[i] == '\\')
+ {
+ doc_path[i] = '/';
+ }
+ if (doc_path[i] != ':')
+ continue;
+ if (i == 0)
+ break;
+ doc_path[i] = doc_path[i - 1];
+ doc_path[i - 1] = '/';
+ }
+ }
+#endif
+ /* construct url - this might use doc_path */
+ if (sprintf (url, "%s:%d%s/%s", "https://127.0.0.1", port,
+ doc_path, "urlpath") < 0)
+ ret = -1;
+
+ free (doc_path);
+ return ret;
+}
+
+/**
+ * test HTTPS file transfer
+ */
+int
+test_https_transfer (void *cls, const char *cipher_suite, int proto_version)
+{
+ int len;
+ int ret = 0;
+ struct CBC cbc;
+ char url[255];
+
+ len = strlen (test_data);
+ if (NULL == (cbc.buf = malloc (sizeof (char) * len)))
+ {
+ fprintf (stderr, MHD_E_MEM);
+ return -1;
+ }
+ cbc.size = len;
+ cbc.pos = 0;
+
+ if (gen_test_file_url (url, DEAMON_TEST_PORT))
+ {
+ ret = -1;
+ goto cleanup;
+ }
+
+ if (CURLE_OK != send_curl_req (url, &cbc, cipher_suite, proto_version))
+ {
+ ret = -1;
+ goto cleanup;
+ }
+
+ /* compare test file & daemon responce */
+ if ( (len != strlen (test_data)) ||
+ (memcmp (cbc.buf,
+ test_data,
+ len) != 0) )
+ {
+ fprintf (stderr, "Error: local file & received file differ.\n");
+ ret = -1;
+ }
+cleanup:
+ free (cbc.buf);
+ return ret;
+}
+
+/**
+ * setup test case
+ *
+ * @param d
+ * @param daemon_flags
+ * @param arg_list
+ * @return
+ */
+int
+setup_testcase (struct MHD_Daemon **d, int daemon_flags, va_list arg_list)
+{
+ *d = MHD_start_daemon_va (daemon_flags, DEAMON_TEST_PORT,
+ NULL, NULL, &http_ahc, NULL, arg_list);
+
+ if (*d == NULL)
+ {
+ fprintf (stderr, MHD_E_SERVER_INIT);
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+teardown_testcase (struct MHD_Daemon *d)
+{
+ MHD_stop_daemon (d);
+}
+
+int
+setup_session (gnutls_session_t * session,
+ gnutls_datum_t * key,
+ gnutls_datum_t * cert,
+ gnutls_certificate_credentials_t * xcred)
+{
+ int ret;
+ const char *err_pos;
+
+ gnutls_certificate_allocate_credentials (xcred);
+ key->size = strlen (srv_key_pem) + 1;
+ key->data = malloc (key->size);
+ if (NULL == key->data)
+ {
+ gnutls_certificate_free_credentials (*xcred);
+ return -1;
+ }
+ memcpy (key->data, srv_key_pem, key->size);
+ cert->size = strlen (srv_self_signed_cert_pem) + 1;
+ cert->data = malloc (cert->size);
+ if (NULL == cert->data)
+ {
+ gnutls_certificate_free_credentials (*xcred);
+ free (key->data);
+ return -1;
+ }
+ memcpy (cert->data, srv_self_signed_cert_pem, cert->size);
+ gnutls_certificate_set_x509_key_mem (*xcred, cert, key,
+ GNUTLS_X509_FMT_PEM);
+ gnutls_init (session, GNUTLS_CLIENT);
+ ret = gnutls_priority_set_direct (*session,
+ "NORMAL", &err_pos);
+ if (ret < 0)
+ {
+ gnutls_deinit (*session);
+ gnutls_certificate_free_credentials (*xcred);
+ free (key->data);
+ return -1;
+ }
+ gnutls_credentials_set (*session,
+ GNUTLS_CRD_CERTIFICATE,
+ *xcred);
+ return 0;
+}
+
+int
+teardown_session (gnutls_session_t session,
+ gnutls_datum_t * key,
+ gnutls_datum_t * cert,
+ gnutls_certificate_credentials_t xcred)
+{
+ free (key->data);
+ key->data = NULL;
+ key->size = 0;
+ free (cert->data);
+ cert->data = NULL;
+ cert->size = 0;
+ gnutls_deinit (session);
+ gnutls_certificate_free_credentials (xcred);
+ return 0;
+}
+
+/* TODO test_wrap: change sig to (setup_func, test, va_list test_arg) */
+int
+test_wrap (const char *test_name, int
+ (*test_function) (void * cls, const char *cipher_suite,
+ int proto_version), void * cls,
+ int daemon_flags, const char *cipher_suite, int proto_version, ...)
+{
+ int ret;
+ va_list arg_list;
+ struct MHD_Daemon *d;
+
+ va_start (arg_list, proto_version);
+ if (setup_testcase (&d, daemon_flags, arg_list) != 0)
+ {
+ va_end (arg_list);
+ fprintf (stderr, "Failed to setup testcase %s\n", test_name);
+ return -1;
+ }
+#if 0
+ fprintf (stdout, "running test: %s ", test_name);
+#endif
+ ret = test_function (NULL, cipher_suite, proto_version);
+#if 0
+ if (ret == 0)
+ {
+ fprintf (stdout, "[pass]\n");
+ }
+ else
+ {
+ fprintf (stdout, "[fail]\n");
+ }
+#endif
+ teardown_testcase (d);
+ va_end (arg_list);
+ return ret;
+}
diff --git a/src/testcurl/https/tls_test_common.h b/src/testcurl/https/tls_test_common.h
new file mode 100644
index 0000000..20198f7
--- /dev/null
+++ b/src/testcurl/https/tls_test_common.h
@@ -0,0 +1,141 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TLS_TEST_COMMON_H_
+#define TLS_TEST_COMMON_H_
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <curl/curl.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <gnutls/gnutls.h>
+
+/* this enables verbos CURL version checking */
+#define DEBUG_HTTPS_TEST 0
+#define CURL_VERBOS_LEVEL 0
+
+#define DEAMON_TEST_PORT 4233
+
+#define test_data "Hello World\n"
+#define ca_cert_file_name "tmp_ca_cert.pem"
+
+#define EMPTY_PAGE "<html><head><title>Empty page</title></head><body>Empty page</body></html>"
+#define PAGE_NOT_FOUND "<html><head><title>File not found</title></head><body>File not found</body></html>"
+
+#define MHD_E_MEM "Error: memory error\n"
+#define MHD_E_SERVER_INIT "Error: failed to start server\n"
+#define MHD_E_TEST_FILE_CREAT "Error: failed to setup test file\n"
+#define MHD_E_CERT_FILE_CREAT "Error: failed to setup test certificate\n"
+#define MHD_E_KEY_FILE_CREAT "Error: failed to setup test certificate\n"
+#define MHD_E_FAILED_TO_CONNECT "Error: server connection could not be established\n"
+
+/* TODO rm if unused */
+struct https_test_data
+{
+ void *cls;
+ const char *cipher_suite;
+ int proto_version;
+};
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+struct CipherDef
+{
+ int options[2];
+ char *curlname;
+};
+
+
+int curl_check_version (const char *req_version, ...);
+int curl_uses_nss_ssl ();
+
+
+FILE *
+setup_ca_cert ();
+
+/**
+ * perform cURL request for file
+ */
+int
+test_daemon_get (void * cls,
+ const char *cipher_suite, int proto_version,
+ int port, int ver_peer);
+
+void print_test_result (int test_outcome, char *test_name);
+
+size_t copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx);
+
+int
+http_ahc (void *cls, struct MHD_Connection *connection,
+ const char *url, const char *method, const char *upload_data,
+ const char *version, size_t *upload_data_size, void **ptr);
+
+int
+http_dummy_ahc (void *cls, struct MHD_Connection *connection,
+ const char *url, const char *method, const char *upload_data,
+ const char *version, size_t *upload_data_size,
+ void **ptr);
+
+
+/**
+ * compile test file url pointing to the current running directory path
+ *
+ * @param url - char buffer into which the url is compiled
+ * @param port port to use for the test
+ * @return -1 on error
+ */
+int gen_test_file_url (char *url, int port);
+
+int
+send_curl_req (char *url, struct CBC *cbc, const char *cipher_suite,
+ int proto_version);
+
+int
+test_https_transfer (void *cls, const char *cipher_suite, int proto_version);
+
+int
+setup_testcase (struct MHD_Daemon **d, int daemon_flags, va_list arg_list);
+
+void teardown_testcase (struct MHD_Daemon *d);
+
+int
+setup_session (gnutls_session_t * session,
+ gnutls_datum_t * key,
+ gnutls_datum_t * cert,
+ gnutls_certificate_credentials_t * xcred);
+
+int
+teardown_session (gnutls_session_t session,
+ gnutls_datum_t * key,
+ gnutls_datum_t * cert,
+ gnutls_certificate_credentials_t xcred);
+
+int
+test_wrap (const char *test_name, int
+ (*test_function) (void * cls, const char *cipher_suite,
+ int proto_version), void *test_function_cls,
+ int daemon_flags, const char *cipher_suite, int proto_version, ...);
+#endif /* TLS_TEST_COMMON_H_ */
diff --git a/src/testcurl/https/tls_test_keys.h b/src/testcurl/https/tls_test_keys.h
new file mode 100644
index 0000000..b6e37ee
--- /dev/null
+++ b/src/testcurl/https/tls_test_keys.h
@@ -0,0 +1,173 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2006, 2007, 2008 Christian Grothoff (and other contributing authors)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MHD_TLS_TEST_KEYS_H
+#define MHD_TLS_TEST_KEYS_H
+
+/* Test Certificates */
+
+/* Certificate Authority key */
+const char ca_key_pem[] = "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIIEowIBAAKCAQEA0EdlP613rjFvEj93tGo9fzBoKWU3CW+AbbfcJ397C89MyZ9J\n"
+ "rlxyLGfa6qVX7CFVNmzgWWfcl2tHlw/fZmWtf/SFgrlkldvuGyY8H3n2HuMsWz/E\n"
+ "h7n5VgwBX8NsP4eZNmikepxpr1mYx25K8FjnsKjAR9jGUSV8UfZ7VLIY0x/yqe+3\n"
+ "32oqc4D/wJbV1AwwvC5Xf9rvHJwcZg57eqbDCL/4GDDk7d9Gark4XK6ZG+FnnxQn\n"
+ "4a4jIdf4FoPp9s0EieHrHwYzs/uBqmfCSF4wXiaO8bmEwtbAsVbZH74Le7ggUbEe\n"
+ "o+jan9XK0dE88AIImGzgoBnlic/Rr7J8OWA+iwIDAQABAoIBAEICZqXkUdpsw2F6\n"
+ "qPMOergNPO3lrKg6ZO8hBs6j2fj3tcPuzljK5sqJDboxNejZ9Zo+rmnXf3Oj5fgL\n"
+ "6UcYMYEsm4W/QRA3uEJ1fzeQnT7Ty9KNprlHaSzquCLEGlIWJSo3xu0vFlWjJUcL\n"
+ "fwemfaOhD/OVUeEU6s5FOngwy6pZUsOajs3fNRtwBGuuXjniKZZlpSf2Wqu3xpHZ\n"
+ "31OF1V0ycUCGPPFtpmUCtnZhS9L8QBTkNtfTIdXv6SfoBRFm0oXb0uL5HGft6yc7\n"
+ "eYRXIscllQciqG3ymJ/y9o0E3A0YsBVauQyi7OEk+Kg8uoYOBkZCIY69hoN2Znlk\n"
+ "OY5S5Z0CgYEA3j8pRAJzvc827KcX4vJf05HYD4aCyaI80fNmx1DgXfglTSGLQ361\n"
+ "6i05YW8WtIvgkma3wF+jJOckBCW/7iq8wAX7Kz75WKGRyyTEb0wSfjx0G8grxX4d\n"
+ "7sTIAAOnQj5WT6E/bkqxQZAYnVtIPxKtSlwts0H/bjPVYwSFchHK7t8CgYEA7+ks\n"
+ "C0EMjF8CDeCfvbOUGiiqAvU3G20LEC3WlJM3AU+J9Jzp6AMkgaIA8J5oNdsbFBn4\n"
+ "N12JPOO+7WRUk6Av8bsh4faE36ThnHohgAL8guRU7jIXvsFyO5yiY7/o/0lES0/V\n"
+ "6xkh/Epj4MReuCGkiD9ifCVAo+dhHskeE9qbYdUCgYA4yBpa7eV0UUTPIcHQkew5\n"
+ "ucFh9hPkQDcZzP4tXlR0rbmaAz/5dp4zvmoyopdCeZpezS+VTtn3y7Y/+QUYbILc\n"
+ "7KpHWkeKhX0iUbp+VQlEh12C25mTU62CG3SdzFEnc5XJsoDqRNsUzSP80B2dP8BW\n"
+ "h0aFzg7csRGLwtP1WOZoMQKBgQCrgsKd+Q8Dexh421DXyX3jhZalLrEKxlXWZy60\n"
+ "YNo98aLqYRNHbpe2pR6O5nARsGYXZMlyq0flY9um0sc0Epyz79g1NoufZrxzpUw1\n"
+ "u+zRlnKxJtaa5KjJvRzKuvPTLYnJXXXM8Na/Cl+E3F3qvQJm9QlvPyKLCmsAGz+J\n"
+ "agsTUQKBgC0wqqJ6b1tbrAD8AVeeAn/IiP1rxYpc3x2s6ikFO2FMHXHC9wgrRPOc\n"
+ "mkokV+DrUOv3I/7jG8wQA/FmBUPy562a1bObIKzg6CPXzrN68AmNnOIVU+H8fdxI\n"
+ "iGyfT8WNpcRmtN11v34qXHwOWGQhpyyk2yNa8VIBSpkShq/EseZ1\n"
+ "-----END RSA PRIVATE KEY-----\n";
+
+/* Certificate Authority cert */
+const char ca_cert_pem[] = "-----BEGIN CERTIFICATE-----\n"
+ "MIIC6DCCAdKgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz\n"
+ "dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG\n"
+ "A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA\n"
+ "0EdlP613rjFvEj93tGo9fzBoKWU3CW+AbbfcJ397C89MyZ9JrlxyLGfa6qVX7CFV\n"
+ "NmzgWWfcl2tHlw/fZmWtf/SFgrlkldvuGyY8H3n2HuMsWz/Eh7n5VgwBX8NsP4eZ\n"
+ "Nmikepxpr1mYx25K8FjnsKjAR9jGUSV8UfZ7VLIY0x/yqe+332oqc4D/wJbV1Aww\n"
+ "vC5Xf9rvHJwcZg57eqbDCL/4GDDk7d9Gark4XK6ZG+FnnxQn4a4jIdf4FoPp9s0E\n"
+ "ieHrHwYzs/uBqmfCSF4wXiaO8bmEwtbAsVbZH74Le7ggUbEeo+jan9XK0dE88AII\n"
+ "mGzgoBnlic/Rr7J8OWA+iwIDAQABo0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1Ud\n"
+ "DwEB/wQFAwMHBAAwHQYDVR0OBBYEFP2olB4s2T/xuoQ5pT2RKojFwZo2MAsGCSqG\n"
+ "SIb3DQEBBQOCAQEAebD5m+vZkVXa8y+QZ5GtsiR9gpH+LKtdWBjk1kmfSgvQI/xA\n"
+ "aDCV/9BhdNGIBOTYGkln8urWd7g2Mj3TwKEAfNTUFpAsrBAlSSLTGYCSt72S2NsS\n"
+ "L/qUxmj1W6X95UHXCo49mSZx3LlaY3mz1L87gq/kK0XpzA3g2uF25jt84RvshsXy\n"
+ "clOc+eRrVETqFZqer96WB7kzFTv+qmROQKmW8X4a2A5r5Jl4vRwOz5/rEeB9Qs0K\n"
+ "rmK8+5HgvWd80WB8BtfFtZfoY/hHVM8nLD3ELVJrOKiTeIACunQFyT5lV0QkdmSA\n"
+ "CGInU7jzs8nu+s2avf6j+eVZUbVJ+dFMApTJgg==\n"
+ "-----END CERTIFICATE-----\n";
+
+/* test server CA signed certificates */
+const char srv_signed_cert_pem[] = "-----BEGIN CERTIFICATE-----\n"
+ "MIIDGzCCAgWgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz\n"
+ "dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG\n"
+ "A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA\n"
+ "vfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW+K03KwEku55QvnUn\n"
+ "dwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8ILq4sw32vo0fbMu5BZ\n"
+ "F49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ020Q5EAAEseD1YtWC\n"
+ "IpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6QYGGh1QmHRPAy3CB\n"
+ "II6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6xyoOl204xuekZOaG9\n"
+ "RUPId74Rtmwfi1TLbBzo2wIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM\n"
+ "MAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHIAAwHQYDVR0OBBYEFOFi4ilKOP1d\n"
+ "XHlWCMwmVKr7mgy8MB8GA1UdIwQYMBaAFP2olB4s2T/xuoQ5pT2RKojFwZo2MAsG\n"
+ "CSqGSIb3DQEBBQOCAQEAHVWPxazupbOkG7Did+dY9z2z6RjTzYvurTtEKQgzM2Vz\n"
+ "GQBA+3pZ3c5mS97fPIs9hZXfnQeelMeZ2XP1a+9vp35bJjZBBhVH+pqxjCgiUflg\n"
+ "A3Zqy0XwwVCgQLE2HyaU3DLUD/aeIFK5gJaOSdNTXZLv43K8kl4cqDbMeRpVTbkt\n"
+ "YmG4AyEOYRNKGTqMEJXJoxD5E3rBUNrVI/XyTjYrulxbNPcMWEHKNeeqWpKDYTFo\n"
+ "Bb01PCthGXiq/4A2RLAFosadzRa8SBpoSjPPfZ0b2w4MJpReHqKbR5+T2t6hzml6\n"
+ "4ToyOKPDmamiTuN5KzLN3cw7DQlvWMvqSOChPLnA3Q==\n"
+ "-----END CERTIFICATE-----\n";
+
+/* test server key */
+const char srv_signed_key_pem[] = "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIIEowIBAAKCAQEAvfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW\n"
+ "+K03KwEku55QvnUndwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8IL\n"
+ "q4sw32vo0fbMu5BZF49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ0\n"
+ "20Q5EAAEseD1YtWCIpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6\n"
+ "QYGGh1QmHRPAy3CBII6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6x\n"
+ "yoOl204xuekZOaG9RUPId74Rtmwfi1TLbBzo2wIDAQABAoIBADu09WSICNq5cMe4\n"
+ "+NKCLlgAT1NiQpLls1gKRbDhKiHU9j8QWNvWWkJWrCya4QdUfLCfeddCMeiQmv3K\n"
+ "lJMvDs+5OjJSHFoOsGiuW2Ias7IjnIojaJalfBml6frhJ84G27IXmdz6gzOiTIer\n"
+ "DjeAgcwBaKH5WwIay2TxIaScl7AwHBauQkrLcyb4hTmZuQh6ArVIN6+pzoVuORXM\n"
+ "bpeNWl2l/HSN3VtUN6aCAKbN/X3o0GavCCMn5Fa85uJFsab4ss/uP+2PusU71+zP\n"
+ "sBm6p/2IbGvF5k3VPDA7X5YX61sukRjRBihY8xSnNYx1UcoOsX6AiPnbhifD8+xQ\n"
+ "Tlf8oJUCgYEA0BTfzqNpr9Wxw5/QXaSdw7S/0eP5a0C/nwURvmfSzuTD4equzbEN\n"
+ "d+dI/s2JMxrdj/I4uoAfUXRGaabevQIjFzC9uyE3LaOyR2zhuvAzX+vVcs6bSXeU\n"
+ "pKpCAcN+3Z3evMaX2f+z/nfSUAl2i4J2R+/LQAWJW4KwRky/m+cxpfUCgYEA6bN1\n"
+ "b73bMgM8wpNt6+fcmS+5n0iZihygQ2U2DEud8nZJL4Nrm1dwTnfZfJBnkGj6+0Q0\n"
+ "cOwj2KS0/wcEdJBP0jucU4v60VMhp75AQeHqidIde0bTViSRo3HWKXHBIFGYoU3T\n"
+ "LyPyKndbqsOObnsFXHn56Nwhr2HLf6nw4taGQY8CgYBoSW36FLCNbd6QGvLFXBGt\n"
+ "2lMhEM8az/K58kJ4WXSwOLtr6MD/WjNT2tkcy0puEJLm6BFCd6A6pLn9jaKou/92\n"
+ "SfltZjJPb3GUlp9zn5tAAeSSi7YMViBrfuFiHObij5LorefBXISLjuYbMwL03MgH\n"
+ "Ocl2JtA2ywMp2KFXs8GQWQKBgFyIVv5ogQrbZ0pvj31xr9HjqK6d01VxIi+tOmpB\n"
+ "4ocnOLEcaxX12BzprW55ytfOCVpF1jHD/imAhb3YrHXu0fwe6DXYXfZV4SSG2vB7\n"
+ "IB9z14KBN5qLHjNGFpMQXHSMek+b/ftTU0ZnPh9uEM5D3YqRLVd7GcdUhHvG8P8Q\n"
+ "C9aXAoGBAJtID6h8wOGMP0XYX5YYnhlC7dOLfk8UYrzlp3xhqVkzKthTQTj6wx9R\n"
+ "GtC4k7U1ki8oJsfcIlBNXd768fqDVWjYju5rzShMpo8OCTS6ipAblKjCxPPVhIpv\n"
+ "tWPlbSn1qj6wylstJ5/3Z+ZW5H4wIKp5jmLiioDhcP0L/Ex3Zx8O\n"
+ "-----END RSA PRIVATE KEY-----\n";
+
+/* test server self signed certificates */
+const char srv_self_signed_cert_pem[] = "-----BEGIN CERTIFICATE-----\n"
+ "MIIC+jCCAeSgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz\n"
+ "dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG\n"
+ "A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA\n"
+ "tDEagv3p9OUhUL55jMucxjNK9N5cuozhcnrwDfBSU6oVrqm5kPqO1I7Cggzw68Y5\n"
+ "jhTcBi4FXmYOZppm1R3MhSJ5JSi/67Q7X4J5rnJLXYGN27qjMpnoGQ/2xmsNG/is\n"
+ "i+h/2vbtPU+WP9SEJnTfPLLpZ7KqCAk7FUUzKsuLx3/SOKtdkrWxPKwYTgnDEN6D\n"
+ "JL7tEzCnG5DFc4mQ7YW9PaRdC3rS1T8PvQ3jB2BUnohM0cFvKRuiU35tU7h7CPbL\n"
+ "4L66VglXoiwqmgcrwI2U968bD0+wRQ5c5bzNoshJOzN6CTMh1IhbklSh/Z6FA/e8\n"
+ "hj0yVo2tdllXuJGVs3PIEwIDAQABo1UwUzAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM\n"
+ "MAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHIAAwHQYDVR0OBBYEFDfU7pAv9LYn\n"
+ "n7jb4WHl4+Vgi2FnMAsGCSqGSIb3DQEBBQOCAQEAkaembPQMmv6OOjbIod8zTatr\n"
+ "x5Bwkwp3TOE1NRyy2OytzFIYRUkNrZYlcmrxcbNNycIK41CNVXbriFCF8gcmIq9y\n"
+ "vaKZn8Gcy+vGggv+1BP9IAPBGKRwSi0wmq9JoGE8hx+qqTpRSdfbM/cps/09hicO\n"
+ "0EIR7kWEbvnpMBcMKYOtYE9Gce7rdSMWVAsKc174xn8vW6TxCUvmWFv5DPg5HG1v\n"
+ "y1SUX73qafRo+W6FN4UC/DHfwRhF8RSKEnVbmgDVCs6GHdKBjU2qRgYyj6nWZqK1\n"
+ "XFUTWgia+Fl3D9vlsXaFcSZKA0Bq1eojl0B0AfeYAxTFwPWXscKvt/bXZfH8bg==\n"
+ "-----END CERTIFICATE-----\n";
+
+/* test server key */
+const char srv_key_pem[] = "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIIEpAIBAAKCAQEAtDEagv3p9OUhUL55jMucxjNK9N5cuozhcnrwDfBSU6oVrqm5\n"
+ "kPqO1I7Cggzw68Y5jhTcBi4FXmYOZppm1R3MhSJ5JSi/67Q7X4J5rnJLXYGN27qj\n"
+ "MpnoGQ/2xmsNG/isi+h/2vbtPU+WP9SEJnTfPLLpZ7KqCAk7FUUzKsuLx3/SOKtd\n"
+ "krWxPKwYTgnDEN6DJL7tEzCnG5DFc4mQ7YW9PaRdC3rS1T8PvQ3jB2BUnohM0cFv\n"
+ "KRuiU35tU7h7CPbL4L66VglXoiwqmgcrwI2U968bD0+wRQ5c5bzNoshJOzN6CTMh\n"
+ "1IhbklSh/Z6FA/e8hj0yVo2tdllXuJGVs3PIEwIDAQABAoIBAAEtcg+LFLGtoxjq\n"
+ "b+tFttBJfbRcfdG6ocYqBGmUXF+MgFs573DHX3sHNOQxlaNHtSgIclF1eYgNZFFt\n"
+ "VLIoBFTzfEQXoFosPUDoEuqVMeXLttmD7P2jwL780XJLZ4Xj6GY07npq1iGBcEZf\n"
+ "yCcdoyGkr9jgc5Auyis8DStGg/jfUBC4NBvF0GnuuNPAdYRPKUpKw9EatI+FdMjy\n"
+ "BuroD90fhdkK8EwMEVb9P17bdIc1MCIZFpUE9YHjVdK/oxCUhQ8KRfdbI4JU5Zh3\n"
+ "UtO6Jm2wFuP3VmeVpPvE/C2rxI70pyl6HMSiFGNc0rhJYCQ+yhohWj7nZ67H4vLx\n"
+ "plv5LxkCgYEAz7ewou8oFafDAMNoxaqKudvUg+lxXewdLDKaYBF5ACi9uAPCJ+v7\n"
+ "M5c/fvPFn/XHzo7xaXbtTAH3Z5xzBs+80OsvL+e1Ut4xR+ELRkybknh/s2wQeABk\n"
+ "Kb0vA59ukQGj12LV5phZMaVoXe6KJ7hZnN62d3K6m1wGE/k58i4pPLUCgYEA3hN8\n"
+ "G95zW7g0jVdSr+KUeVmephph9yh8Yb+3I3ojwOIv6d45TopGx8pFZlnBAMZf1ZQx\n"
+ "DIhzJNnaqZy/4w7RNaOGWnPA/5f+MIoHBiLGEEmfHC3lt087Yp9OuwDUHwpETYdV\n"
+ "o+KBCvVh60Et3bZUgF/1k/3YXxn8J5dsmJsjNqcCgYBLflyRa1BrRnTGMz9CEDCp\n"
+ "Si9b3h1Y4Hbd2GppHhCXMTd6yMrpDYhYANGQB3M9Juv+s88j4JhwNoq/uonH4Pqk\n"
+ "B8Y3qAQr4RuSH0WkwDUOsALhqBX4N1QwI1USAQEDbNAqeP5698X7GD3tXcQSmZrg\n"
+ "O8WfdjBCRNjkq4EW9xX/vQKBgQDONtmwJ0iHiu2BseyeVo/4fzfKlgUSNQ4K1rOA\n"
+ "xhIdMeu8Bxa/z7caHsGC4SVPSuYCtbE2Kh6BwapChcPJXCD45fgEViiJLuJiwEj1\n"
+ "caTpyvNsf1IoffJvCe9ZxtMyX549P8ZOgC3Dt0hN5CBrGLwu2Ox5l+YrqT10pi+5\n"
+ "JZX1UQKBgQCrcXrdkkDAc/a4+PxNRpJRLcU4fhv8/lr+UWItE8eUe7bd25bTQfQm\n"
+ "VpNKc/kAJ66PjIED6fy3ADhd2y4naT2a24uAgQ/M494J68qLnGh6K4JU/09uxR2v\n"
+ "1i2q/4FNLdFFk1XP4iNnTHRLZ+NYr2p5Y9RcvQfTjOauz8Ahav0lyg==\n"
+ "-----END RSA PRIVATE KEY-----\n";
+
+#endif
diff --git a/src/testcurl/perf_get.c b/src/testcurl/perf_get.c
new file mode 100644
index 0000000..1e42f7d
--- /dev/null
+++ b/src/testcurl/perf_get.c
@@ -0,0 +1,532 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009, 2011 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file perf_get.c
+ * @brief benchmark simple GET operations (sequential access).
+ * Note that we run libcurl in the same process at the
+ * same time, so the execution time given is the combined
+ * time for both MHD and libcurl; it is quite possible
+ * that more time is spend with libcurl than with MHD,
+ * so the performance scores calculated with this code
+ * should NOT be used to compare with other HTTP servers
+ * (since MHD is actually better); only the relative
+ * scores between MHD versions are meaningful.
+ * Furthermore, this code ONLY tests MHD processing
+ * a single request at a time. This is again
+ * not universally meaningful (i.e. when comparing
+ * multithreaded vs. single-threaded or select/poll).
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "gauger.h"
+
+#ifndef WINDOWS
+#include <unistd.h>
+#include <sys/socket.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+/**
+ * How many rounds of operations do we do for each
+ * test?
+ */
+#define ROUNDS 500
+
+/**
+ * Do we use HTTP 1.1?
+ */
+static int oneone;
+
+/**
+ * Response to return (re-used).
+ */
+static struct MHD_Response *response;
+
+/**
+ * Time this round was started.
+ */
+static unsigned long long start_time;
+
+
+/**
+ * Get the current timestamp
+ *
+ * @return current time in ms
+ */
+static unsigned long long
+now ()
+{
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+ return (((unsigned long long) tv.tv_sec * 1000LL) +
+ ((unsigned long long) tv.tv_usec / 1000LL));
+}
+
+
+/**
+ * Start the timer.
+ */
+static void
+start_timer()
+{
+ start_time = now ();
+}
+
+
+/**
+ * Stop the timer and report performance
+ *
+ * @param desc description of the threading mode we used
+ */
+static void
+stop (const char *desc)
+{
+ double rps = ((double) (ROUNDS * 1000)) / ((double) (now() - start_time));
+
+ fprintf (stderr,
+ "Sequential GETs using %s: %f %s\n",
+ desc,
+ rps,
+ "requests/s");
+ GAUGER (desc,
+ "Sequential GETs",
+ rps,
+ "requests/s");
+}
+
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+
+static size_t
+copyBuffer (void *ptr,
+ size_t size, size_t nmemb,
+ void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static int
+testInternalGet (int port, int poll_flag)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ unsigned int i;
+ char url[64];
+
+ sprintf(url, "http://127.0.0.1:%d/hello_world", port);
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ start_timer ();
+ for (i=0;i<ROUNDS;i++)
+ {
+ cbc.pos = 0;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ }
+ stop (poll_flag == MHD_USE_POLL ? "internal poll" :
+ poll_flag == MHD_USE_EPOLL_LINUX_ONLY ? "internal epoll" : "internal select");
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+
+static int
+testMultithreadedGet (int port, int poll_flag)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ unsigned int i;
+ char url[64];
+
+ sprintf(url, "http://127.0.0.1:%d/hello_world", port);
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
+ port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ start_timer ();
+ for (i=0;i<ROUNDS;i++)
+ {
+ cbc.pos = 0;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ }
+ stop ((poll_flag & MHD_USE_POLL) ? "thread with poll" :
+ (poll_flag & MHD_USE_EPOLL_LINUX_ONLY) ? "thread with epoll" : "thread with select");
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testMultithreadedPoolGet (int port, int poll_flag)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ unsigned int i;
+ char url[64];
+
+ sprintf(url, "http://127.0.0.1:%d/hello_world", port);
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ port, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ start_timer ();
+ for (i=0;i<ROUNDS;i++)
+ {
+ cbc.pos = 0;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ }
+ stop (0 != (poll_flag & MHD_USE_POLL) ? "thread pool with poll" :
+ 0 != (poll_flag & MHD_USE_EPOLL_LINUX_ONLY) ? "thread pool with epoll" : "thread pool with select");
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testExternalGet (int port)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+ unsigned int i;
+ char url[64];
+
+ sprintf(url, "http://127.0.0.1:%d/hello_world", port);
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ start_timer ();
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ for (i=0;i<ROUNDS;i++)
+ {
+ cbc.pos = 0;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (c != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ c = NULL;
+ }
+ }
+ /* two possibilities here; as select sets are
+ tiny, this makes virtually no difference
+ in actual runtime right now, even though the
+ number of select calls is virtually cut in half
+ (and 'select' is the most expensive of our system
+ calls according to 'strace') */
+ if (0)
+ MHD_run (d);
+ else
+ MHD_run_from_select (d, &rs, &ws, &es);
+ }
+ if (NULL != c)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ fprintf (stderr, "Timeout!?\n");
+ }
+ }
+ stop ("external select");
+ if (multi != NULL)
+ {
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+ int port = 1081;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ response = MHD_create_response_from_buffer (strlen ("/hello_world"),
+ "/hello_world",
+ MHD_RESPMEM_MUST_COPY);
+ errorCount += testExternalGet (port++);
+ errorCount += testInternalGet (port++, 0);
+ errorCount += testMultithreadedGet (port++, 0);
+ errorCount += testMultithreadedPoolGet (port++, 0);
+ if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_POLL))
+ {
+ errorCount += testInternalGet(port++, MHD_USE_POLL);
+ errorCount += testMultithreadedGet(port++, MHD_USE_POLL);
+ errorCount += testMultithreadedPoolGet(port++, MHD_USE_POLL);
+ }
+ if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_EPOLL))
+ {
+ errorCount += testInternalGet(port++, MHD_USE_EPOLL_LINUX_ONLY);
+ errorCount += testMultithreadedPoolGet(port++, MHD_USE_EPOLL_LINUX_ONLY);
+ }
+ MHD_destroy_response (response);
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/perf_get_concurrent.c b/src/testcurl/perf_get_concurrent.c
new file mode 100644
index 0000000..28559ee
--- /dev/null
+++ b/src/testcurl/perf_get_concurrent.c
@@ -0,0 +1,364 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009, 2011 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file perf_get_concurrent.c
+ * @brief benchmark concurrent GET operations
+ * Note that we run libcurl on the machine at the
+ * same time, so the execution time may be influenced
+ * by the concurrent activity; it is quite possible
+ * that more time is spend with libcurl than with MHD,
+ * so the performance scores calculated with this code
+ * should NOT be used to compare with other HTTP servers
+ * (since MHD is actually better); only the relative
+ * scores between MHD versions are meaningful.
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "gauger.h"
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+/**
+ * How many rounds of operations do we do for each
+ * test (total number of requests will be ROUNDS * PAR).
+ */
+#define ROUNDS 500
+
+/**
+ * How many requests do we do in parallel?
+ */
+#define PAR CPU_COUNT
+
+/**
+ * Do we use HTTP 1.1?
+ */
+static int oneone;
+
+/**
+ * Response to return (re-used).
+ */
+static struct MHD_Response *response;
+
+/**
+ * Time this round was started.
+ */
+static unsigned long long start_time;
+
+
+/**
+ * Get the current timestamp
+ *
+ * @return current time in ms
+ */
+static unsigned long long
+now ()
+{
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+ return (((unsigned long long) tv.tv_sec * 1000LL) +
+ ((unsigned long long) tv.tv_usec / 1000LL));
+}
+
+
+/**
+ * Start the timer.
+ */
+static void
+start_timer()
+{
+ start_time = now ();
+}
+
+
+/**
+ * Stop the timer and report performance
+ *
+ * @param desc description of the threading mode we used
+ */
+static void
+stop (const char *desc)
+{
+ double rps = ((double) (PAR * ROUNDS * 1000)) / ((double) (now() - start_time));
+
+ fprintf (stderr,
+ "Parallel GETs using %s: %f %s\n",
+ desc,
+ rps,
+ "requests/s");
+ GAUGER (desc,
+ "Parallel GETs",
+ rps,
+ "requests/s");
+}
+
+
+static size_t
+copyBuffer (void *ptr,
+ size_t size, size_t nmemb,
+ void *ctx)
+{
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static pid_t
+do_gets (int port)
+{
+ pid_t ret;
+ CURL *c;
+ CURLcode errornum;
+ unsigned int i;
+ unsigned int j;
+ pid_t par[PAR];
+ char url[64];
+
+ sprintf(url, "http://127.0.0.1:%d/hello_world", port);
+
+ ret = fork ();
+ if (ret == -1) abort ();
+ if (ret != 0)
+ return ret;
+ for (j=0;j<PAR;j++)
+ {
+ par[j] = fork ();
+ if (par[j] == 0)
+ {
+ for (i=0;i<ROUNDS;i++)
+ {
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ _exit (1);
+ }
+ curl_easy_cleanup (c);
+ }
+ _exit (0);
+ }
+ }
+ for (j=0;j<PAR;j++)
+ waitpid (par[j], NULL, 0);
+ _exit (0);
+}
+
+
+static void
+join_gets (pid_t pid)
+{
+ int status;
+
+ status = 1;
+ waitpid (pid, &status, 0);
+ if (0 != status)
+ abort ();
+}
+
+
+static int
+testInternalGet (int port, int poll_flag)
+{
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ start_timer ();
+ join_gets (do_gets (port));
+ stop (poll_flag ? "internal poll" : "internal select");
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+
+static int
+testMultithreadedGet (int port, int poll_flag)
+{
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
+ port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ start_timer ();
+ join_gets (do_gets (port));
+ stop (poll_flag ? "thread with poll" : "thread with select");
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+static int
+testMultithreadedPoolGet (int port, int poll_flag)
+{
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ port, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ start_timer ();
+ join_gets (do_gets (port));
+ stop (poll_flag ? "thread pool with poll" : "thread pool with select");
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+static int
+testExternalGet (int port)
+{
+ struct MHD_Daemon *d;
+ pid_t pid;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ struct timeval tv;
+ MHD_UNSIGNED_LONG_LONG tt;
+ int tret;
+
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ start_timer ();
+ pid = do_gets (port);
+ while (0 == waitpid (pid, NULL, WNOHANG))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tret = MHD_get_timeout (d, &tt);
+ if (MHD_YES != tret) tt = 1;
+ tv.tv_sec = tt / 1000;
+ tv.tv_usec = 1000 * (tt % 1000);
+ if (-1 == select (max + 1, &rs, &ws, &es, &tv))
+ {
+ if (EINTR == errno)
+ continue;
+ fprintf (stderr,
+ "select failed: %s\n",
+ strerror (errno));
+ break;
+ }
+ MHD_run (d);
+ }
+ stop ("external select");
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+ int port = 1081;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ response = MHD_create_response_from_buffer (strlen ("/hello_world"),
+ "/hello_world",
+ MHD_RESPMEM_MUST_COPY);
+ errorCount += testInternalGet (port++, 0);
+ errorCount += testMultithreadedGet (port++, 0);
+ errorCount += testMultithreadedPoolGet (port++, 0);
+ errorCount += testExternalGet (port++);
+#ifndef WINDOWS
+ errorCount += testInternalGet (port++, MHD_USE_POLL);
+ errorCount += testMultithreadedGet (port++, MHD_USE_POLL);
+ errorCount += testMultithreadedPoolGet (port++, MHD_USE_POLL);
+#endif
+#if EPOLL_SUPPORT
+ errorCount += testInternalGet (port++, MHD_USE_EPOLL_LINUX_ONLY);
+ errorCount += testMultithreadedPoolGet (port++, MHD_USE_EPOLL_LINUX_ONLY);
+#endif
+ MHD_destroy_response (response);
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_callback.c b/src/testcurl/test_callback.c
new file mode 100644
index 0000000..83233e6
--- /dev/null
+++ b/src/testcurl/test_callback.c
@@ -0,0 +1,189 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009, 2011 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_callback.c
+ * @brief Testcase for MHD not calling the callback too often
+ * @author Jan Seeger
+ * @author Christian Grothoff
+ */
+
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+
+struct callback_closure {
+ unsigned int called;
+};
+
+
+static ssize_t
+called_twice(void *cls, uint64_t pos, char *buf, size_t max)
+{
+ struct callback_closure *cls2 = cls;
+
+ if (cls2->called == 0)
+ {
+ memset(buf, 0, max);
+ strcat(buf, "test");
+ cls2->called = 1;
+ return strlen(buf);
+ }
+ if (cls2->called == 1)
+ {
+ cls2->called = 2;
+ return MHD_CONTENT_READER_END_OF_STREAM;
+ }
+ fprintf(stderr,
+ "Handler called after returning END_OF_STREAM!\n");
+ return MHD_CONTENT_READER_END_WITH_ERROR;
+}
+
+
+static int
+callback(void *cls, struct MHD_Connection *connection, const char *url,
+ const char *method, const char *version, const char *upload_data,
+ size_t *upload_data_size, void **con_cls) {
+ struct callback_closure *cbc = calloc(1, sizeof(struct callback_closure));
+ struct MHD_Response *r;
+
+ r = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024,
+ &called_twice, cbc,
+ &free);
+ MHD_queue_response(connection, 200, r);
+ MHD_destroy_response(r);
+ return MHD_YES;
+}
+
+
+static size_t
+discard_buffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ return size * nmemb;
+}
+
+
+int main(int argc, char **argv)
+{
+ struct MHD_Daemon *d;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ CURL *c;
+ CURLM *multi;
+ CURLMcode mret;
+ struct CURLMsg *msg;
+ int running;
+ struct timeval tv;
+ int extra;
+
+ d = MHD_start_daemon(0,
+ 8000,
+ NULL,
+ NULL,
+ callback,
+ NULL,
+ MHD_OPTION_END);
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:8000/");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &discard_buffer);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ extra = 10;
+ while ( (c != NULL) || (--extra > 0) )
+ {
+ max = MHD_INVALID_SOCKET;
+ FD_ZERO(&ws);
+ FD_ZERO(&rs);
+ FD_ZERO(&es);
+ curl_multi_perform (multi, &running);
+ if (NULL != multi)
+ {
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 3;
+ }
+ }
+ if (MHD_YES !=
+ MHD_get_fdset(d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select(max + 1, &rs, &ws, &es, &tv);
+ if (NULL != multi)
+ {
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ }
+ MHD_run(d);
+ }
+ MHD_stop_daemon(d);
+ return 0;
+}
diff --git a/src/testcurl/test_concurrent_stop.c b/src/testcurl/test_concurrent_stop.c
new file mode 100644
index 0000000..60cc98d
--- /dev/null
+++ b/src/testcurl/test_concurrent_stop.c
@@ -0,0 +1,228 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009, 2011, 2015 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_concurrent_stop.c
+ * @brief test stopping server while concurrent GETs are ongoing
+ * @author Christian Grothoff
+ */
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "gauger.h"
+
+#ifdef CPU_COUNT
+#undef CPU_COUNT
+#endif
+#define CPU_COUNT 40
+
+
+/**
+ * How many rounds of operations do we do for each
+ * test (total number of requests will be ROUNDS * PAR).
+ */
+#define ROUNDS 50000
+
+/**
+ * How many requests do we do in parallel?
+ */
+#define PAR CPU_COUNT
+
+/**
+ * Do we use HTTP 1.1?
+ */
+static int oneone;
+
+/**
+ * Response to return (re-used).
+ */
+static struct MHD_Response *response;
+
+
+static size_t
+copyBuffer (void *ptr,
+ size_t size, size_t nmemb,
+ void *ctx)
+{
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_OK,
+ response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static pid_t
+do_gets (int port)
+{
+ pid_t ret;
+ CURL *c;
+ CURLcode errornum;
+ unsigned int i;
+ unsigned int j;
+ pid_t par[PAR];
+ char url[64];
+
+ sprintf(url, "http://127.0.0.1:%d/hello_world", port);
+
+ ret = fork ();
+ if (ret == -1) abort ();
+ if (ret != 0)
+ return ret;
+ for (j=0;j<PAR;j++)
+ {
+ par[j] = fork ();
+ if (par[j] == 0)
+ {
+ for (i=0;i<ROUNDS;i++)
+ {
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ curl_easy_cleanup (c);
+ _exit (1);
+ }
+ curl_easy_cleanup (c);
+ }
+ _exit (0);
+ }
+ }
+ for (j=0;j<PAR;j++)
+ waitpid (par[j], NULL, 0);
+ _exit (0);
+}
+
+
+static void
+join_gets (pid_t pid)
+{
+ int status;
+
+ status = 1;
+ waitpid (pid, &status, 0);
+ if (0 != status)
+ abort ();
+}
+
+
+static int
+testMultithreadedGet (int port, int poll_flag)
+{
+ struct MHD_Daemon *d;
+ pid_t p;
+
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
+ port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ p = do_gets (port);
+ sleep (1);
+ MHD_stop_daemon (d);
+ join_gets (p);
+ return 0;
+}
+
+
+static int
+testMultithreadedPoolGet (int port, int poll_flag)
+{
+ struct MHD_Daemon *d;
+ pid_t p;
+
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ port,
+ NULL, NULL,
+ &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ p = do_gets (port);
+ sleep (1);
+ MHD_stop_daemon (d);
+ join_gets (p);
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+ int port = 1081;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ response = MHD_create_response_from_buffer (strlen ("/hello_world"),
+ "/hello_world",
+ MHD_RESPMEM_MUST_COPY);
+ errorCount += testMultithreadedGet (port++, 0);
+ errorCount += testMultithreadedPoolGet (port++, 0);
+ MHD_destroy_response (response);
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_digestauth.c b/src/testcurl/test_digestauth.c
new file mode 100644
index 0000000..255e086
--- /dev/null
+++ b/src/testcurl/test_digestauth.c
@@ -0,0 +1,247 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2010 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_digestauth.c
+ * @brief Testcase for libmicrohttpd Digest Auth
+ * @author Amr Ali
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_GCRYPT_H
+#include <gcrypt.h>
+#endif
+
+#ifndef WINDOWS
+#include <sys/socket.h>
+#include <unistd.h>
+#else
+#include <wincrypt.h>
+#endif
+
+#define PAGE "<html><head><title>libmicrohttpd demo</title></head><body>Access granted</body></html>"
+
+#define DENIED "<html><head><title>libmicrohttpd demo</title></head><body>Access denied</body></html>"
+
+#define MY_OPAQUE "11733b200778ce33060f31c9af70a870ba96ddd4"
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ struct MHD_Response *response;
+ char *username;
+ const char *password = "testpass";
+ const char *realm = "test@example.com";
+ int ret;
+
+ username = MHD_digest_auth_get_username(connection);
+ if ( (username == NULL) ||
+ (0 != strcmp (username, "testuser")) )
+ {
+ response = MHD_create_response_from_buffer(strlen (DENIED),
+ DENIED,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_auth_fail_response(connection, realm,
+ MY_OPAQUE,
+ response,
+ MHD_NO);
+ MHD_destroy_response(response);
+ return ret;
+ }
+ ret = MHD_digest_auth_check(connection, realm,
+ username,
+ password,
+ 300);
+ free(username);
+ if ( (ret == MHD_INVALID_NONCE) ||
+ (ret == MHD_NO) )
+ {
+ response = MHD_create_response_from_buffer(strlen (DENIED),
+ DENIED,
+ MHD_RESPMEM_PERSISTENT);
+ if (NULL == response)
+ return MHD_NO;
+ ret = MHD_queue_auth_fail_response(connection, realm,
+ MY_OPAQUE,
+ response,
+ (ret == MHD_INVALID_NONCE) ? MHD_YES : MHD_NO);
+ MHD_destroy_response(response);
+ return ret;
+ }
+ response = MHD_create_response_from_buffer(strlen(PAGE), PAGE,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+ MHD_destroy_response(response);
+ return ret;
+}
+
+
+static int
+testDigestAuth ()
+{
+ int fd;
+ CURL *c;
+ CURLcode errornum;
+ struct MHD_Daemon *d;
+ struct CBC cbc;
+ size_t len;
+ size_t off = 0;
+ char buf[2048];
+ char rnd[8];
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+#ifndef WINDOWS
+ fd = open("/dev/urandom", O_RDONLY);
+ if (-1 == fd)
+ {
+ fprintf(stderr, "Failed to open `%s': %s\n",
+ "/dev/urandom",
+ strerror(errno));
+ return 1;
+ }
+ while (off < 8)
+ {
+ len = read(fd, rnd, 8);
+ if (len == -1)
+ {
+ fprintf(stderr, "Failed to read `%s': %s\n",
+ "/dev/urandom",
+ strerror(errno));
+ (void) close(fd);
+ return 1;
+ }
+ off += len;
+ }
+ (void) close(fd);
+#else
+ {
+ HCRYPTPROV cc;
+ BOOL b;
+ b = CryptAcquireContext (&cc, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ if (b == 0)
+ {
+ fprintf (stderr, "Failed to acquire crypto provider context: %lu\n",
+ GetLastError ());
+ return 1;
+ }
+ b = CryptGenRandom (cc, 8, rnd);
+ if (b == 0)
+ {
+ fprintf (stderr, "Failed to generate 8 random bytes: %lu\n",
+ GetLastError ());
+ }
+ CryptReleaseContext (cc, 0);
+ if (b == 0)
+ return 1;
+ }
+#endif
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1337, NULL, NULL, &ahc_echo, PAGE,
+ MHD_OPTION_DIGEST_AUTH_RANDOM, sizeof (rnd), rnd,
+ MHD_OPTION_NONCE_NC_SIZE, 300,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1337/");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
+ curl_easy_setopt (c, CURLOPT_USERPWD, "testuser:testpass");
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen (PAGE))
+ return 4;
+ if (0 != strncmp (PAGE, cbc.buf, strlen (PAGE)))
+ return 8;
+ return 0;
+}
+
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+#ifdef HAVE_GCRYPT_H
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+#endif
+if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testDigestAuth ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_digestauth_with_arguments.c b/src/testcurl/test_digestauth_with_arguments.c
new file mode 100644
index 0000000..51868ab
--- /dev/null
+++ b/src/testcurl/test_digestauth_with_arguments.c
@@ -0,0 +1,245 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2010, 2012 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_digestauth_with_arguments.c
+ * @brief Testcase for libmicrohttpd Digest Auth with arguments
+ * @author Amr Ali
+ */
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_GCRYPT_H
+#include <gcrypt.h>
+#endif
+
+#ifndef WINDOWS
+#include <sys/socket.h>
+#include <unistd.h>
+#else
+#include <wincrypt.h>
+#endif
+
+#define PAGE "<html><head><title>libmicrohttpd demo</title></head><body>Access granted</body></html>"
+
+#define DENIED "<html><head><title>libmicrohttpd demo</title></head><body>Access denied</body></html>"
+
+#define MY_OPAQUE "11733b200778ce33060f31c9af70a870ba96ddd4"
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ struct MHD_Response *response;
+ char *username;
+ const char *password = "testpass";
+ const char *realm = "test@example.com";
+ int ret;
+
+ username = MHD_digest_auth_get_username(connection);
+ if ( (username == NULL) ||
+ (0 != strcmp (username, "testuser")) )
+ {
+ response = MHD_create_response_from_buffer(strlen (DENIED),
+ DENIED,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_auth_fail_response(connection, realm,
+ MY_OPAQUE,
+ response,
+ MHD_NO);
+ MHD_destroy_response(response);
+ return ret;
+ }
+ ret = MHD_digest_auth_check(connection, realm,
+ username,
+ password,
+ 300);
+ free(username);
+ if ( (ret == MHD_INVALID_NONCE) ||
+ (ret == MHD_NO) )
+ {
+ response = MHD_create_response_from_buffer(strlen (DENIED),
+ DENIED,
+ MHD_RESPMEM_PERSISTENT);
+ if (NULL == response)
+ return MHD_NO;
+ ret = MHD_queue_auth_fail_response(connection, realm,
+ MY_OPAQUE,
+ response,
+ (ret == MHD_INVALID_NONCE) ? MHD_YES : MHD_NO);
+ MHD_destroy_response(response);
+ return ret;
+ }
+ response = MHD_create_response_from_buffer(strlen(PAGE), PAGE,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+ MHD_destroy_response(response);
+ return ret;
+}
+
+
+static int
+testDigestAuth ()
+{
+ int fd;
+ CURL *c;
+ CURLcode errornum;
+ struct MHD_Daemon *d;
+ struct CBC cbc;
+ size_t len;
+ size_t off = 0;
+ char buf[2048];
+ char rnd[8];
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+#ifndef WINDOWS
+ fd = open("/dev/urandom", O_RDONLY);
+ if (-1 == fd)
+ {
+ fprintf(stderr, "Failed to open `%s': %s\n",
+ "/dev/urandom",
+ strerror(errno));
+ return 1;
+ }
+ while (off < 8)
+ {
+ len = read(fd, rnd, 8);
+ if (len == -1)
+ {
+ fprintf(stderr, "Failed to read `%s': %s\n",
+ "/dev/urandom",
+ strerror(errno));
+ (void) close(fd);
+ return 1;
+ }
+ off += len;
+ }
+ (void) close(fd);
+#else
+ {
+ HCRYPTPROV cc;
+ BOOL b;
+ b = CryptAcquireContext (&cc, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ if (b == 0)
+ {
+ fprintf (stderr, "Failed to acquire crypto provider context: %lu\n",
+ GetLastError ());
+ return 1;
+ }
+ b = CryptGenRandom (cc, 8, rnd);
+ if (b == 0)
+ {
+ fprintf (stderr, "Failed to generate 8 random bytes: %lu\n",
+ GetLastError ());
+ }
+ CryptReleaseContext (cc, 0);
+ if (b == 0)
+ return 1;
+ }
+#endif
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1337, NULL, NULL, &ahc_echo, PAGE,
+ MHD_OPTION_DIGEST_AUTH_RANDOM, sizeof (rnd), rnd,
+ MHD_OPTION_NONCE_NC_SIZE, 300,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1337/foo?key=value");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
+ curl_easy_setopt (c, CURLOPT_USERPWD, "testuser:testpass");
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen (PAGE))
+ return 4;
+ if (0 != strncmp (PAGE, cbc.buf, strlen (PAGE)))
+ return 8;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+#ifdef HAVE_GCRYPT_H
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+#endif
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testDigestAuth ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_get.c b/src/testcurl/test_get.c
new file mode 100644
index 0000000..e4c531d
--- /dev/null
+++ b/src/testcurl/test_get.c
@@ -0,0 +1,640 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009, 2011 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_get.c
+ * @brief Testcase for libmicrohttpd GET operations
+ * TODO: test parsing of query
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include "platform_interface.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif /* !WIN32_LEAN_AND_MEAN */
+#include <windows.h>
+#endif
+
+#ifndef WINDOWS
+#include <unistd.h>
+#include <sys/socket.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static int
+testInternalGet (int poll_flag)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+
+static int
+testMultithreadedGet (int poll_flag)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
+ 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+
+static int
+testMultithreadedPoolGet (int poll_flag)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ 1081, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+
+static int
+testExternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+static int
+testUnknownPortGet (int poll_flag)
+{
+ struct MHD_Daemon *d;
+ const union MHD_DaemonInfo *di;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(addr);
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ 1, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_SOCK_ADDR, &addr,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 32768;
+
+ di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
+ if (di == NULL)
+ return 65536;
+
+ if (0 != getsockname(di->listen_fd, (struct sockaddr *) &addr, &addr_len))
+ return 131072;
+
+ if (addr.sin_family != AF_INET)
+ return 26214;
+
+ snprintf(buf, sizeof(buf), "http://127.0.0.1:%hu/hello_world",
+ ntohs(addr.sin_port));
+
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, buf);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 524288;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 1048576;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 2097152;
+ return 0;
+}
+
+
+static int
+testStopRace (int poll_flag)
+{
+ struct sockaddr_in sin;
+ MHD_socket fd;
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
+ 1081, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_CONNECTION_TIMEOUT, 5, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+
+ fd = socket (PF_INET, SOCK_STREAM, 0);
+ if (fd == MHD_INVALID_SOCKET)
+ {
+ fprintf(stderr, "socket error\n");
+ return 256;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(1081);
+ sin.sin_addr.s_addr = htonl(0x7f000001);
+
+ if (connect (fd, (struct sockaddr *)(&sin), sizeof(sin)) < 0)
+ {
+ fprintf(stderr, "connect error\n");
+ MHD_socket_close_ (fd);
+ return 512;
+ }
+
+ /* printf("Waiting\n"); */
+ /* Let the thread get going. */
+ usleep(500000);
+
+ /* printf("Stopping daemon\n"); */
+ MHD_stop_daemon (d);
+
+ MHD_socket_close_ (fd);
+
+ /* printf("good\n"); */
+ return 0;
+}
+
+
+static int
+ahc_empty (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp ("GET", method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ response = MHD_create_response_from_buffer (0,
+ NULL,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static int
+curlExcessFound(CURL *c, curl_infotype type, char *data, size_t size, void *cls)
+{
+ static const char *excess_found = "Excess found";
+ const size_t str_size = strlen (excess_found);
+
+ if (CURLINFO_TEXT == type
+ && size >= str_size
+ && 0 == strncmp(excess_found, data, str_size))
+ *(int *)cls = 1;
+ return 0;
+}
+
+
+static int
+testEmptyGet (int poll_flag)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ int excess_found = 0;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ 11081, NULL, NULL, &ahc_empty, NULL, MHD_OPTION_END);
+ if (d == NULL)
+ return 4194304;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, &curlExcessFound);
+ curl_easy_setopt (c, CURLOPT_DEBUGDATA, &excess_found);
+ curl_easy_setopt (c, CURLOPT_VERBOSE, 1);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 8388608;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != 0)
+ return 16777216;
+ if (excess_found)
+ return 33554432;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testInternalGet (0);
+ errorCount += testMultithreadedGet (0);
+ errorCount += testMultithreadedPoolGet (0);
+ errorCount += testUnknownPortGet (0);
+ errorCount += testStopRace (0);
+ errorCount += testExternalGet ();
+ errorCount += testEmptyGet (0);
+ if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_POLL))
+ {
+ errorCount += testInternalGet(MHD_USE_POLL);
+ errorCount += testMultithreadedGet(MHD_USE_POLL);
+ errorCount += testMultithreadedPoolGet(MHD_USE_POLL);
+ errorCount += testUnknownPortGet(MHD_USE_POLL);
+ errorCount += testStopRace(MHD_USE_POLL);
+ errorCount += testEmptyGet(MHD_USE_POLL);
+ }
+ if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_EPOLL))
+ {
+ errorCount += testInternalGet(MHD_USE_EPOLL_LINUX_ONLY);
+ errorCount += testMultithreadedPoolGet(MHD_USE_EPOLL_LINUX_ONLY);
+ errorCount += testUnknownPortGet(MHD_USE_EPOLL_LINUX_ONLY);
+ errorCount += testEmptyGet(MHD_USE_EPOLL_LINUX_ONLY);
+ }
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_get_chunked.c b/src/testcurl/test_get_chunked.c
new file mode 100644
index 0000000..3b8bf39
--- /dev/null
+++ b/src/testcurl/test_get_chunked.c
@@ -0,0 +1,414 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_get_chunked.c
+ * @brief Testcase for libmicrohttpd GET operations with chunked content encoding
+ * TODO:
+ * - how to test that chunking was actually used?
+ * - use CURLOPT_HEADERFUNCTION to validate
+ * footer was sent
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+/**
+ * MHD content reader callback that returns
+ * data in chunks.
+ */
+static ssize_t
+crc (void *cls, uint64_t pos, char *buf, size_t max)
+{
+ struct MHD_Response **responseptr = cls;
+
+ if (pos == 128 * 10)
+ {
+ MHD_add_response_header (*responseptr, "Footer", "working");
+ return MHD_CONTENT_READER_END_OF_STREAM;
+ }
+ if (max < 128)
+ abort (); /* should not happen in this testcase... */
+ memset (buf, 'A' + (pos / 128), 128);
+ return 128;
+}
+
+/**
+ * Dummy function that does nothing.
+ */
+static void
+crcf (void *ptr)
+{
+ free (ptr);
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size, void **ptr)
+{
+ static int aptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ struct MHD_Response **responseptr;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&aptr != *ptr)
+ {
+ /* do never respond on first call */
+ *ptr = &aptr;
+ return MHD_YES;
+ }
+ responseptr = malloc (sizeof (struct MHD_Response *));
+ if (responseptr == NULL)
+ return MHD_NO;
+ response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
+ 1024,
+ &crc, responseptr, &crcf);
+ *responseptr = response;
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+static int
+validate (struct CBC cbc, int ebase)
+{
+ int i;
+ char buf[128];
+
+ if (cbc.pos != 128 * 10)
+ return ebase;
+
+ for (i = 0; i < 10; i++)
+ {
+ memset (buf, 'A' + i, 128);
+ if (0 != memcmp (buf, &cbc.buf[i * 128], 128))
+ {
+ fprintf (stderr,
+ "Got `%.*s'\nWant `%.*s'\n",
+ 128, buf, 128, &cbc.buf[i * 128]);
+ return ebase * 2;
+ }
+ }
+ return 0;
+}
+
+static int
+testInternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return validate (cbc, 4);
+}
+
+static int
+testMultithreadedGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return validate (cbc, 64);
+}
+
+static int
+testMultithreadedPoolGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return validate (cbc, 64);
+}
+
+static int
+testExternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ return validate (cbc, 8192);
+}
+
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testInternalGet ();
+ errorCount += testMultithreadedGet ();
+ errorCount += testMultithreadedPoolGet ();
+ errorCount += testExternalGet ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_get_response_cleanup.c b/src/testcurl/test_get_response_cleanup.c
new file mode 100644
index 0000000..f881746
--- /dev/null
+++ b/src/testcurl/test_get_response_cleanup.c
@@ -0,0 +1,302 @@
+/* DO NOT CHANGE THIS LINE */
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_get_response_cleanup.c
+ * @brief Testcase for libmicrohttpd response cleanup
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#ifndef WINDOWS
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif /* !WIN32_LEAN_AND_MEAN */
+#include <windows.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+#define TESTSTR "/* DO NOT CHANGE THIS LINE */"
+
+static int oneone;
+
+static int ok;
+
+
+static pid_t
+fork_curl (const char *url)
+{
+ pid_t ret;
+
+ ret = fork();
+ if (ret != 0)
+ return ret;
+ execlp ("curl", "curl", "-s", "-N", "-o", "/dev/null", "-GET", url, NULL);
+ fprintf (stderr,
+ "Failed to exec curl: %s\n",
+ strerror (errno));
+ _exit (-1);
+}
+
+static void
+kill_curl (pid_t pid)
+{
+ int status;
+
+ //fprintf (stderr, "Killing curl\n");
+ kill (pid, SIGTERM);
+ waitpid (pid, &status, 0);
+}
+
+
+static ssize_t
+push_callback (void *cls, uint64_t pos, char *buf, size_t max)
+{
+ if (max == 0)
+ return 0;
+ buf[0] = 'd';
+ return 1;
+}
+
+static void
+push_free_callback (void *cls)
+{
+ int *ok = cls;
+
+ //fprintf (stderr, "Cleanup callback called!\n");
+ *ok = 0;
+}
+
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ //fprintf (stderr, "In CB: %s!\n", method);
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
+ 32 * 1024,
+ &push_callback,
+ &ok,
+ &push_free_callback);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static int
+testInternalGet ()
+{
+ struct MHD_Daemon *d;
+ pid_t curl;
+
+ ok = 1;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ curl = fork_curl ("http://127.0.0.1:11080/");
+ sleep (1);
+ kill_curl (curl);
+ sleep (1);
+ // fprintf (stderr, "Stopping daemon!\n");
+ MHD_stop_daemon (d);
+ if (ok != 0)
+ return 2;
+ return 0;
+}
+
+static int
+testMultithreadedGet ()
+{
+ struct MHD_Daemon *d;
+ pid_t curl;
+
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 2,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ ok = 1;
+ //fprintf (stderr, "Forking cURL!\n");
+ curl = fork_curl ("http://127.0.0.1:1081/");
+ sleep (1);
+ kill_curl (curl);
+ sleep (1);
+ curl = fork_curl ("http://127.0.0.1:1081/");
+ sleep (1);
+ if (ok != 0)
+ {
+ kill_curl (curl);
+ MHD_stop_daemon (d);
+ return 64;
+ }
+ kill_curl (curl);
+ sleep (1);
+ //fprintf (stderr, "Stopping daemon!\n");
+ MHD_stop_daemon (d);
+ if (ok != 0)
+ return 32;
+
+ return 0;
+}
+
+static int
+testMultithreadedPoolGet ()
+{
+ struct MHD_Daemon *d;
+ pid_t curl;
+
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 64;
+ ok = 1;
+ curl = fork_curl ("http://127.0.0.1:1081/");
+ sleep (1);
+ kill_curl (curl);
+ sleep (1);
+ //fprintf (stderr, "Stopping daemon!\n");
+ MHD_stop_daemon (d);
+ if (ok != 0)
+ return 128;
+ return 0;
+}
+
+static int
+testExternalGet ()
+{
+ struct MHD_Daemon *d;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ time_t start;
+ struct timeval tv;
+ pid_t curl;
+
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ curl = fork_curl ("http://127.0.0.1:1082/");
+
+ start = time (NULL);
+ while ((time (NULL) - start < 2))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ MHD_run (d);
+ }
+ kill_curl (curl);
+ start = time (NULL);
+ while ((time (NULL) - start < 2))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ MHD_run (d);
+ }
+ // fprintf (stderr, "Stopping daemon!\n");
+ MHD_stop_daemon (d);
+ if (ok != 0)
+ return 1024;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ errorCount += testInternalGet ();
+ errorCount += testMultithreadedGet ();
+ errorCount += testMultithreadedPoolGet ();
+ errorCount += testExternalGet ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_get_sendfile.c b/src/testcurl/test_get_sendfile.c
new file mode 100644
index 0000000..f0853b2
--- /dev/null
+++ b/src/testcurl/test_get_sendfile.c
@@ -0,0 +1,500 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_get_sendfile.c
+ * @brief Testcase for libmicrohttpd response from FD
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include "platform_interface.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifndef WINDOWS
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+#define TESTSTR "This is the content of the test file we are sending using sendfile (if available)"
+
+char *sourcefile;
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+ int fd;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ fd = open (sourcefile, O_RDONLY);
+ if (fd == -1)
+ {
+ fprintf (stderr, "Failed to open `%s': %s\n",
+ sourcefile,
+ MHD_strerror_ (errno));
+ exit (1);
+ }
+ response = MHD_create_response_from_fd (strlen (TESTSTR), fd);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static int
+testInternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen (TESTSTR))
+ return 4;
+ if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
+ return 8;
+ return 0;
+}
+
+static int
+testMultithreadedGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen (TESTSTR))
+ return 64;
+ if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
+ return 128;
+ return 0;
+}
+
+static int
+testMultithreadedPoolGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen (TESTSTR))
+ return 64;
+ if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
+ return 128;
+ return 0;
+}
+
+static int
+testExternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen (TESTSTR))
+ return 8192;
+ if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
+ return 16384;
+ return 0;
+}
+
+static int
+testUnknownPortGet ()
+{
+ struct MHD_Daemon *d;
+ const union MHD_DaemonInfo *di;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(addr);
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_SOCK_ADDR, &addr,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 32768;
+
+ di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
+ if (di == NULL)
+ return 65536;
+
+ if (0 != getsockname(di->listen_fd, (struct sockaddr *) &addr, &addr_len))
+ return 131072;
+
+ if (addr.sin_family != AF_INET)
+ return 26214;
+
+ snprintf(buf, sizeof(buf), "http://127.0.0.1:%hu/",
+ ntohs(addr.sin_port));
+
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, buf);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 524288;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen (TESTSTR))
+ return 1048576;
+ if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
+ return 2097152;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+ const char *tmp;
+ FILE *f;
+
+ if ( (NULL == (tmp = getenv ("TMPDIR"))) &&
+ (NULL == (tmp = getenv ("TMP"))) &&
+ (NULL == (tmp = getenv ("TEMP"))) )
+ tmp = "/tmp";
+ sourcefile = malloc (strlen (tmp) + 32);
+ sprintf (sourcefile,
+ "%s/%s",
+ tmp,
+ "test-mhd-sendfile");
+ f = fopen (sourcefile, "w");
+ if (NULL == f)
+ {
+ fprintf (stderr, "failed to write test file\n");
+ free (sourcefile);
+ return 1;
+ }
+ fwrite (TESTSTR, strlen (TESTSTR), 1, f);
+ fclose (f);
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testInternalGet ();
+ errorCount += testMultithreadedGet ();
+ errorCount += testMultithreadedPoolGet ();
+ errorCount += testExternalGet ();
+ errorCount += testUnknownPortGet ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ unlink (sourcefile);
+ free (sourcefile);
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_iplimit.c b/src/testcurl/test_iplimit.c
new file mode 100644
index 0000000..813fc8b
--- /dev/null
+++ b/src/testcurl/test_iplimit.c
@@ -0,0 +1,313 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_iplimit.c
+ * @brief Testcase for libmicrohttpd GET operations
+ * TODO: test parsing of query
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif /* !WIN32_LEAN_AND_MEAN */
+#include <windows.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+static int
+testMultithreadedGet ()
+{
+ struct MHD_Daemon *d;
+ char buf[2048];
+ int k;
+ unsigned int success;
+ unsigned int failure;
+
+ /* Test only valid for HTTP/1.1 (uses persistent connections) */
+ if (!oneone)
+ return 0;
+
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081, NULL, NULL,
+ &ahc_echo, "GET",
+ MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+
+ for (k = 0; k < 3; ++k)
+ {
+ struct CBC cbc[3];
+ CURL *cenv[3];
+ int i;
+
+ success = 0;
+ failure = 0;
+ for (i = 0; i < 3; ++i)
+ {
+ CURL *c;
+ CURLcode errornum;
+
+ cenv[i] = c = curl_easy_init ();
+ cbc[i].buf = buf;
+ cbc[i].size = 2048;
+ cbc[i].pos = 0;
+
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc[i]);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_FORBID_REUSE, 0L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+ errornum = curl_easy_perform (c);
+ if (CURLE_OK == errornum)
+ success++;
+ else
+ failure++;
+ }
+
+ /* Cleanup the environments */
+ for (i = 0; i < 3; ++i)
+ curl_easy_cleanup (cenv[i]);
+ if ( (2 != success) ||
+ (1 != failure) )
+ {
+ fprintf (stderr,
+ "Unexpected number of success (%u) or failure (%u)\n",
+ success,
+ failure);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+
+ sleep(2);
+
+ for (i = 0; i < 2; ++i)
+ {
+ if (cbc[i].pos != strlen ("/hello_world"))
+ {
+ MHD_stop_daemon (d);
+ return 64;
+ }
+ if (0 != strncmp ("/hello_world", cbc[i].buf, strlen ("/hello_world")))
+ {
+ MHD_stop_daemon (d);
+ return 128;
+ }
+ }
+ }
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+static int
+testMultithreadedPoolGet ()
+{
+ struct MHD_Daemon *d;
+ char buf[2048];
+ int k;
+
+ /* Test only valid for HTTP/1.1 (uses persistent connections) */
+ if (!oneone)
+ return 0;
+
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2,
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+
+ for (k = 0; k < 3; ++k)
+ {
+ struct CBC cbc[3];
+ CURL *cenv[3];
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ {
+ CURL *c;
+ CURLcode errornum;
+
+ cenv[i] = c = curl_easy_init ();
+ cbc[i].buf = buf;
+ cbc[i].size = 2048;
+ cbc[i].pos = 0;
+
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc[i]);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_FORBID_REUSE, 0L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+ errornum = curl_easy_perform (c);
+ if ( ( (CURLE_OK != errornum) && (i < 2) ) ||
+ ( (CURLE_OK == errornum) && (i == 2) ) )
+ {
+ int j;
+
+ /* First 2 should succeed */
+ if (i < 2)
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+
+ /* Last request should have failed */
+ else
+ fprintf (stderr,
+ "No error on IP address over limit\n");
+
+ for (j = 0; j < i; ++j)
+ curl_easy_cleanup (cenv[j]);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ }
+
+ /* Cleanup the environments */
+ for (i = 0; i < 3; ++i)
+ curl_easy_cleanup (cenv[i]);
+
+ sleep(2);
+
+ for (i = 0; i < 2; ++i)
+ {
+ if (cbc[i].pos != strlen ("/hello_world"))
+ {
+ MHD_stop_daemon (d);
+ return 64;
+ }
+ if (0 != strncmp ("/hello_world", cbc[i].buf, strlen ("/hello_world")))
+ {
+ MHD_stop_daemon (d);
+ return 128;
+ }
+ }
+
+
+ }
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount |= testMultithreadedGet ();
+ errorCount |= testMultithreadedPoolGet ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_large_put.c b/src/testcurl/test_large_put.c
new file mode 100644
index 0000000..ec0022e
--- /dev/null
+++ b/src/testcurl/test_large_put.c
@@ -0,0 +1,479 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2008 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_large_put.c
+ * @brief Testcase for libmicrohttpd PUT operations
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+static int oneone;
+
+/**
+ * Do not make this much larger since we will hit the
+ * MHD default buffer limit and the test code is not
+ * written for incremental upload processing...
+ * (larger values will likely cause MHD to generate
+ * an internal server error -- which would be avoided
+ * by writing the putBuffer method in a more general
+ * fashion).
+ */
+#define PUT_SIZE (256 * 1024)
+
+static char *put_buffer;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
+{
+ unsigned int *pos = ptr;
+ unsigned int wrt;
+
+ wrt = size * nmemb;
+ if (wrt > PUT_SIZE - (*pos))
+ wrt = PUT_SIZE - (*pos);
+ memcpy (stream, &put_buffer[*pos], wrt);
+ (*pos) += wrt;
+ return wrt;
+}
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ int *done = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp ("PUT", method))
+ return MHD_NO; /* unexpected method */
+ if ((*done) == 0)
+ {
+ if (*upload_data_size != PUT_SIZE)
+ {
+#if 0
+ fprintf (stderr,
+ "Waiting for more data (%u/%u)...\n",
+ *upload_data_size, PUT_SIZE);
+#endif
+ return MHD_YES; /* not yet ready */
+ }
+ if (0 == memcmp (upload_data, put_buffer, PUT_SIZE))
+ {
+ *upload_data_size = 0;
+ }
+ else
+ {
+ printf ("Invalid upload data!\n");
+ return MHD_NO;
+ }
+ *done = 1;
+ return MHD_YES;
+ }
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+static int
+testInternalPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+ char buf[2048];
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1080,
+ NULL, NULL, &ahc_echo, &done_flag,
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (1024*1024),
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+static int
+testMultithreadedPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+ char buf[2048];
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 1081,
+ NULL, NULL, &ahc_echo, &done_flag,
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (1024*1024),
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ {
+ fprintf (stderr, "Got invalid response `%.*s'\n", (int)cbc.pos, cbc.buf);
+ return 64;
+ }
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testMultithreadedPoolPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+ char buf[2048];
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081,
+ NULL, NULL, &ahc_echo, &done_flag,
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (1024*1024),
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ {
+ fprintf (stderr, "Got invalid response `%.*s'\n", (int)cbc.pos, cbc.buf);
+ return 64;
+ }
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testExternalPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ char buf[2048];
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ multi = NULL;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082,
+ NULL, NULL, &ahc_echo, &done_flag,
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+ (size_t) (PUT_SIZE * 4), MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ {
+ fprintf (stderr, "Got invalid response `%.*s'\n", (int)cbc.pos, cbc.buf);
+ return 8192;
+ }
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ put_buffer = malloc (PUT_SIZE);
+ if (NULL == put_buffer) return 1;
+ memset (put_buffer, 1, PUT_SIZE);
+ errorCount += testInternalPut ();
+ errorCount += testMultithreadedPut ();
+ errorCount += testMultithreadedPoolPut ();
+ errorCount += testExternalPut ();
+ free (put_buffer);
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_long_header.c b/src/testcurl/test_long_header.c
new file mode 100644
index 0000000..e1e024b
--- /dev/null
+++ b/src/testcurl/test_long_header.c
@@ -0,0 +1,253 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_long_header.c
+ * @brief Testcase for libmicrohttpd handling of very long headers
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+/**
+ * We will set the memory available per connection to
+ * half of this value, so the actual value does not have
+ * to be big at all...
+ */
+#define VERY_LONG (1024*10)
+
+static int oneone;
+
+static int
+apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
+{
+ return MHD_YES;
+}
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+static int
+testLongUrlGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ char *url;
+ long code;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
+ 1080,
+ &apc_all,
+ NULL,
+ &ahc_echo,
+ "GET",
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+ (size_t) (VERY_LONG / 2), MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ url = malloc (VERY_LONG);
+ if (url == NULL)
+ {
+ MHD_stop_daemon (d);
+ return 1;
+ }
+ memset (url, 'a', VERY_LONG);
+ url[VERY_LONG - 1] = '\0';
+ memcpy (url, "http://127.0.0.1:1080/", strlen ("http://127.0.0.1:1080/"));
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK == curl_easy_perform (c))
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ free (url);
+ return 2;
+ }
+ if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ free (url);
+ return 4;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ free (url);
+ if (code != MHD_HTTP_REQUEST_URI_TOO_LONG)
+ return 8;
+ return 0;
+}
+
+
+static int
+testLongHeaderGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ char *url;
+ long code;
+ struct curl_slist *header = NULL;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
+ 1080,
+ &apc_all,
+ NULL,
+ &ahc_echo,
+ "GET",
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+ (size_t) (VERY_LONG / 2), MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ url = malloc (VERY_LONG);
+ if (url == NULL)
+ {
+ MHD_stop_daemon (d);
+ return 16;
+ }
+ memset (url, 'a', VERY_LONG);
+ url[VERY_LONG - 1] = '\0';
+ url[VERY_LONG / 2] = ':';
+ url[VERY_LONG / 2 + 1] = ' ';
+ header = curl_slist_append (header, url);
+
+ curl_easy_setopt (c, CURLOPT_HTTPHEADER, header);
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK == curl_easy_perform (c))
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ curl_slist_free_all (header);
+ free (url);
+ return 32;
+ }
+ if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
+ {
+ curl_slist_free_all (header);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ free (url);
+ return 64;
+ }
+ curl_slist_free_all (header);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ free (url);
+ if (code != MHD_HTTP_REQUEST_ENTITY_TOO_LARGE)
+ return 128;
+ return 0;
+}
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testLongUrlGet ();
+ errorCount += testLongHeaderGet ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_options.c b/src/testcurl/test_options.c
new file mode 100644
index 0000000..4afe3d4
--- /dev/null
+++ b/src/testcurl/test_options.c
@@ -0,0 +1,124 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file mhds_get_test.c
+ * @brief Testcase for libmicrohttpd HTTPS GET operations
+ * @author Sagie Amir
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+
+#define MHD_E_MEM "Error: memory error\n"
+#define MHD_E_SERVER_INIT "Error: failed to start server\n"
+
+const int DEBUG_GNUTLS_LOG_LEVEL = 0;
+const char *test_file_name = "https_test_file";
+const char test_file_data[] = "Hello World\n";
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ return 0;
+}
+
+int
+test_wrap (char *test_name, int (*test) (void))
+{
+ int ret;
+
+ fprintf (stdout, "running test: %s ", test_name);
+ ret = test ();
+ if (ret == 0)
+ {
+ fprintf (stdout, "[pass]\n");
+ }
+ else
+ {
+ fprintf (stdout, "[fail]\n");
+ }
+ return ret;
+}
+
+
+/**
+ * Test daemon initialization with the MHD_OPTION_SOCK_ADDR option
+ */
+static int
+test_ip_addr_option ()
+{
+ struct MHD_Daemon *d;
+ struct sockaddr_in daemon_ip_addr;
+#if HAVE_INET6
+ struct sockaddr_in6 daemon_ip_addr6;
+#endif
+
+ memset (&daemon_ip_addr, 0, sizeof (struct sockaddr_in));
+ daemon_ip_addr.sin_family = AF_INET;
+ daemon_ip_addr.sin_port = htons (4233);
+ daemon_ip_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+#if HAVE_INET6
+ memset (&daemon_ip_addr6, 0, sizeof (struct sockaddr_in6));
+ daemon_ip_addr6.sin6_family = AF_INET6;
+ daemon_ip_addr6.sin6_port = htons (4233);
+ daemon_ip_addr6.sin6_addr = in6addr_loopback;
+#endif
+
+ d = MHD_start_daemon (MHD_USE_DEBUG, 4233,
+ NULL, NULL, &ahc_echo, NULL, MHD_OPTION_SOCK_ADDR,
+ &daemon_ip_addr, MHD_OPTION_END);
+
+ if (d == 0)
+ return -1;
+
+ MHD_stop_daemon (d);
+
+#if HAVE_INET6
+ d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_IPv6, 4233,
+ NULL, NULL, &ahc_echo, NULL, MHD_OPTION_SOCK_ADDR,
+ &daemon_ip_addr6, MHD_OPTION_END);
+
+ if (d == 0)
+ return -1;
+
+ MHD_stop_daemon (d);
+#endif
+
+ return 0;
+}
+
+/* setup a temporary transfer test file */
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ errorCount += test_wrap ("ip addr option", &test_ip_addr_option);
+
+ return errorCount != 0;
+}
diff --git a/src/testcurl/test_parse_cookies.c b/src/testcurl/test_parse_cookies.c
new file mode 100644
index 0000000..7d70867
--- /dev/null
+++ b/src/testcurl/test_parse_cookies.c
@@ -0,0 +1,250 @@
+
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_parse_cookies.c
+ * @brief Testcase for HTTP cookie parsing
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+ const char *hdr;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ ret = 0;
+
+ hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name1");
+ if ((hdr == NULL) || (0 != strcmp (hdr, "var1")))
+ abort ();
+ hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name2");
+ if ((hdr == NULL) || (0 != strcmp (hdr, "var2")))
+ abort ();
+ hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name3");
+ if ((hdr == NULL) || (0 != strcmp (hdr, "")))
+ abort ();
+ hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name4");
+ if ((hdr == NULL) || (0 != strcmp (hdr, "var4 with spaces")))
+ abort ();
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+static int
+testExternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:21080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ /* note that the string below intentionally uses the
+ various ways cookies can be specified to exercise the
+ parser! Do not change! */
+ curl_easy_setopt (c, CURLOPT_COOKIE,
+ "name1=var1; name2=var2,name3 ;name4=\"var4 with spaces\";");
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testExternalGet ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_post.c b/src/testcurl/test_post.c
new file mode 100644
index 0000000..49bf30a
--- /dev/null
+++ b/src/testcurl/test_post.c
@@ -0,0 +1,654 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_post.c
+ * @brief Testcase for libmicrohttpd POST operations using URL-encoding
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif /* !WIN32_LEAN_AND_MEAN */
+#include <windows.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+#define POST_DATA "name=daniel&project=curl"
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+
+static void
+completed_cb (void *cls,
+ struct MHD_Connection *connection,
+ void **con_cls,
+ enum MHD_RequestTerminationCode toe)
+{
+ struct MHD_PostProcessor *pp = *con_cls;
+
+ if (NULL != pp)
+ MHD_destroy_post_processor (pp);
+ *con_cls = NULL;
+}
+
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+
+/**
+ * Note that this post_iterator is not perfect
+ * in that it fails to support incremental processing.
+ * (to be fixed in the future)
+ */
+static int
+post_iterator (void *cls,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *filename,
+ const char *content_type,
+ const char *transfer_encoding,
+ const char *value, uint64_t off, size_t size)
+{
+ int *eok = cls;
+
+ if ((0 == strcmp (key, "name")) &&
+ (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size)))
+ (*eok) |= 1;
+ if ((0 == strcmp (key, "project")) &&
+ (size == strlen ("curl")) && (0 == strncmp (value, "curl", size)))
+ (*eok) |= 2;
+ return MHD_YES;
+}
+
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int eok;
+ struct MHD_Response *response;
+ struct MHD_PostProcessor *pp;
+ int ret;
+
+ if (0 != strcmp ("POST", method))
+ {
+ printf ("METHOD: %s\n", method);
+ return MHD_NO; /* unexpected method */
+ }
+ pp = *unused;
+ if (pp == NULL)
+ {
+ eok = 0;
+ pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
+ *unused = pp;
+ }
+ MHD_post_process (pp, upload_data, *upload_data_size);
+ if ((eok == 3) && (0 == *upload_data_size))
+ {
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ MHD_destroy_post_processor (pp);
+ *unused = NULL;
+ return ret;
+ }
+ *upload_data_size = 0;
+ return MHD_YES;
+}
+
+
+static int
+testInternalPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1080, NULL, NULL, &ahc_echo, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
+ curl_easy_setopt (c, CURLOPT_POST, 1L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+static int
+testMultithreadedPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
+ curl_easy_setopt (c, CURLOPT_POST, 1L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testMultithreadedPoolPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, NULL,
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
+ MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
+ curl_easy_setopt (c, CURLOPT_POST, 1L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testExternalPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082, NULL, NULL, &ahc_echo, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
+ curl_easy_setopt (c, CURLOPT_POST, 1L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+static int
+ahc_cancel (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp ("POST", method))
+ {
+ fprintf (stderr,
+ "Unexpected method `%s'\n", method);
+ return MHD_NO;
+ }
+
+ if (*unused == NULL)
+ {
+ *unused = "wibble";
+ /* We don't want the body. Send a 500. */
+ response = MHD_create_response_from_buffer (0, NULL,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response(connection, 500, response);
+ if (ret != MHD_YES)
+ fprintf(stderr, "Failed to queue response\n");
+ MHD_destroy_response(response);
+ return ret;
+ }
+ else
+ {
+ fprintf(stderr,
+ "In ahc_cancel again. This should not happen.\n");
+ return MHD_NO;
+ }
+}
+
+struct CRBC
+{
+ const char *buffer;
+ size_t size;
+ size_t pos;
+};
+
+
+static size_t
+readBuffer(void *p, size_t size, size_t nmemb, void *opaque)
+{
+ struct CRBC *data = opaque;
+ size_t required = size * nmemb;
+ size_t left = data->size - data->pos;
+
+ if (required > left)
+ required = left;
+
+ memcpy(p, data->buffer + data->pos, required);
+ data->pos += required;
+
+ return required/size;
+}
+
+
+static size_t
+slowReadBuffer(void *p, size_t size, size_t nmemb, void *opaque)
+{
+ sleep(1);
+ return readBuffer(p, size, nmemb, opaque);
+}
+
+
+#define FLAG_EXPECT_CONTINUE 1
+#define FLAG_CHUNKED 2
+#define FLAG_FORM_DATA 4
+#define FLAG_SLOW_READ 8
+#define FLAG_COUNT 16
+
+
+static int
+testMultithreadedPostCancelPart(int flags)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ struct curl_slist *headers = NULL;
+ long response_code;
+ CURLcode cc;
+ int result = 0;
+ struct CRBC crbc;
+
+ /* Don't test features that aren't available with HTTP/1.0 in
+ * HTTP/1.0 mode. */
+ if (!oneone && (flags & (FLAG_EXPECT_CONTINUE | FLAG_CHUNKED)))
+ return 0;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_cancel, NULL,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 32768;
+
+ crbc.buffer = "Test content";
+ crbc.size = strlen(crbc.buffer);
+ crbc.pos = 0;
+
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, (flags & FLAG_SLOW_READ) ? &slowReadBuffer : &readBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &crbc);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDS, NULL);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, crbc.size);
+ curl_easy_setopt (c, CURLOPT_POST, 1L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+ if (flags & FLAG_CHUNKED)
+ headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
+ if (!(flags & FLAG_FORM_DATA))
+ headers = curl_slist_append(headers, "Content-Type: application/octet-stream");
+ if (flags & FLAG_EXPECT_CONTINUE)
+ headers = curl_slist_append(headers, "Expect: 100-Continue");
+ curl_easy_setopt(c, CURLOPT_HTTPHEADER, headers);
+
+ if (CURLE_HTTP_RETURNED_ERROR != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "flibbet curl_easy_perform didn't fail as expected: `%s' %d\n",
+ curl_easy_strerror (errornum), errornum);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ curl_slist_free_all(headers);
+ return 65536;
+ }
+
+ if (CURLE_OK != (cc = curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE, &response_code)))
+ {
+ fprintf(stderr, "curl_easy_getinfo failed: '%s'\n", curl_easy_strerror(errornum));
+ result = 65536;
+ }
+
+ if (!result && (response_code != 500))
+ {
+ fprintf(stderr, "Unexpected response code: %ld\n", response_code);
+ result = 131072;
+ }
+
+ if (!result && (cbc.pos != 0))
+ result = 262144;
+
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ curl_slist_free_all(headers);
+ return result;
+}
+
+
+static int
+testMultithreadedPostCancel()
+{
+ int result = 0;
+ int flags;
+ for(flags = 0; flags < FLAG_COUNT; ++flags)
+ result |= testMultithreadedPostCancelPart(flags);
+ return result;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testMultithreadedPostCancel ();
+ errorCount += testInternalPost ();
+ errorCount += testMultithreadedPost ();
+ errorCount += testMultithreadedPoolPost ();
+ errorCount += testExternalPost ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_post_loop.c b/src/testcurl/test_post_loop.c
new file mode 100644
index 0000000..fe8d25c
--- /dev/null
+++ b/src/testcurl/test_post_loop.c
@@ -0,0 +1,531 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_post_loop.c
+ * @brief Testcase for libmicrohttpd POST operations using URL-encoding
+ * @author Christian Grothoff (inspired by bug report #1296)
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <gauger.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+#define POST_DATA "<?xml version='1.0' ?>\n<xml>\n<data-id>1</data-id>\n</xml>\n"
+
+#define LOOPCOUNT 1000
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **mptr)
+{
+ static int marker;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp ("POST", method))
+ {
+ printf ("METHOD: %s\n", method);
+ return MHD_NO; /* unexpected method */
+ }
+ if ((*mptr != NULL) && (0 == *upload_data_size))
+ {
+ if (*mptr != &marker)
+ abort ();
+ response = MHD_create_response_from_buffer (2, "OK",
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ *mptr = NULL;
+ return ret;
+ }
+ if (strlen (POST_DATA) != *upload_data_size)
+ return MHD_YES;
+ *upload_data_size = 0;
+ *mptr = ▮
+ return MHD_YES;
+}
+
+
+static int
+testInternalPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ int i;
+ char url[1024];
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1080, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ for (i = 0; i < LOOPCOUNT; i++)
+ {
+ if (99 == i % 100)
+ fprintf (stderr, ".");
+ c = curl_easy_init ();
+ cbc.pos = 0;
+ buf[0] = '\0';
+ sprintf (url, "http://127.0.0.1:1080/hw%d", i);
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
+ curl_easy_setopt (c, CURLOPT_POST, 1L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ if ((buf[0] != 'O') || (buf[1] != 'K'))
+ {
+ MHD_stop_daemon (d);
+ return 4;
+ }
+ }
+ MHD_stop_daemon (d);
+ if (LOOPCOUNT >= 99)
+ fprintf (stderr, "\n");
+ return 0;
+}
+
+static int
+testMultithreadedPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ int i;
+ char url[1024];
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ for (i = 0; i < LOOPCOUNT; i++)
+ {
+ if (99 == i % 100)
+ fprintf (stderr, ".");
+ c = curl_easy_init ();
+ cbc.pos = 0;
+ buf[0] = '\0';
+ sprintf (url, "http://127.0.0.1:1081/hw%d", i);
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
+ curl_easy_setopt (c, CURLOPT_POST, 1L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ if ((buf[0] != 'O') || (buf[1] != 'K'))
+ {
+ MHD_stop_daemon (d);
+ return 64;
+ }
+ }
+ MHD_stop_daemon (d);
+ if (LOOPCOUNT >= 99)
+ fprintf (stderr, "\n");
+ return 0;
+}
+
+static int
+testMultithreadedPoolPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ int i;
+ char url[1024];
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, NULL,
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ for (i = 0; i < LOOPCOUNT; i++)
+ {
+ if (99 == i % 100)
+ fprintf (stderr, ".");
+ c = curl_easy_init ();
+ cbc.pos = 0;
+ buf[0] = '\0';
+ sprintf (url, "http://127.0.0.1:1081/hw%d", i);
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
+ curl_easy_setopt (c, CURLOPT_POST, 1L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ if ((buf[0] != 'O') || (buf[1] != 'K'))
+ {
+ MHD_stop_daemon (d);
+ return 64;
+ }
+ }
+ MHD_stop_daemon (d);
+ if (LOOPCOUNT >= 99)
+ fprintf (stderr, "\n");
+ return 0;
+}
+
+static int
+testExternalPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+ int i;
+ unsigned long long timeout;
+ long ctimeout;
+ char url[1024];
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ for (i = 0; i < LOOPCOUNT; i++)
+ {
+ if (99 == i % 100)
+ fprintf (stderr, ".");
+ c = curl_easy_init ();
+ cbc.pos = 0;
+ buf[0] = '\0';
+ sprintf (url, "http://127.0.0.1:1082/hw%d", i);
+ curl_easy_setopt (c, CURLOPT_URL, url);
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
+ curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
+ curl_easy_setopt (c, CURLOPT_POST, 1L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ while (CURLM_CALL_MULTI_PERFORM ==
+ curl_multi_perform (multi, &running));
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ if (MHD_NO == MHD_get_timeout (d, &timeout))
+ timeout = 100; /* 100ms == INFTY -- CURL bug... */
+ if ((CURLM_OK == curl_multi_timeout (multi, &ctimeout)) &&
+ (ctimeout < timeout) && (ctimeout >= 0))
+ timeout = ctimeout;
+ if ( (c == NULL) || (running == 0) )
+ timeout = 0; /* terminate quickly... */
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ if (-1 == select (max + 1, &rs, &ws, &es, &tv))
+ {
+ if (EINTR == errno)
+ continue;
+ fprintf (stderr,
+ "select failed: %s\n",
+ strerror (errno));
+ break;
+ }
+ while (CURLM_CALL_MULTI_PERFORM ==
+ curl_multi_perform (multi, &running));
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ c = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (c != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ }
+ if ((buf[0] != 'O') || (buf[1] != 'K'))
+ {
+ curl_multi_cleanup (multi);
+ MHD_stop_daemon (d);
+ return 8192;
+ }
+ }
+ curl_multi_cleanup (multi);
+ MHD_stop_daemon (d);
+ if (LOOPCOUNT >= 99)
+ fprintf (stderr, "\n");
+ return 0;
+}
+
+
+/**
+ * Time this round was started.
+ */
+static unsigned long long start_time;
+
+
+/**
+ * Get the current timestamp
+ *
+ * @return current time in ms
+ */
+static unsigned long long
+now ()
+{
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+ return (((unsigned long long) tv.tv_sec * 1000LL) +
+ ((unsigned long long) tv.tv_usec / 1000LL));
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ start_time = now();
+ errorCount += testInternalPost ();
+ fprintf (stderr,
+ oneone ? "%s: Sequential POSTs (http/1.1) %f/s\n" : "%s: Sequential POSTs (http/1.0) %f/s\n",
+ "internal select",
+ (double) 1000 * LOOPCOUNT / (now() - start_time + 1.0));
+ GAUGER ("internal select",
+ oneone ? "Sequential POSTs (http/1.1)" : "Sequential POSTs (http/1.0)",
+ (double) 1000 * LOOPCOUNT / (now() - start_time + 1.0),
+ "requests/s");
+ start_time = now();
+ errorCount += testMultithreadedPost ();
+ fprintf (stderr,
+ oneone ? "%s: Sequential POSTs (http/1.1) %f/s\n" : "%s: Sequential POSTs (http/1.0) %f/s\n",
+ "multithreaded post",
+ (double) 1000 * LOOPCOUNT / (now() - start_time + 1.0));
+ GAUGER ("Multithreaded select",
+ oneone ? "Sequential POSTs (http/1.1)" : "Sequential POSTs (http/1.0)",
+ (double) 1000 * LOOPCOUNT / (now() - start_time + 1.0),
+ "requests/s");
+ start_time = now();
+ errorCount += testMultithreadedPoolPost ();
+ fprintf (stderr,
+ oneone ? "%s: Sequential POSTs (http/1.1) %f/s\n" : "%s: Sequential POSTs (http/1.0) %f/s\n",
+ "thread with pool",
+ (double) 1000 * LOOPCOUNT / (now() - start_time + 1.0));
+ GAUGER ("thread with pool",
+ oneone ? "Sequential POSTs (http/1.1)" : "Sequential POSTs (http/1.0)",
+ (double) 1000 * LOOPCOUNT / (now() - start_time + 1.0),
+ "requests/s");
+ start_time = now();
+ errorCount += testExternalPost ();
+ fprintf (stderr,
+ oneone ? "%s: Sequential POSTs (http/1.1) %f/s\n" : "%s: Sequential POSTs (http/1.0) %f/s\n",
+ "external select",
+ (double) 1000 * LOOPCOUNT / (now() - start_time + 1.0));
+ GAUGER ("external select",
+ oneone ? "Sequential POSTs (http/1.1)" : "Sequential POSTs (http/1.0)",
+ (double) 1000 * LOOPCOUNT / (now() - start_time + 1.0),
+ "requests/s");
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_postform.c b/src/testcurl/test_postform.c
new file mode 100644
index 0000000..450eb6f
--- /dev/null
+++ b/src/testcurl/test_postform.c
@@ -0,0 +1,498 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_postform.c
+ * @brief Testcase for libmicrohttpd POST operations using multipart/postform data
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_GCRYPT_H
+#include <gcrypt.h>
+#endif
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+
+static void
+completed_cb (void *cls,
+ struct MHD_Connection *connection,
+ void **con_cls,
+ enum MHD_RequestTerminationCode toe)
+{
+ struct MHD_PostProcessor *pp = *con_cls;
+
+ if (NULL != pp)
+ MHD_destroy_post_processor (pp);
+ *con_cls = NULL;
+}
+
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+
+/**
+ * Note that this post_iterator is not perfect
+ * in that it fails to support incremental processing.
+ * (to be fixed in the future)
+ */
+static int
+post_iterator (void *cls,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *filename,
+ const char *content_type,
+ const char *transfer_encoding,
+ const char *value, uint64_t off, size_t size)
+{
+ int *eok = cls;
+
+#if 0
+ fprintf (stderr, "PI sees %s-%.*s\n", key, size, value);
+#endif
+ if ((0 == strcmp (key, "name")) &&
+ (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size)))
+ (*eok) |= 1;
+ if ((0 == strcmp (key, "project")) &&
+ (size == strlen ("curl")) && (0 == strncmp (value, "curl", size)))
+ (*eok) |= 2;
+ return MHD_YES;
+}
+
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int eok;
+ struct MHD_Response *response;
+ struct MHD_PostProcessor *pp;
+ int ret;
+
+ if (0 != strcmp ("POST", method))
+ {
+ printf ("METHOD: %s\n", method);
+ return MHD_NO; /* unexpected method */
+ }
+ pp = *unused;
+ if (pp == NULL)
+ {
+ eok = 0;
+ pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
+ if (pp == NULL)
+ abort ();
+ *unused = pp;
+ }
+ MHD_post_process (pp, upload_data, *upload_data_size);
+ if ((eok == 3) && (0 == *upload_data_size))
+ {
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ MHD_destroy_post_processor (pp);
+ *unused = NULL;
+ return ret;
+ }
+ *upload_data_size = 0;
+ return MHD_YES;
+}
+
+static struct curl_httppost *
+make_form ()
+{
+ struct curl_httppost *post = NULL;
+ struct curl_httppost *last = NULL;
+
+ curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END);
+ curl_formadd (&post, &last, CURLFORM_COPYNAME, "project",
+ CURLFORM_COPYCONTENTS, "curl", CURLFORM_END);
+ return post;
+}
+
+
+static int
+testInternalPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ struct curl_httppost *pd;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1080, NULL, NULL, &ahc_echo, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ pd = make_form ();
+ curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ curl_formfree (pd);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ curl_formfree (pd);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+static int
+testMultithreadedPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ struct curl_httppost *pd;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ pd = make_form ();
+ curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ curl_formfree (pd);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ curl_formfree (pd);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testMultithreadedPoolPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ struct curl_httppost *pd;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081, NULL, NULL, &ahc_echo, NULL,
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
+ MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ pd = make_form ();
+ curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ curl_formfree (pd);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ curl_formfree (pd);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testExternalPost ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+ struct curl_httppost *pd;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082, NULL, NULL, &ahc_echo, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ pd = make_form ();
+ curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ curl_formfree (pd);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_formfree (pd);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ curl_formfree (pd);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ curl_formfree (pd);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ curl_formfree (pd);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+#ifdef HAVE_GCRYPT_H
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+#endif
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testInternalPost ();
+ errorCount += testMultithreadedPost ();
+ errorCount += testMultithreadedPoolPost ();
+ errorCount += testExternalPost ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_process_arguments.c b/src/testcurl/test_process_arguments.c
new file mode 100644
index 0000000..a3e5841
--- /dev/null
+++ b/src/testcurl/test_process_arguments.c
@@ -0,0 +1,249 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2013 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_process_arguments.c
+ * @brief Testcase for HTTP URI arguments
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+ const char *hdr;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ hdr = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "k");
+ if ((hdr == NULL) || (0 != strcmp (hdr, "v x")))
+ abort ();
+ hdr = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND, "hash");
+ if ((hdr == NULL) || (0 != strcmp (hdr, "#foo")))
+ abort ();
+ hdr = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND, "space");
+ if ((hdr == NULL) || (0 != strcmp (hdr, "\240bar")))
+ abort ();
+ if (3 != MHD_get_connection_values (connection,
+ MHD_GET_ARGUMENT_KIND,
+ NULL, NULL))
+ abort ();
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static int
+testExternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL,
+ "http://127.0.0.1:21080/hello+world?k=v+x&hash=%23foo&space=%A0bar");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello+world"))
+ return 8192;
+ if (0 != strncmp ("/hello+world", cbc.buf, strlen ("/hello+world")))
+ return 16384;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testExternalGet ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_process_headers.c b/src/testcurl/test_process_headers.c
new file mode 100644
index 0000000..4a219fb
--- /dev/null
+++ b/src/testcurl/test_process_headers.c
@@ -0,0 +1,434 @@
+
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_process_headers.c
+ * @brief Testcase for HTTP header access
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+kv_cb (void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
+{
+ if ((0 == strcmp (key, MHD_HTTP_HEADER_HOST)) &&
+ (0 == strcmp (value, "127.0.0.1:21080")) && (kind == MHD_HEADER_KIND))
+ {
+ *((int *) cls) = 1;
+ return MHD_NO;
+ }
+ return MHD_YES;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+ const char *hdr;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ ret = 0;
+ MHD_get_connection_values (connection, MHD_HEADER_KIND, &kv_cb, &ret);
+ if (ret != 1)
+ abort ();
+ hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "NotFound");
+ if (hdr != NULL)
+ abort ();
+ hdr = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT);
+ if ((hdr == NULL) || (0 != strcmp (hdr, "*/*")))
+ abort ();
+ hdr = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND, MHD_HTTP_HEADER_HOST);
+ if ((hdr == NULL) || (0 != strcmp (hdr, "127.0.0.1:21080")))
+ abort ();
+ MHD_set_connection_value (connection,
+ MHD_HEADER_KIND, "FakeHeader", "NowPresent");
+ hdr = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND, "FakeHeader");
+ if ((hdr == NULL) || (0 != strcmp (hdr, "NowPresent")))
+ abort ();
+
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ MHD_add_response_header (response, "MyHeader", "MyValue");
+ hdr = MHD_get_response_header (response, "MyHeader");
+ if (0 != strcmp ("MyValue", hdr))
+ abort ();
+ MHD_add_response_header (response, "MyHeader", "MyValueToo");
+ if (MHD_YES != MHD_del_response_header (response, "MyHeader", "MyValue"))
+ abort ();
+ hdr = MHD_get_response_header (response, "MyHeader");
+ if (0 != strcmp ("MyValueToo", hdr))
+ abort ();
+ if (1 != MHD_get_response_headers (response, NULL, NULL))
+ abort ();
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static int
+testInternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:21080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+static int
+testMultithreadedGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:21080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testMultithreadedPoolGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 21080, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:21080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+ return 0;
+}
+
+static int
+testExternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:21080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system! */
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ errorCount += testMultithreadedGet ();
+ errorCount += testMultithreadedPoolGet ();
+ errorCount += testExternalGet ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_put.c b/src/testcurl/test_put.c
new file mode 100644
index 0000000..fe1d8db
--- /dev/null
+++ b/src/testcurl/test_put.c
@@ -0,0 +1,440 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_put.c
+ * @brief Testcase for libmicrohttpd PUT operations
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+static int oneone;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
+{
+ unsigned int *pos = ptr;
+ unsigned int wrt;
+
+ wrt = size * nmemb;
+ if (wrt > 8 - (*pos))
+ wrt = 8 - (*pos);
+ memcpy (stream, &("Hello123"[*pos]), wrt);
+ (*pos) += wrt;
+ return wrt;
+}
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ int *done = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp ("PUT", method))
+ return MHD_NO; /* unexpected method */
+ if ((*done) == 0)
+ {
+ if (*upload_data_size != 8)
+ return MHD_YES; /* not yet ready */
+ if (0 == memcmp (upload_data, "Hello123", 8))
+ {
+ *upload_data_size = 0;
+ }
+ else
+ {
+ printf ("Invalid upload data `%8s'!\n", upload_data);
+ return MHD_NO;
+ }
+ *done = 1;
+ return MHD_YES;
+ }
+ response = MHD_create_response_from_buffer (strlen (url), (void*) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+static int
+testInternalPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1080,
+ NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+static int
+testMultithreadedPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 1081,
+ NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+
+ return 0;
+}
+
+static int
+testMultithreadedPoolPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1081,
+ NULL, NULL, &ahc_echo, &done_flag,
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+
+ return 0;
+}
+
+
+static int
+testExternalPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+ unsigned int pos = 0;
+ int done_flag = 0;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082,
+ NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testInternalPut ();
+ errorCount += testMultithreadedPut ();
+ errorCount += testMultithreadedPoolPut ();
+ errorCount += testExternalPut ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_put_chunked.c b/src/testcurl/test_put_chunked.c
new file mode 100644
index 0000000..b2fa322
--- /dev/null
+++ b/src/testcurl/test_put_chunked.c
@@ -0,0 +1,448 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_put_chunked.c
+ * @brief Testcase for libmicrohttpd PUT operations with chunked encoding
+ * for the upload data
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
+{
+ unsigned int *pos = ptr;
+ unsigned int wrt;
+
+ wrt = size * nmemb;
+ if (wrt > 8 - (*pos))
+ wrt = 8 - (*pos);
+ if (wrt > 4)
+ wrt = 4; /* only send half at first => force multiple chunks! */
+ memcpy (stream, &("Hello123"[*pos]), wrt);
+ (*pos) += wrt;
+ return wrt;
+}
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ int *done = cls;
+ struct MHD_Response *response;
+ int ret;
+ int have;
+
+ if (0 != strcmp ("PUT", method))
+ return MHD_NO; /* unexpected method */
+ if ((*done) < 8)
+ {
+ have = *upload_data_size;
+ if (have + *done > 8)
+ {
+ printf ("Invalid upload data `%8s'!\n", upload_data);
+ return MHD_NO;
+ }
+ if (0 == memcmp (upload_data, &"Hello123"[*done], have))
+ {
+ *done += have;
+ *upload_data_size = 0;
+ }
+ else
+ {
+ printf ("Invalid upload data `%8s'!\n", upload_data);
+ return MHD_NO;
+ }
+#if 0
+ fprintf (stderr, "Not ready for response: %u/%u\n", *done, 8);
+#endif
+ return MHD_YES;
+ }
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+static int
+testInternalPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 11080,
+ NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ /*
+ // by not giving the file size, we force chunking!
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ */
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+static int
+testMultithreadedPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 11081,
+ NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ /*
+ // by not giving the file size, we force chunking!
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ */
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+
+ return 0;
+}
+
+static int
+testMultithreadedPoolPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 11081,
+ NULL, NULL, &ahc_echo, &done_flag,
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ /*
+ // by not giving the file size, we force chunking!
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ */
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+
+ return 0;
+}
+
+
+static int
+testExternalPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+ unsigned int pos = 0;
+ int done_flag = 0;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 11082,
+ NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ /*
+ // by not giving the file size, we force chunking!
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ */
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testInternalPut ();
+ errorCount += testMultithreadedPut ();
+ errorCount += testMultithreadedPoolPut ();
+ errorCount += testExternalPut ();
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_quiesce.c b/src/testcurl/test_quiesce.c
new file mode 100644
index 0000000..17adcb2
--- /dev/null
+++ b/src/testcurl/test_quiesce.c
@@ -0,0 +1,457 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2013, 2015 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file test_quiesce.c
+ * @brief Testcase for libmicrohttpd quiescing
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include "platform_interface.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#include <sys/socket.h>
+#endif
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ *unused = NULL;
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static void
+request_completed (void *cls, struct MHD_Connection *connection,
+ void **con_cls, enum MHD_RequestTerminationCode code)
+{
+ int *done = (int *)cls;
+ *done = 1;
+}
+
+
+static void *
+ServeOneRequest(void *param)
+{
+ struct MHD_Daemon *d;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket fd, max;
+ time_t start;
+ struct timeval tv;
+ int done = 0;
+
+ fd = (MHD_socket) (intptr_t) param;
+
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_LISTEN_SOCKET, fd,
+ MHD_OPTION_NOTIFY_COMPLETED, &request_completed, &done,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return "MHD_start_daemon() failed";
+
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && done == 0)
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ MHD_stop_daemon (d);
+ MHD_socket_close_(fd);
+ return "MHD_get_fdset() failed";
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ MHD_SYS_select_ (max + 1, &rs, &ws, &es, &tv);
+ MHD_run (d);
+ }
+ MHD_stop_daemon (d);
+ MHD_socket_close_(fd);
+ return NULL;
+}
+
+
+static CURL *
+setupCURL (void *cbc)
+{
+ CURL *c;
+
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, 150L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+ return c;
+}
+
+
+static int
+testGet (int type, int pool_count, int poll_flag)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+ MHD_socket fd;
+ pthread_t thrd;
+ const char *thrdRet;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ if (pool_count > 0) {
+ d = MHD_start_daemon (type | MHD_USE_DEBUG | MHD_USE_PIPE_FOR_SHUTDOWN | poll_flag,
+ 11080, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, pool_count, MHD_OPTION_END);
+
+ } else {
+ d = MHD_start_daemon (type | MHD_USE_DEBUG | MHD_USE_PIPE_FOR_SHUTDOWN | poll_flag,
+ 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ }
+ if (d == NULL)
+ return 1;
+
+ c = setupCURL(&cbc);
+
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+
+ if (cbc.pos != strlen ("/hello_world")) {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4;
+ }
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 8;
+ }
+
+ fd = MHD_quiesce_daemon (d);
+ if (0 != pthread_create(&thrd, NULL, &ServeOneRequest, (void*)(intptr_t) fd))
+ {
+ fprintf (stderr, "pthread_create failed\n");
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 16;
+ }
+
+ cbc.pos = 0;
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+
+ if (0 != pthread_join(thrd, (void**)&thrdRet))
+ {
+ fprintf (stderr, "pthread_join failed\n");
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 16;
+ }
+ if (NULL != thrdRet)
+ {
+ fprintf (stderr, "ServeOneRequest() error: %s\n", thrdRet);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 16;
+ }
+
+ if (cbc.pos != strlen ("/hello_world"))
+ {
+ fprintf(stderr, "%s\n", cbc.buf);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ MHD_socket_close_(fd);
+ return 4;
+ }
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ {
+ fprintf(stderr, "%s\n", cbc.buf);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ MHD_socket_close_(fd);
+ return 8;
+ }
+
+ /* at this point, the forked server quit, and the new
+ * server has quiesced, so new requests should fail
+ */
+ if (CURLE_OK == (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr, "curl_easy_perform should fail\n");
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ MHD_socket_close_(fd);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ MHD_socket_close_(fd);
+
+ return 0;
+}
+
+
+static int
+testExternalGet ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+ int i;
+ MHD_socket fd;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = setupCURL(&cbc);
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+
+ for (i = 0; i < 2; i++) {
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (i == 0 && msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ else if (i == 1 && msg->data.result == CURLE_OK)
+ printf ("%s should have failed at %s:%d\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__);
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+
+ if (i == 0) {
+ /* quiesce the daemon on the 1st iteration, so the 2nd should fail */
+ fd = MHD_quiesce_daemon(d);
+ if (MHD_INVALID_SOCKET == fd)
+ abort ();
+ MHD_socket_close_ (fd);
+ c = setupCURL (&cbc);
+ multi = curl_multi_init ();
+ mret = curl_multi_add_handle (multi, c);
+ }
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testGet (MHD_USE_SELECT_INTERNALLY, 0, 0);
+ errorCount += testGet (MHD_USE_THREAD_PER_CONNECTION, 0, 0);
+ errorCount += testGet (MHD_USE_SELECT_INTERNALLY, CPU_COUNT, 0);
+ errorCount += testExternalGet ();
+ if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_POLL))
+ {
+ errorCount += testGet(MHD_USE_SELECT_INTERNALLY, 0, MHD_USE_POLL);
+ errorCount += testGet (MHD_USE_THREAD_PER_CONNECTION, 0, MHD_USE_POLL);
+ errorCount += testGet (MHD_USE_SELECT_INTERNALLY, CPU_COUNT, MHD_USE_POLL);
+ }
+ if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_EPOLL))
+ {
+ errorCount += testGet (MHD_USE_SELECT_INTERNALLY, 0, MHD_USE_EPOLL_LINUX_ONLY);
+ errorCount += testGet (MHD_USE_SELECT_INTERNALLY, CPU_COUNT, MHD_USE_EPOLL_LINUX_ONLY);
+ }
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_start_stop.c b/src/testcurl/test_start_stop.c
new file mode 100644
index 0000000..a708341
--- /dev/null
+++ b/src/testcurl/test_start_stop.c
@@ -0,0 +1,129 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2011 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_start_stop.c
+ * @brief test for #1901 (start+stop)
+ * @author Christian Grothoff
+ */
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+
+#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
+#undef CPU_COUNT
+#endif
+#if !defined(CPU_COUNT)
+#define CPU_COUNT 2
+#endif
+
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ return MHD_NO;
+}
+
+
+static int
+testInternalGet (int poll_flag)
+{
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+static int
+testMultithreadedGet (int poll_flag)
+{
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
+ 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 2;
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+static int
+testMultithreadedPoolGet (int poll_flag)
+{
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ 1081, NULL, NULL, &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ if (d == NULL)
+ return 4;
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+static int
+testExternalGet ()
+{
+ struct MHD_Daemon *d;
+
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 8;
+ MHD_stop_daemon (d);
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ errorCount += testInternalGet (0);
+ errorCount += testMultithreadedGet (0);
+ errorCount += testMultithreadedPoolGet (0);
+ errorCount += testExternalGet ();
+ if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_POLL))
+ {
+ errorCount += testInternalGet(MHD_USE_POLL);
+ errorCount += testMultithreadedGet(MHD_USE_POLL);
+ errorCount += testMultithreadedPoolGet(MHD_USE_POLL);
+ }
+ if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_EPOLL))
+ {
+ errorCount += testInternalGet(MHD_USE_EPOLL_LINUX_ONLY);
+ errorCount += testMultithreadedPoolGet(MHD_USE_EPOLL_LINUX_ONLY);
+ }
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ return errorCount != 0; /* 0 == pass */
+}
diff --git a/src/testcurl/test_termination.c b/src/testcurl/test_termination.c
new file mode 100644
index 0000000..25f9e61
--- /dev/null
+++ b/src/testcurl/test_termination.c
@@ -0,0 +1,125 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2009 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_termination.c
+ * @brief Testcase for libmicrohttpd tolerating client not closing immediately
+ * @author hollosig
+ */
+#define PORT 12345
+
+#include "platform.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <microhttpd.h>
+#include <unistd.h>
+#include <curl/curl.h>
+
+#ifndef __MINGW32__
+#include <sys/select.h>
+#include <sys/socket.h>
+#endif
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif /* !WIN32_LEAN_AND_MEAN */
+#include <windows.h>
+#endif
+
+static int
+connection_handler (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t * upload_data_size,
+ void **ptr)
+{
+ static int i;
+
+ if (*ptr == NULL)
+ {
+ *ptr = &i;
+ return MHD_YES;
+ }
+
+ if (*upload_data_size != 0)
+ {
+ (*upload_data_size) = 0;
+ return MHD_YES;
+ }
+
+ struct MHD_Response *response =
+ MHD_create_response_from_buffer (strlen ("Response"), "Response",
+ MHD_RESPMEM_PERSISTENT);
+ int ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+
+ return ret;
+}
+
+static size_t
+write_data (void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ return size * nmemb;
+}
+
+int
+main ()
+{
+ struct MHD_Daemon *daemon;
+
+ daemon = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ PORT,
+ NULL,
+ NULL, connection_handler, NULL, MHD_OPTION_END);
+
+ if (daemon == NULL)
+ {
+ fprintf (stderr, "Daemon cannot be started!");
+ exit (1);
+ }
+
+ CURL *curl = curl_easy_init ();
+ //curl_easy_setopt(curl, CURLOPT_POST, 1L);
+ char url[255];
+ sprintf (url, "http://127.0.0.1:%d", PORT);
+ curl_easy_setopt (curl, CURLOPT_URL, url);
+ curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, write_data);
+
+ CURLcode success = curl_easy_perform (curl);
+ if (success != 0)
+ {
+ fprintf (stderr, "CURL Error");
+ exit (1);
+ }
+ /* CPU used to go crazy here */
+ sleep (1);
+
+ curl_easy_cleanup (curl);
+ MHD_stop_daemon (daemon);
+
+ return 0;
+}
diff --git a/src/testcurl/test_timeout.c b/src/testcurl/test_timeout.c
new file mode 100644
index 0000000..006c1a8
--- /dev/null
+++ b/src/testcurl/test_timeout.c
@@ -0,0 +1,294 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_timeout.c
+ * @brief Testcase for libmicrohttpd PUT operations
+ * @author Matthias Wachs
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+static int oneone;
+
+static int withTimeout = 1;
+
+static int withoutTimeout = 1;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+
+static void
+termination_cb (void *cls,
+ struct MHD_Connection *connection,
+ void **con_cls,
+ enum MHD_RequestTerminationCode toe)
+{
+ int *test = cls;
+
+ switch (toe)
+ {
+ case MHD_REQUEST_TERMINATED_COMPLETED_OK :
+ if (test == &withoutTimeout)
+ {
+ withoutTimeout = 0;
+ }
+ break;
+ case MHD_REQUEST_TERMINATED_WITH_ERROR :
+ case MHD_REQUEST_TERMINATED_READ_ERROR :
+ break;
+ case MHD_REQUEST_TERMINATED_TIMEOUT_REACHED :
+ if (test == &withTimeout)
+ {
+ withTimeout = 0;
+ }
+ break;
+ case MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN:
+ break;
+ case MHD_REQUEST_TERMINATED_CLIENT_ABORT:
+ break;
+ }
+}
+
+
+static size_t
+putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
+{
+ unsigned int *pos = ptr;
+ unsigned int wrt;
+
+ wrt = size * nmemb;
+ if (wrt > 8 - (*pos))
+ wrt = 8 - (*pos);
+ memcpy (stream, &("Hello123"[*pos]), wrt);
+ (*pos) += wrt;
+ return wrt;
+}
+
+
+static size_t
+putBuffer_fail (void *stream, size_t size, size_t nmemb, void *ptr)
+{
+ return 0;
+}
+
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ int *done = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp ("PUT", method))
+ return MHD_NO; /* unexpected method */
+ if ((*done) == 0)
+ {
+ if (*upload_data_size != 8)
+ return MHD_YES; /* not yet ready */
+ if (0 == memcmp (upload_data, "Hello123", 8))
+ {
+ *upload_data_size = 0;
+ }
+ else
+ {
+ printf ("Invalid upload data `%8s'!\n", upload_data);
+ return MHD_NO;
+ }
+ *done = 1;
+ return MHD_YES;
+ }
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+static int
+testWithoutTimeout ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1080,
+ NULL, NULL, &ahc_echo, &done_flag,
+ MHD_OPTION_CONNECTION_TIMEOUT, 2,
+ MHD_OPTION_NOTIFY_COMPLETED, &termination_cb, &withTimeout,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+static int
+testWithTimeout ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 1080,
+ NULL, NULL, &ahc_echo, &done_flag,
+ MHD_OPTION_CONNECTION_TIMEOUT, 2,
+ MHD_OPTION_NOTIFY_COMPLETED, &termination_cb, &withoutTimeout,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer_fail);
+ curl_easy_setopt (c, CURLOPT_READDATA, &testWithTimeout);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (errornum == CURLE_GOT_NOTHING)
+ /* mhd had the timeout */
+ return 0;
+ else
+ /* curl had the timeout first */
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 64;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 16;
+ errorCount += testWithoutTimeout ();
+ errorCount += testWithTimeout ();
+ if (errorCount != 0)
+ fprintf (stderr,
+ "Error during test execution (code: %u)\n",
+ errorCount);
+ curl_global_cleanup ();
+ if ((withTimeout == 0) && (withoutTimeout == 0))
+ return 0;
+ else
+ return errorCount; /* 0 == pass */
+}
diff --git a/src/testcurl/test_urlparse.c b/src/testcurl/test_urlparse.c
new file mode 100644
index 0000000..c48bff2
--- /dev/null
+++ b/src/testcurl/test_urlparse.c
@@ -0,0 +1,191 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009, 2011 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_urlparse.c
+ * @brief Testcase for libmicrohttpd url parsing
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif /* !WIN32_LEAN_AND_MEAN */
+#include <windows.h>
+#endif
+
+#ifndef WINDOWS
+#include <unistd.h>
+#include <sys/socket.h>
+#endif
+
+static int oneone;
+
+static int matches;
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+test_values (void *cls,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *value)
+{
+ if ( (0 == strcmp (key, "a")) &&
+ (0 == strcmp (value, "b")) )
+ matches += 1;
+ if ( (0 == strcmp (key, "c")) &&
+ (0 == strcmp (value, "")) )
+ matches += 2;
+ if ( (0 == strcmp (key, "d")) &&
+ (NULL == value) )
+ matches += 4;
+ return MHD_YES;
+}
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size,
+ void **unused)
+{
+ static int ptr;
+ const char *me = cls;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp (me, method))
+ return MHD_NO; /* unexpected method */
+ if (&ptr != *unused)
+ {
+ *unused = &ptr;
+ return MHD_YES;
+ }
+ MHD_get_connection_values (connection,
+ MHD_GET_ARGUMENT_KIND,
+ &test_values,
+ NULL);
+ *unused = NULL;
+ response = MHD_create_response_from_buffer (strlen (url),
+ (void *) url,
+ MHD_RESPMEM_MUST_COPY);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ if (ret == MHD_NO)
+ abort ();
+ return ret;
+}
+
+
+static int
+testInternalGet (int poll_flag)
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+ 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world?a=b&c=&d");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+ if (oneone)
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ /* NOTE: use of CONNECTTIMEOUT without also
+ setting NOSIGNAL results in really weird
+ crashes on my system!*/
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ if (matches != 7)
+ return 16;
+ return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ oneone = (NULL != strrchr (argv[0], (int) '/')) ?
+ (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testInternalGet (0);
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}