mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
testzzuf: re-worked zzuf testing
* merged test_get, test_get_chunked, test_put * fixed use of header instead of footer in chunked data callback * added checks for results of all used MHD functions * added reading of all data in the input buffer provided by MHD for callback * re-used libcurl handles to re-use connections in all modes * added testing of 'poll' and 'epoll' for all tests * removed the need for socat * removed forking with potential forked process zombies * fixed processing only of the first request (as soon as socat connection become broken, all following requests went to nowhere) * implemented correct response for unsupported methods * used proper timeout for 'external select()' (taken into account libcurl timeout too) * added check for extra reply data * added debug print of libcurl sent and received data * merged all tests into single source file * fixed a lot of compiler warnings * added check for incorrect replies produced by MHD
This commit is contained in:
+45
-41
@@ -3052,47 +3052,6 @@ AS_IF([[test "x$enable_postprocessor" != "xno"]],
|
||||
AM_CONDITIONAL([HAVE_POSTPROCESSOR], [test "x$enable_postprocessor" != "xno"])
|
||||
AC_MSG_RESULT([[$enable_postprocessor]])
|
||||
|
||||
|
||||
# optional: have zzuf, socat?
|
||||
run_zzuf_tests="no"
|
||||
AS_VAR_IF([use_heavy_tests],["yes"],
|
||||
[
|
||||
AS_VAR_IF([enable_curl],["yes"],
|
||||
[
|
||||
AC_CHECK_PROG([have_zzuf],[zzuf],[yes],[no])
|
||||
AS_VAR_IF([have_zzuf],["yes"],
|
||||
[
|
||||
AC_CHECK_PROG([have_socat],[socat],[yes],[no])
|
||||
AS_VAR_IF([have_socat],["yes"],
|
||||
[
|
||||
run_zzuf_tests="yes"
|
||||
run_zzuf_tests_MSG="yes"
|
||||
],
|
||||
[
|
||||
run_zzuf_tests="no"
|
||||
run_zzuf_tests_MSG="no, socat tool not found"
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
run_zzuf_tests="no"
|
||||
run_zzuf_tests_MSG="no, zzuf tool not found"
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
run_zzuf_tests="no"
|
||||
run_zzuf_tests_MSG="no, tests with libcurl are not enabled"
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
run_zzuf_tests="no"
|
||||
run_zzuf_tests_MSG="no, heavy tests are not enabled"
|
||||
]
|
||||
)
|
||||
AM_CONDITIONAL([RUN_ZZUF_TESTS],[test "x$run_zzuf_tests" = "xyes"])
|
||||
|
||||
have_gnutls=no
|
||||
have_gnutls_sni=no
|
||||
have_gcrypt=no
|
||||
@@ -4883,6 +4842,50 @@ int main(void)
|
||||
]
|
||||
)
|
||||
|
||||
# fuzzing tests
|
||||
run_zzuf_tests="no"
|
||||
AS_VAR_IF([use_heavy_tests],["yes"],
|
||||
[
|
||||
AS_VAR_IF([enable_curl],["yes"],
|
||||
[
|
||||
AC_PATH_PROG([ZZUF],[zzuf],[no])
|
||||
AS_VAR_IF([ZZUF],["no"],
|
||||
[
|
||||
run_zzuf_tests="no"
|
||||
run_zzuf_tests_MSG="no, zzuf tool not found"
|
||||
],
|
||||
[
|
||||
AS_IF([test "x${ac_cv_func_accept4}" = "xyes" && test "x${enable_asserts}" = "xno"],
|
||||
[
|
||||
run_zzuf_tests="no"
|
||||
run_zzuf_tests_MSG="no, fuzzing tests require asserts enabled on this platform"
|
||||
],
|
||||
[test -n "${enabled_sanitizers}"],
|
||||
[
|
||||
run_zzuf_tests="no"
|
||||
run_zzuf_tests_MSG="no, fuzzing tests cannot be used with sanitizers"
|
||||
],
|
||||
[
|
||||
run_zzuf_tests="yes"
|
||||
run_zzuf_tests_MSG="yes"
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
run_zzuf_tests="no"
|
||||
run_zzuf_tests_MSG="no, tests with libcurl are not enabled"
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
run_zzuf_tests="no"
|
||||
run_zzuf_tests_MSG="no, heavy tests are not enabled"
|
||||
]
|
||||
)
|
||||
AM_CONDITIONAL([RUN_ZZUF_TESTS],[test "x$run_zzuf_tests" = "xyes"])
|
||||
|
||||
# Final flags that may interfere with autoconf detections
|
||||
AS_CASE([${enable_build_type}],[debug|debugger],
|
||||
[ # Debug build or build for walking with debugger
|
||||
@@ -4955,6 +4958,7 @@ AC_CONFIG_COMMANDS([po-directories],
|
||||
# not contain the actual installation.
|
||||
AC_DEFINE_DIR([MHD_PLUGIN_INSTALL_PREFIX], [libdir/libmicrohttpd], [tls plugins])
|
||||
|
||||
AC_SUBST([ZZUF])
|
||||
|
||||
# should experimental code be compiled (code that may not yet compile)?
|
||||
AC_MSG_CHECKING(whether to compile experimental code)
|
||||
|
||||
+76
-47
@@ -1,17 +1,29 @@
|
||||
# This Makefile.am is in the public domain
|
||||
|
||||
SUBDIRS = .
|
||||
|
||||
# ZZUF_SEED can be redefined to use other initial seeds
|
||||
# for extended testing. E.g.,
|
||||
# make ZZUF_SEED=1234 check
|
||||
ZZUF_SEED = 0
|
||||
|
||||
# Additional flags for zzuf
|
||||
ZZUF_FLAGS =
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/include \
|
||||
-I$(top_srcdir)/src/microhttpd \
|
||||
-DMHD_CPU_COUNT=$(CPU_COUNT) \
|
||||
$(CPPFLAGS_ac) $(LIBCURL_CPPFLAGS)
|
||||
|
||||
AM_CFLAGS = $(CFLAGS_ac) @LIBGCRYPT_CFLAGS@
|
||||
AM_CFLAGS = $(CFLAGS_ac)
|
||||
|
||||
AM_LDFLAGS = $(LDFLAGS_ac)
|
||||
|
||||
AM_TESTS_ENVIRONMENT = $(TESTS_ENVIRONMENT_ac)
|
||||
AM_TESTS_ENVIRONMENT = $(TESTS_ENVIRONMENT_ac) \
|
||||
ZZUF="$(ZZUF)" ; export ZZUF ; \
|
||||
ZZUF_SEED="$(ZZUF_SEED)" ; export ZZUF_SEED ; \
|
||||
ZZUF_FLAGS="$(ZZUF_FLAGS)" ; export ZZUF_FLAGS ;
|
||||
|
||||
if USE_COVERAGE
|
||||
AM_CFLAGS += -fprofile-arcs -ftest-coverage
|
||||
@@ -25,11 +37,6 @@ $(top_builddir)/src/microhttpd/libmicrohttpd.la: $(top_builddir)/src/microhttpd/
|
||||
@echo ' cd $(top_builddir)/src/microhttpd && $(MAKE) $(AM_MAKEFLAGS) libmicrohttpd.la'; \
|
||||
$(am__cd) $(top_builddir)/src/microhttpd && $(MAKE) $(AM_MAKEFLAGS) libmicrohttpd.la
|
||||
|
||||
EXTRA_DIST = README socat.c
|
||||
|
||||
THREAD_ONLY_TESTS = \
|
||||
test_long_header
|
||||
|
||||
check_PROGRAMS = \
|
||||
test_get \
|
||||
test_get_chunked \
|
||||
@@ -38,64 +45,86 @@ check_PROGRAMS = \
|
||||
test_put \
|
||||
test_put_chunked \
|
||||
test_put_large \
|
||||
test_get11 \
|
||||
test_post11 \
|
||||
test_post_form11 \
|
||||
test_put11 \
|
||||
test_put_large11
|
||||
test_get_long_uri \
|
||||
test_get_long_header \
|
||||
test_get_close \
|
||||
test_get_chunked_close \
|
||||
test_post_close \
|
||||
test_post_form_close \
|
||||
test_put_close \
|
||||
test_put_chunked_close \
|
||||
test_put_large_close \
|
||||
test_get_long_uri_close \
|
||||
test_get_long_header_close \
|
||||
test_get10 \
|
||||
test_get_chunked10 \
|
||||
test_post10 \
|
||||
test_post_form10 \
|
||||
test_put10 \
|
||||
test_put_large10 \
|
||||
test_get_long_uri10 \
|
||||
test_get_long_header10
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
||||
|
||||
if USE_POSIX_THREADS
|
||||
check_PROGRAMS += \
|
||||
$(THREAD_ONLY_TESTS)
|
||||
endif
|
||||
if USE_W32_THREADS
|
||||
check_PROGRAMS += \
|
||||
$(THREAD_ONLY_TESTS)
|
||||
endif
|
||||
|
||||
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
dist_check_SCRIPTS = zzuf_test_runner.sh
|
||||
|
||||
LOG_COMPILER = @SHELL@ $(srcdir)/zzuf_test_runner.sh
|
||||
|
||||
tests_common_sources = mhd_debug_funcs.h mhd_debug_funcs.c
|
||||
|
||||
test_get_SOURCES = \
|
||||
test_get.c
|
||||
test_get.c $(tests_common_sources)
|
||||
|
||||
test_get_chunked_SOURCES = \
|
||||
test_get_chunked.c
|
||||
test_get_chunked_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_post_SOURCES = \
|
||||
test_post.c
|
||||
test_post_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_post_form_SOURCES = \
|
||||
test_post_form.c
|
||||
test_post_form_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_put_SOURCES = \
|
||||
test_put.c
|
||||
test_put_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_put_chunked_SOURCES = \
|
||||
test_put_chunked.c
|
||||
test_put_chunked_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_put_large_SOURCES = \
|
||||
test_put_large.c
|
||||
test_put_large_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_get_long_uri_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_get_long_header_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_get11_SOURCES = \
|
||||
test_get.c
|
||||
test_get_close_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_post11_SOURCES = \
|
||||
test_post.c
|
||||
test_get_chunked_close_SOURCES = $(test_get_chunked_SOURCES)
|
||||
|
||||
test_post_form11_SOURCES = \
|
||||
test_post_form.c
|
||||
test_post_close_SOURCES = $(test_post_SOURCES)
|
||||
|
||||
test_put11_SOURCES = \
|
||||
test_put.c
|
||||
test_post_form_close_SOURCES = $(test_post_form_SOURCES)
|
||||
|
||||
test_put_large11_SOURCES = \
|
||||
test_put_large.c
|
||||
test_put_close_SOURCES = $(test_put_SOURCES)
|
||||
|
||||
test_long_header_SOURCES = \
|
||||
test_long_header.c
|
||||
test_put_chunked_close_SOURCES = $(test_put_chunked_SOURCES)
|
||||
|
||||
test_put_large_close_SOURCES = $(test_put_large_SOURCES)
|
||||
|
||||
test_get_long_uri_close_SOURCES = $(test_get_long_uri_SOURCES)
|
||||
|
||||
test_get_long_header_close_SOURCES = $(test_get_long_header_SOURCES)
|
||||
|
||||
test_get10_SOURCES = $(test_get_SOURCES)
|
||||
|
||||
test_get_chunked10_SOURCES = $(test_get_chunked_SOURCES)
|
||||
|
||||
test_post10_SOURCES = $(test_post_SOURCES)
|
||||
|
||||
test_post_form10_SOURCES = $(test_post_form_SOURCES)
|
||||
|
||||
test_put10_SOURCES = $(test_put_SOURCES)
|
||||
|
||||
test_put_large10_SOURCES = $(test_put_large_SOURCES)
|
||||
|
||||
test_get_long_uri10_SOURCES = $(test_get_long_uri_SOURCES)
|
||||
|
||||
test_get_long_header10_SOURCES = $(test_get_long_header_SOURCES)
|
||||
|
||||
@@ -61,3 +61,48 @@ MHD_avoid_accept4_ (struct MHD_Daemon *daemon)
|
||||
#endif /* ! _DEBUG */
|
||||
#endif /* USE_ACCEPT4 */
|
||||
}
|
||||
|
||||
#ifdef MHD_ASAN_ACTIVE
|
||||
#define MHD_ASAN_ENABLED_ 1
|
||||
#else /* ! MHD_ASAN_ACTIVE */
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
#define MHD_ASAN_ENABLED_ 1
|
||||
#else /* ! __SANITIZE_ADDRESS__ */
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(address_sanitizer)
|
||||
#define MHD_ASAN_ENABLED_ 1
|
||||
#endif /* __has_feature(address_sanitizer) */
|
||||
#endif /* __has_feature */
|
||||
#endif /* ! __SANITIZE_ADDRESS__ */
|
||||
#endif /* ! MHD_ASAN_ACTIVE */
|
||||
/**
|
||||
* Checks whether any know sanitizer is enabled for this build.
|
||||
* zzuf does not work together with sanitizers as both are intercepting
|
||||
* standard library calls.
|
||||
* @return non-zero if any sanitizer is enabled,
|
||||
* zero otherwise
|
||||
*/
|
||||
int
|
||||
MHD_are_sanitizers_enabled_ (void)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef MHD_ASAN_ENABLED_
|
||||
++ret;
|
||||
#endif /* ! MHD_ASAN_ENABLED_ */
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(thread_sanitizer)
|
||||
++ret;
|
||||
#endif
|
||||
#if __has_feature(memory_sanitizer)
|
||||
++ret;
|
||||
#endif
|
||||
#if __has_feature(dataflow_sanitizer)
|
||||
++ret;
|
||||
#endif
|
||||
#else /* ! defined(__has_feature) */
|
||||
#ifdef __SANITIZE_THREAD__
|
||||
++ret;
|
||||
#endif
|
||||
#endif /* ! defined(__has_feature) */
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -44,4 +44,14 @@ MHD_is_avoid_accept4_possible_ (void);
|
||||
void
|
||||
MHD_avoid_accept4_ (struct MHD_Daemon *daemon);
|
||||
|
||||
/**
|
||||
* Checks whether any know sanitizer is enabled for this build.
|
||||
* zzuf does not work together with sanitizers as both are intercepting
|
||||
* standard library calls.
|
||||
* @return non-zero if any sanitizer is enabled,
|
||||
* zero otherwise
|
||||
*/
|
||||
int
|
||||
MHD_are_sanitizers_enabled_ (void);
|
||||
|
||||
#endif /* MHD_DEBUG_FUNCS_H */
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
This file is part of libmicrohttpd
|
||||
Copyright (C) 2008,2016 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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file socat.c
|
||||
* @brief Code to fork-exec zzuf and start the socat process
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif /* !WIN32_LEAN_AND_MEAN */
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* A larger loop count will run more random tests --
|
||||
* which would be good, except that it may take too
|
||||
* long for most user's patience. So this small
|
||||
* value is the default.
|
||||
*/
|
||||
#ifndef _MHD_VHEAVY_TESTS
|
||||
#define LOOP_COUNT 10
|
||||
#else /* ! _MHD_VHEAVY_TESTS */
|
||||
#define LOOP_COUNT 200
|
||||
#endif /* ! _MHD_VHEAVY_TESTS */
|
||||
|
||||
#define CURL_TIMEOUT 50L
|
||||
|
||||
static pid_t zzuf_pid;
|
||||
|
||||
static void
|
||||
zzuf_socat_start ()
|
||||
{
|
||||
int status;
|
||||
char *const args[] = {
|
||||
"zzuf",
|
||||
"--ratio=0.0:0.75",
|
||||
"-n",
|
||||
"-A",
|
||||
"socat",
|
||||
"-lf",
|
||||
"/dev/null",
|
||||
"TCP4-LISTEN:11081,reuseaddr,fork",
|
||||
"TCP4:127.0.0.1:11080",
|
||||
NULL,
|
||||
};
|
||||
zzuf_pid = fork ();
|
||||
if (zzuf_pid == -1)
|
||||
{
|
||||
fprintf (stderr, "fork failed: %s\n", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
if (zzuf_pid != 0)
|
||||
{
|
||||
(void) sleep (1); /* allow zzuf and socat to start */
|
||||
status = 0;
|
||||
if (0 < waitpid (zzuf_pid, &status, WNOHANG))
|
||||
{
|
||||
if (WIFEXITED (status))
|
||||
fprintf (stderr,
|
||||
"zzuf died with status code %d!\n",
|
||||
WEXITSTATUS (status));
|
||||
if (WIFSIGNALED (status))
|
||||
fprintf (stderr,
|
||||
"zzuf died from signal %d!\n", WTERMSIG (status));
|
||||
exit (1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
setpgid (0, 0);
|
||||
execvp ("zzuf", args);
|
||||
fprintf (stderr, "execution of `zzuf' failed: %s\n", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
zzuf_socat_stop ()
|
||||
{
|
||||
int status;
|
||||
if (zzuf_pid != 0)
|
||||
{
|
||||
if (0 != killpg (zzuf_pid, SIGINT))
|
||||
fprintf (stderr, "Failed to killpg: %s\n", strerror (errno));
|
||||
kill (zzuf_pid, SIGINT);
|
||||
waitpid (zzuf_pid, &status, 0);
|
||||
(void) sleep (1); /* allow socat to also die in peace */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* end of socat.c */
|
||||
+1540
-234
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
This file is part of libmicrohttpd
|
||||
Copyright (C) 2007, 2008 Christian Grothoff
|
||||
Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
|
||||
|
||||
libmicrohttpd is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
@@ -19,12 +20,12 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test_get.c
|
||||
* @brief Testcase for libmicrohttpd GET operations
|
||||
* @file testzzuf/test_get.c
|
||||
* @brief Several testcases for libmicrohttpd with input fuzzing
|
||||
* @author Christian Grothoff
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
#include "MHD_config.h"
|
||||
#include "platform.h"
|
||||
#include <curl/curl.h>
|
||||
#include <microhttpd.h>
|
||||
@@ -36,298 +37,1603 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "socat.c"
|
||||
#include "mhd_debug_funcs.h"
|
||||
#include "test_helpers.h"
|
||||
|
||||
#ifndef MHD_STATICSTR_LEN_
|
||||
/**
|
||||
* Determine length of static string / macro strings at compile time.
|
||||
*/
|
||||
#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
|
||||
#endif /* ! MHD_STATICSTR_LEN_ */
|
||||
|
||||
#ifndef CURL_VERSION_BITS
|
||||
#define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z))
|
||||
#endif /* ! CURL_VERSION_BITS */
|
||||
#ifndef CURL_AT_LEAST_VERSION
|
||||
#define CURL_AT_LEAST_VERSION(x,y,z) \
|
||||
(LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z))
|
||||
#endif /* ! CURL_AT_LEAST_VERSION */
|
||||
|
||||
/**
|
||||
* A larger loop count will run more random tests --
|
||||
* which would be good, except that it may take too
|
||||
* long for most user's patience. So this small
|
||||
* value is the default.
|
||||
* Can be redefined by CPPFLAGS=-DLOOP_COUNT=123
|
||||
*/
|
||||
#ifndef LOOP_COUNT
|
||||
#ifndef _MHD_VHEAVY_TESTS
|
||||
#define LOOP_COUNT 10
|
||||
#else /* ! _MHD_HEAVY_TESTS */
|
||||
#define LOOP_COUNT 200
|
||||
#endif /* ! _MHD_HEAVY_TESTS */
|
||||
#endif /* LOOP_COUNT */
|
||||
|
||||
#ifdef _DEBUG
|
||||
/* Uncomment the next line (or use CPPFLAGS) to see all request and response bodies in log */
|
||||
/* #define TEST_PRINT_BODY */
|
||||
/* Uncomment the next line (or use CPPFLAGS) to see all request bodies as they are sent by libcurl */
|
||||
/* #define TEST_PRINT_BODY_RQ 1 */
|
||||
/* Uncomment the next line (or use CPPFLAGS) to see all request bodies as they are received by libcurl */
|
||||
/* #define TEST_PRINT_BODY_RP 1 */
|
||||
#endif /* _DEBUG */
|
||||
|
||||
#define MHD_TIMEOUT 2
|
||||
|
||||
#define CURL_TIMEOUT 5
|
||||
|
||||
/* Global test parameters */
|
||||
static int oneone;
|
||||
static int dry_run;
|
||||
static int use_get;
|
||||
static int use_get_chunked;
|
||||
static int use_put;
|
||||
static int use_put_large;
|
||||
static int use_put_chunked;
|
||||
static int use_post;
|
||||
static int use_post_form;
|
||||
static int use_long_header;
|
||||
static int use_long_uri;
|
||||
static int use_close;
|
||||
|
||||
struct CBC
|
||||
#define TEST_BASE_URI "http:/" "/127.0.0.1/test_uri"
|
||||
|
||||
#define EMPTY_PAGE "Empty page."
|
||||
#define EMPTY_PAGE_ALT "Alternative empty page."
|
||||
#define METHOD_NOT_SUPPORTED "HTTP method is not supported."
|
||||
#define POST_DATA_BROKEN "The POST request is ill-formed."
|
||||
|
||||
#define POST_KEY1 "test"
|
||||
#define POST_VALUE1 "test_post"
|
||||
#define POST_KEY2 "library"
|
||||
#define POST_VALUE2 "GNU libmicrohttpd"
|
||||
#define POST_URLENC_DATA \
|
||||
POST_KEY1 "=" POST_VALUE1 "&" POST_KEY2 "=" "GNU%20libmicrohttpd"
|
||||
|
||||
#define PUT_NORMAL_SIZE 11
|
||||
/* Does not need to be very large as MHD buffer will be made smaller anyway */
|
||||
#define PUT_LARGE_SIZE (4 * 1024)
|
||||
/* The length of "very long" URI and header strings. MHD uses smaller buffer. */
|
||||
#define TEST_STRING_VLONG_LEN 8 * 1024
|
||||
|
||||
|
||||
#if ! CURL_AT_LEAST_VERSION (7,56,0)
|
||||
#define TEST_USE_STATIC_POST_DATA 1
|
||||
static struct curl_httppost *post_first;
|
||||
static struct curl_httppost *post_last;
|
||||
#endif /* ! CURL_AT_LEAST_VERSION(7,56,0) */
|
||||
|
||||
static struct curl_slist *libcurl_long_header;
|
||||
|
||||
/**
|
||||
* Initialise long header for libcurl
|
||||
*
|
||||
* @return non-zero if succeed,
|
||||
* zero if failed
|
||||
*/
|
||||
static int
|
||||
long_header_init (void)
|
||||
{
|
||||
char *buf;
|
||||
size_t pos;
|
||||
size_t size;
|
||||
|
||||
buf = malloc (TEST_STRING_VLONG_LEN + 1);
|
||||
if (NULL == buf)
|
||||
{
|
||||
fprintf (stderr, "malloc() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
return 0;
|
||||
}
|
||||
buf[TEST_STRING_VLONG_LEN] = 0;
|
||||
buf[0] = 'A';
|
||||
memset (buf + 1, 'a', TEST_STRING_VLONG_LEN / 2 - 2);
|
||||
buf[TEST_STRING_VLONG_LEN / 2 - 1] = ':';
|
||||
buf[TEST_STRING_VLONG_LEN / 2] = ' ';
|
||||
memset (buf + TEST_STRING_VLONG_LEN / 2 + 1, 'c',
|
||||
TEST_STRING_VLONG_LEN / 2 - 1);
|
||||
libcurl_long_header = curl_slist_append (NULL, buf);
|
||||
free (buf);
|
||||
if (NULL != libcurl_long_header)
|
||||
return ! 0; /* Success exit point */
|
||||
|
||||
fprintf (stderr, "curl_slist_append() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
return 0; /* Failure exit point */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Globally initialise test environment
|
||||
* @return non-zero if succeed,
|
||||
* zero if failed
|
||||
*/
|
||||
static int
|
||||
test_global_init (void)
|
||||
{
|
||||
libcurl_long_header = NULL;
|
||||
if (CURLE_OK != curl_global_init (CURL_GLOBAL_WIN32))
|
||||
{
|
||||
fprintf (stderr, "curl_global_init() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (long_header_init ())
|
||||
{
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
return 1; /* Success exit point */
|
||||
#else /* ! TEST_USE_STATIC_POST_DATA */
|
||||
post_first = NULL;
|
||||
post_last = NULL;
|
||||
if ((CURL_FORMADD_OK !=
|
||||
curl_formadd (&post_first, &post_last,
|
||||
CURLFORM_PTRNAME, POST_KEY1,
|
||||
CURLFORM_NAMELENGTH,
|
||||
(long) MHD_STATICSTR_LEN_ (POST_KEY1),
|
||||
CURLFORM_PTRCONTENTS, POST_VALUE1,
|
||||
#if CURL_AT_LEAST_VERSION (7,46,0)
|
||||
CURLFORM_CONTENTLEN,
|
||||
(curl_off_t) MHD_STATICSTR_LEN_ (POST_VALUE1),
|
||||
#else /* ! CURL_AT_LEAST_VERSION(7,46,0) */
|
||||
CURLFORM_CONTENTSLENGTH,
|
||||
(long) MHD_STATICSTR_LEN_ (POST_VALUE1),
|
||||
#endif /* ! CURL_AT_LEAST_VERSION(7,46,0) */
|
||||
CURLFORM_END)) ||
|
||||
(CURL_FORMADD_OK !=
|
||||
curl_formadd (&post_first, &post_last,
|
||||
CURLFORM_PTRNAME, POST_KEY2,
|
||||
CURLFORM_NAMELENGTH,
|
||||
(long) MHD_STATICSTR_LEN_ (POST_KEY2),
|
||||
CURLFORM_PTRCONTENTS, POST_VALUE2,
|
||||
#if CURL_AT_LEAST_VERSION (7,46,0)
|
||||
CURLFORM_CONTENTLEN,
|
||||
(curl_off_t) MHD_STATICSTR_LEN_ (POST_VALUE2),
|
||||
#else /* ! CURL_AT_LEAST_VERSION(7,46,0) */
|
||||
CURLFORM_CONTENTSLENGTH,
|
||||
(long) MHD_STATICSTR_LEN_ (POST_VALUE2),
|
||||
#endif /* ! CURL_AT_LEAST_VERSION(7,46,0) */
|
||||
CURLFORM_END)))
|
||||
fprintf (stderr, "curl_formadd() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
else
|
||||
return 1; /* Success exit point */
|
||||
|
||||
if (NULL != post_first)
|
||||
curl_formfree (post_first);
|
||||
curl_slist_free_all (libcurl_long_header);
|
||||
#endif /* ! CURL_AT_LEAST_VERSION(7,56,0) */
|
||||
}
|
||||
curl_global_cleanup ();
|
||||
return 0; /* Failure exit point */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Globally de-initialise test environment
|
||||
*/
|
||||
static void
|
||||
test_global_deinit (void)
|
||||
{
|
||||
#ifdef TEST_USE_STATIC_POST_DATA
|
||||
curl_formfree (post_first);
|
||||
#endif /* TEST_USE_STATIC_POST_DATA */
|
||||
curl_global_cleanup ();
|
||||
if (NULL != libcurl_long_header)
|
||||
curl_slist_free_all (libcurl_long_header);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* libcurl callback parameters for uploads, downloads and debug callbacks
|
||||
*/
|
||||
struct CBC
|
||||
{
|
||||
/* Upload members */
|
||||
size_t up_pos;
|
||||
size_t up_size;
|
||||
/* Download members */
|
||||
char *dn_buf;
|
||||
size_t dn_pos;
|
||||
size_t dn_buf_size;
|
||||
/* Debug callback members */
|
||||
unsigned int excess_found;
|
||||
};
|
||||
|
||||
static void
|
||||
initCBC (struct CBC *libcurlcbc, char *dn_buf, size_t dn_buf_size)
|
||||
{
|
||||
libcurlcbc->up_pos = 0;
|
||||
if (use_put_large)
|
||||
libcurlcbc->up_size = PUT_LARGE_SIZE;
|
||||
else if (use_put)
|
||||
libcurlcbc->up_size = PUT_NORMAL_SIZE;
|
||||
else
|
||||
libcurlcbc->up_size = 0;
|
||||
libcurlcbc->dn_buf = dn_buf;
|
||||
libcurlcbc->dn_pos = 0;
|
||||
libcurlcbc->dn_buf_size = dn_buf_size;
|
||||
libcurlcbc->excess_found = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
resetCBC (struct CBC *libcurlcbc)
|
||||
{
|
||||
libcurlcbc->up_pos = 0;
|
||||
libcurlcbc->dn_pos = 0;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
putBuffer (void *stream, size_t item_size, size_t nitems, void *ctx)
|
||||
{
|
||||
size_t to_fill;
|
||||
size_t i;
|
||||
struct CBC *cbc = ctx;
|
||||
|
||||
to_fill = cbc->up_size - cbc->up_pos;
|
||||
/* Skip overflow check as the return value is valid anyway */
|
||||
if (use_put_chunked)
|
||||
{
|
||||
/* Send data as several chunks */
|
||||
if (to_fill > cbc->up_size / 3)
|
||||
to_fill = cbc->up_size / 3;
|
||||
}
|
||||
if (to_fill > item_size * nitems)
|
||||
to_fill = item_size * nitems;
|
||||
|
||||
/* Avoid libcurl magic numbers */
|
||||
#ifdef CURL_READFUNC_PAUSE
|
||||
if (CURL_READFUNC_ABORT == to_fill)
|
||||
to_fill -= 2;
|
||||
#endif /* CURL_READFUNC_PAUSE */
|
||||
#ifdef CURL_READFUNC_ABORT
|
||||
if (CURL_READFUNC_ABORT == to_fill)
|
||||
--to_fill;
|
||||
#endif /* CURL_READFUNC_ABORT */
|
||||
for (i = 0; i < to_fill; ++i)
|
||||
((char *) stream)[i] = 'a' + (char) ((cbc->up_pos + i)
|
||||
% (unsigned char) ('z' - 'a' + 1));
|
||||
|
||||
cbc->up_pos += to_fill;
|
||||
return to_fill;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
if (cbc->dn_pos + size * nmemb > cbc->dn_buf_size)
|
||||
return 0; /* overflow */
|
||||
memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
|
||||
cbc->pos += size * nmemb;
|
||||
memcpy (&cbc->dn_buf[cbc->dn_pos], ptr, size * nmemb);
|
||||
cbc->dn_pos += size * nmemb;
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
|
||||
static enum MHD_Result
|
||||
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 **req_cls)
|
||||
#define TEST_MAGIC_MARKER0 0xFEE1C0DE
|
||||
#define TEST_MAGIC_MARKER1 (TEST_MAGIC_MARKER0 + 1)
|
||||
#define TEST_MAGIC_MARKER2 (TEST_MAGIC_MARKER0 + 2)
|
||||
|
||||
struct content_cb_param_strct
|
||||
{
|
||||
static int ptr;
|
||||
const char *me = cls;
|
||||
unsigned int magic0; /**< Must have TEST_MAGIC_MARKER0 value */
|
||||
struct MHD_Response *response; /**< The pointer to the response structure */
|
||||
};
|
||||
|
||||
/**
|
||||
* MHD content reader callback that returns
|
||||
* data in chunks.
|
||||
*/
|
||||
static ssize_t
|
||||
content_cb (void *cls, uint64_t pos, char *buf, size_t max)
|
||||
{
|
||||
struct content_cb_param_strct *param = (struct content_cb_param_strct *) cls;
|
||||
size_t fill_size;
|
||||
|
||||
if ((unsigned int) TEST_MAGIC_MARKER0 != param->magic0)
|
||||
{
|
||||
fprintf (stderr, "Wrong cls pointer "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
fflush (stderr);
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (pos >= 128 * 10)
|
||||
{
|
||||
if (MHD_YES !=
|
||||
MHD_add_response_footer (param->response, "Footer", "working"))
|
||||
{
|
||||
fprintf (stderr, "MHD_add_response_footer() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
fflush (stderr);
|
||||
abort ();
|
||||
}
|
||||
return MHD_CONTENT_READER_END_OF_STREAM;
|
||||
}
|
||||
|
||||
if (128 > max)
|
||||
fill_size = 128;
|
||||
else
|
||||
fill_size = max;
|
||||
memset (buf, 'A' + (char) (unsigned int) (pos / 128), fill_size);
|
||||
|
||||
return (ssize_t) fill_size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deallocate memory for callback cls.
|
||||
*/
|
||||
static void
|
||||
crcf (void *ptr)
|
||||
{
|
||||
free (ptr);
|
||||
}
|
||||
|
||||
|
||||
struct req_process_strct
|
||||
{
|
||||
unsigned int magic2; /**< Must have TEST_MAGIC_MARKER2 value */
|
||||
int is_static; /**< Non-zero if statically allocated, zero if malloc()'ed */
|
||||
struct MHD_PostProcessor *postprocsr;
|
||||
unsigned int post_data_sum;
|
||||
};
|
||||
|
||||
static enum MHD_Result
|
||||
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)
|
||||
{
|
||||
struct req_process_strct *param = (struct req_process_strct *) cls;
|
||||
size_t i;
|
||||
|
||||
(void) filename; (void) content_type; (void) transfer_encoding;
|
||||
(void) off; /* Unused. Mute compiler warnings. */
|
||||
|
||||
if (TEST_MAGIC_MARKER2 != param->magic2)
|
||||
{
|
||||
fprintf (stderr, "The 'param->magic2' has wrong value "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (MHD_POSTDATA_KIND != kind)
|
||||
{
|
||||
fprintf (stderr, "The 'kind' parameter has wrong value "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (NULL != key)
|
||||
param->post_data_sum += (unsigned int) strlen (key);
|
||||
|
||||
for (i = 0; size > i; ++i)
|
||||
param->post_data_sum += (unsigned int) (unsigned char) value[i];
|
||||
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_req_pr_data (struct req_process_strct *pr_data)
|
||||
{
|
||||
if (NULL == pr_data)
|
||||
return;
|
||||
if (TEST_MAGIC_MARKER2 != pr_data->magic2)
|
||||
{
|
||||
fprintf (stderr, "The 'pr_data->magic2' has wrong value "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
abort ();
|
||||
}
|
||||
if (pr_data->is_static)
|
||||
{
|
||||
if (NULL != pr_data->postprocsr)
|
||||
{
|
||||
fprintf (stderr, "The 'pr_data->postprocsr' has wrong value "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
abort ();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (NULL != pr_data->postprocsr)
|
||||
MHD_destroy_post_processor (pr_data->postprocsr);
|
||||
pr_data->postprocsr = NULL;
|
||||
free (pr_data);
|
||||
}
|
||||
|
||||
|
||||
struct ahc_param_strct
|
||||
{
|
||||
unsigned int magic1; /**< Must have TEST_MAGIC_MARKER1 value */
|
||||
unsigned int err_flag; /**< Non-zero if any error is encountered */
|
||||
unsigned int num_replies; /**< The number of replies sent for the current request */
|
||||
};
|
||||
|
||||
static enum MHD_Result
|
||||
send_error_response (struct MHD_Connection *connection,
|
||||
struct ahc_param_strct *param,
|
||||
unsigned int status_code,
|
||||
const char *static_text,
|
||||
const size_t static_text_len)
|
||||
{
|
||||
struct MHD_Response *response;
|
||||
response =
|
||||
MHD_create_response_from_buffer_static (static_text_len,
|
||||
static_text);
|
||||
if (NULL != response)
|
||||
{
|
||||
if (MHD_YES == MHD_add_response_header (response,
|
||||
MHD_HTTP_HEADER_CONNECTION,
|
||||
"close"))
|
||||
{
|
||||
if (MHD_YES == MHD_queue_response (connection, status_code, response))
|
||||
{
|
||||
MHD_destroy_response (response);
|
||||
return MHD_YES; /* Success exit point */
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "MHD_queue_response() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "MHD_add_response_header() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
MHD_destroy_response (response);
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "MHD_create_response_from_callback() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
|
||||
param->err_flag = 1;
|
||||
return MHD_NO; /* Failure exit point */
|
||||
}
|
||||
|
||||
|
||||
static enum MHD_Result
|
||||
ahc_check (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 **req_cls)
|
||||
{
|
||||
static struct req_process_strct static_req_pr_data = {
|
||||
TEST_MAGIC_MARKER2, ! 0, NULL, 0
|
||||
};
|
||||
struct req_process_strct *req_pr_data;
|
||||
struct ahc_param_strct *param = (struct ahc_param_strct *) cls;
|
||||
struct MHD_Response *response;
|
||||
enum MHD_Result ret;
|
||||
(void) version; (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */
|
||||
unsigned char data_sum;
|
||||
int is_post_req;
|
||||
|
||||
if (NULL == url)
|
||||
fprintf (stderr, "The \"url\" parameter is NULL.\n");
|
||||
if (NULL == method)
|
||||
fprintf (stderr, "The \"method\" parameter is NULL.\n");
|
||||
if (NULL == version)
|
||||
fprintf (stderr, "The \"version\" parameter is NULL.\n");
|
||||
if (NULL == upload_data_size)
|
||||
fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
|
||||
if ((0 != *upload_data_size) && (NULL == upload_data))
|
||||
fprintf (stderr, "Upload data is NULL with non-zero size.\n");
|
||||
if (0 != strcmp (me, method))
|
||||
return MHD_NO; /* unexpected method */
|
||||
if (&ptr != *req_cls)
|
||||
if (NULL == cls)
|
||||
{
|
||||
*req_cls = &ptr;
|
||||
fprintf (stderr, "The 'cls' parameter is NULL "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
fflush (stderr);
|
||||
abort ();
|
||||
}
|
||||
if ((unsigned int) TEST_MAGIC_MARKER1 != param->magic1)
|
||||
{
|
||||
fprintf (stderr, "The 'param->magic1' has wrong value "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
fflush (stderr);
|
||||
abort ();
|
||||
}
|
||||
if (NULL == connection)
|
||||
{
|
||||
fprintf (stderr, "The 'connection' parameter is NULL "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
return MHD_NO; /* Should not reply */
|
||||
}
|
||||
if (1)
|
||||
{ /* Simple check for 'connection' parameter validity */
|
||||
const union MHD_ConnectionInfo *conn_info;
|
||||
conn_info =
|
||||
MHD_get_connection_info (connection,
|
||||
MHD_CONNECTION_INFO_CONNECTION_TIMEOUT);
|
||||
if (NULL == conn_info)
|
||||
{
|
||||
fprintf (stderr, "The 'MHD_get_connection_info' has returned NULL "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
}
|
||||
else if (MHD_TIMEOUT != conn_info->connection_timeout)
|
||||
{
|
||||
fprintf (stderr, "The 'MHD_get_connection_info' has returned "
|
||||
"unexpected timeout value "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
}
|
||||
}
|
||||
if (NULL == url)
|
||||
{
|
||||
fprintf (stderr, "The 'url' parameter is NULL "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
}
|
||||
if (NULL == method)
|
||||
{
|
||||
fprintf (stderr, "The 'method' parameter is NULL "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
return MHD_NO; /* Should not reply */
|
||||
}
|
||||
if (NULL == version)
|
||||
{
|
||||
fprintf (stderr, "The 'version' parameter is NULL "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
return MHD_NO; /* Should not reply */
|
||||
}
|
||||
if (NULL == upload_data_size)
|
||||
{
|
||||
fprintf (stderr, "The 'upload_data_size' parameter is NULL "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
return MHD_NO; /* Should not reply */
|
||||
}
|
||||
if ((0 != *upload_data_size) && (NULL == upload_data))
|
||||
{
|
||||
fprintf (stderr, "The 'upload_data' parameter is NULL "
|
||||
"while '*upload_data_size' is not zero "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
return MHD_NO; /* Should not reply */
|
||||
}
|
||||
if ((NULL != upload_data) && (0 == *upload_data_size))
|
||||
{
|
||||
fprintf (stderr, "The 'upload_data' parameter is NOT NULL "
|
||||
"while '*upload_data_size' is zero "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
return MHD_NO; /* Should not reply */
|
||||
}
|
||||
|
||||
if (0 != param->num_replies)
|
||||
{
|
||||
/* Phantom "second" request due to the fuzzing of the input. Refuse. */
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
is_post_req = (0 == strcmp (method, MHD_HTTP_METHOD_POST));
|
||||
if ((0 != strcmp (method, MHD_HTTP_METHOD_GET))
|
||||
&& (0 != strcmp (method, MHD_HTTP_METHOD_HEAD))
|
||||
&& (0 != strcmp (method, MHD_HTTP_METHOD_PUT))
|
||||
&& (! is_post_req))
|
||||
{
|
||||
/* Unsupported method for this callback */
|
||||
return send_error_response (connection, param, MHD_HTTP_NOT_IMPLEMENTED,
|
||||
METHOD_NOT_SUPPORTED,
|
||||
MHD_STATICSTR_LEN_ (METHOD_NOT_SUPPORTED));
|
||||
}
|
||||
|
||||
if (NULL == *req_cls)
|
||||
{
|
||||
if (! is_post_req)
|
||||
{ /* Use static memory */
|
||||
*req_cls = &static_req_pr_data;
|
||||
}
|
||||
else
|
||||
{ /* POST request, use PostProcessor */
|
||||
req_pr_data =
|
||||
(struct req_process_strct *) malloc (sizeof (struct req_process_strct));
|
||||
if (NULL == req_pr_data)
|
||||
{
|
||||
fprintf (stderr, "malloc() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
return MHD_NO;
|
||||
}
|
||||
req_pr_data->magic2 = TEST_MAGIC_MARKER2;
|
||||
req_pr_data->is_static = 0;
|
||||
req_pr_data->post_data_sum = 0;
|
||||
req_pr_data->postprocsr = MHD_create_post_processor (connection, 1024,
|
||||
&post_iterator,
|
||||
req_pr_data);
|
||||
if (NULL == req_pr_data->postprocsr)
|
||||
{
|
||||
free (req_pr_data);
|
||||
if (NULL == upload_data)
|
||||
return send_error_response (connection, param, MHD_HTTP_BAD_REQUEST,
|
||||
POST_DATA_BROKEN,
|
||||
MHD_STATICSTR_LEN_ (POST_DATA_BROKEN));
|
||||
else
|
||||
return MHD_NO; /* Cannot handle request, broken POST */
|
||||
}
|
||||
*req_cls = req_pr_data;
|
||||
}
|
||||
if (NULL == upload_data)
|
||||
return MHD_YES;
|
||||
}
|
||||
req_pr_data = (struct req_process_strct *) *req_cls;
|
||||
|
||||
data_sum = 0;
|
||||
if (NULL != upload_data)
|
||||
{
|
||||
if (is_post_req)
|
||||
{
|
||||
if (MHD_YES != MHD_post_process (req_pr_data->postprocsr,
|
||||
upload_data, *upload_data_size))
|
||||
{
|
||||
free_req_pr_data (req_pr_data);
|
||||
*req_cls = NULL;
|
||||
/* Processing upload body (context), error reply cannot be queued here */
|
||||
return MHD_NO;
|
||||
}
|
||||
*upload_data_size = 0; /* All data have been processed */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check that all 'upload_data' is addressable */
|
||||
size_t pos;
|
||||
for (pos = 0; pos < *upload_data_size; ++pos)
|
||||
data_sum += (unsigned char) upload_data[pos];
|
||||
if (0 != *upload_data_size)
|
||||
{
|
||||
if (3 >= *upload_data_size)
|
||||
*upload_data_size = 0; /* Consume all incoming data */
|
||||
else
|
||||
*upload_data_size = data_sum % *upload_data_size; /* Pseudo-random */
|
||||
}
|
||||
}
|
||||
return MHD_YES;
|
||||
}
|
||||
if (is_post_req)
|
||||
{
|
||||
if (MHD_YES != MHD_destroy_post_processor (req_pr_data->postprocsr))
|
||||
{
|
||||
free (req_pr_data);
|
||||
*req_cls = NULL;
|
||||
return send_error_response (connection, param, MHD_HTTP_BAD_REQUEST,
|
||||
POST_DATA_BROKEN,
|
||||
MHD_STATICSTR_LEN_ (POST_DATA_BROKEN));
|
||||
}
|
||||
req_pr_data->postprocsr = NULL;
|
||||
}
|
||||
data_sum += (unsigned char) req_pr_data->post_data_sum;
|
||||
free_req_pr_data (req_pr_data);
|
||||
*req_cls = 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)
|
||||
|
||||
ret = MHD_YES;
|
||||
if (use_get_chunked)
|
||||
{
|
||||
struct content_cb_param_strct *cnt_cb_param;
|
||||
cnt_cb_param = malloc (sizeof (struct content_cb_param_strct));
|
||||
if (NULL == cnt_cb_param)
|
||||
{
|
||||
fprintf (stderr, "malloc() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
/* External error, do not rise the error flag */
|
||||
return MHD_NO;
|
||||
}
|
||||
cnt_cb_param->magic0 = (unsigned int) TEST_MAGIC_MARKER0;
|
||||
response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
|
||||
1024,
|
||||
&content_cb, cnt_cb_param,
|
||||
&crcf);
|
||||
if (NULL == response)
|
||||
{
|
||||
fprintf (stderr, "MHD_create_response_from_callback() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
free (cnt_cb_param);
|
||||
param->err_flag = 1;
|
||||
ret = MHD_NO;
|
||||
}
|
||||
else
|
||||
cnt_cb_param->response = response;
|
||||
}
|
||||
else if (use_get || use_put || use_post)
|
||||
{
|
||||
/* Randomly choose the response page for the POST requests */
|
||||
if (0 == data_sum % 2)
|
||||
response =
|
||||
MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (EMPTY_PAGE),
|
||||
EMPTY_PAGE);
|
||||
else
|
||||
response =
|
||||
MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ ( \
|
||||
EMPTY_PAGE_ALT),
|
||||
EMPTY_PAGE_ALT);
|
||||
|
||||
if (NULL == response)
|
||||
{
|
||||
fprintf (stderr, "MHD_create_response_from_buffer_static() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
ret = MHD_NO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Response is not implemented for this test. "
|
||||
"Internal logic is broken. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (NULL != response)
|
||||
{
|
||||
if ((MHD_YES == ret) &&
|
||||
(use_close || (! oneone && (0 != strcmp (version,
|
||||
MHD_HTTP_VERSION_1_0)))))
|
||||
{
|
||||
ret = MHD_add_response_header (response,
|
||||
MHD_HTTP_HEADER_CONNECTION,
|
||||
"close");
|
||||
if (MHD_YES != ret)
|
||||
{
|
||||
fprintf (stderr, "MHD_add_response_header() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
}
|
||||
}
|
||||
if (MHD_YES == ret)
|
||||
{
|
||||
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
|
||||
if (MHD_YES != ret)
|
||||
{
|
||||
fprintf (stderr, "MHD_queue_response() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
param->num_replies++;
|
||||
|
||||
MHD_destroy_response (response);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "MHD_create_response_from_buffer_static() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
ret = MHD_NO;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
req_completed_cleanup (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
void **req_cls,
|
||||
enum MHD_RequestTerminationCode toe)
|
||||
{
|
||||
struct ahc_param_strct *param = (struct ahc_param_strct *) cls;
|
||||
struct req_process_strct *req_pr_data = (struct req_process_strct *) *req_cls;
|
||||
(void) connection; /* Unused. Mute compiler warning. */
|
||||
|
||||
if (NULL == param)
|
||||
{
|
||||
fprintf (stderr, "The 'cls' parameter is NULL at line %d.\n",
|
||||
(int) __LINE__);
|
||||
fflush (stderr);
|
||||
abort ();
|
||||
}
|
||||
if ((unsigned int) TEST_MAGIC_MARKER1 != param->magic1)
|
||||
{
|
||||
fprintf (stderr, "The 'param->magic1' has wrong value at line %d.\n",
|
||||
(int) __LINE__);
|
||||
fflush (stderr);
|
||||
abort ();
|
||||
}
|
||||
if (NULL == req_pr_data)
|
||||
return; /* The data have been freed */
|
||||
if ((unsigned int) TEST_MAGIC_MARKER2 != req_pr_data->magic2)
|
||||
{
|
||||
fprintf (stderr, "The 'req_pr_data->magic2' has wrong value at line %d.\n",
|
||||
(int) __LINE__);
|
||||
fflush (stderr);
|
||||
abort ();
|
||||
}
|
||||
if (MHD_REQUEST_TERMINATED_COMPLETED_OK == toe)
|
||||
{
|
||||
fprintf (stderr, "The request completed successful, but request cls has"
|
||||
"not been cleared. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
param->err_flag = 1;
|
||||
}
|
||||
if (req_pr_data->is_static)
|
||||
return;
|
||||
if (NULL != req_pr_data->postprocsr)
|
||||
MHD_destroy_post_processor (req_pr_data->postprocsr);
|
||||
req_pr_data->postprocsr = NULL;
|
||||
free (req_pr_data);
|
||||
*req_cls = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Un-comment the next line (or use CPPFLAGS) to avoid
|
||||
logging of the traffic with debug builds */
|
||||
/* #define TEST_NO_PRINT_TRAFFIC 1 */
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef TEST_PRINT_BODY
|
||||
#ifndef TEST_PRINT_BODY_RQ
|
||||
#define TEST_PRINT_BODY_RQ 1
|
||||
#endif /* TEST_PRINT_BODY_RQ */
|
||||
#ifndef TEST_PRINT_BODY_RP
|
||||
#define TEST_PRINT_BODY_RP 1
|
||||
#endif /* TEST_PRINT_BODY_RP */
|
||||
#endif /* TEST_PRINT_BODY */
|
||||
#endif /* _DEBUG */
|
||||
|
||||
static int
|
||||
libcurl_debug_cb (CURL *handle,
|
||||
curl_infotype type,
|
||||
char *data,
|
||||
size_t size,
|
||||
void *ctx)
|
||||
{
|
||||
static const char excess_mark[] = "Excess found";
|
||||
static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark);
|
||||
struct CBC *cbc = ctx;
|
||||
(void) handle;
|
||||
|
||||
#if defined(_DEBUG) && ! defined(TEST_NO_PRINT_TRAFFIC)
|
||||
switch (type)
|
||||
{
|
||||
case CURLINFO_TEXT:
|
||||
fprintf (stderr, "* %.*s", (int) size, data);
|
||||
break;
|
||||
case CURLINFO_HEADER_IN:
|
||||
fprintf (stderr, "< %.*s", (int) size, data);
|
||||
break;
|
||||
case CURLINFO_HEADER_OUT:
|
||||
fprintf (stderr, "> %.*s", (int) size, data);
|
||||
break;
|
||||
case CURLINFO_DATA_IN:
|
||||
#ifdef TEST_PRINT_BODY_RP
|
||||
fprintf (stderr, "<| %.*s\n", (int) size, data);
|
||||
#endif /* TEST_PRINT_BODY_RP */
|
||||
break;
|
||||
case CURLINFO_DATA_OUT:
|
||||
#ifdef TEST_PRINT_BODY_RQ
|
||||
fprintf (stderr, ">| %.*s\n", (int) size, data);
|
||||
#endif /* TEST_PRINT_BODY_RQ */
|
||||
break;
|
||||
case CURLINFO_SSL_DATA_IN:
|
||||
case CURLINFO_SSL_DATA_OUT:
|
||||
case CURLINFO_END:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* _DEBUG && ! TEST_NO_PRINT_TRAFFIC */
|
||||
if (use_close || ! oneone)
|
||||
{
|
||||
/* Check for extra data only if every connection is terminated by MHD
|
||||
after one request, otherwise MHD may react on garbage after request
|
||||
data. */
|
||||
if (CURLINFO_TEXT == type)
|
||||
{
|
||||
if ((size >= excess_mark_len) &&
|
||||
(0 == memcmp (data, excess_mark, excess_mark_len)))
|
||||
{
|
||||
fprintf (stderr, "Extra data has been detected in MHD reply "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
cbc->excess_found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static CURL *
|
||||
setupCURL (struct CBC *cbc, uint16_t port
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
, curl_mime **mime
|
||||
#endif /* ! TEST_USE_STATIC_POST_DATA */
|
||||
)
|
||||
{
|
||||
CURL *c;
|
||||
CURLcode e;
|
||||
char *buf;
|
||||
const char *uri_to_use;
|
||||
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
*mime = NULL;
|
||||
#endif /* ! TEST_USE_STATIC_POST_DATA */
|
||||
|
||||
if (! use_long_uri)
|
||||
{
|
||||
uri_to_use = TEST_BASE_URI;
|
||||
buf = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t pos;
|
||||
buf = malloc (TEST_STRING_VLONG_LEN + 1);
|
||||
if (NULL == buf)
|
||||
{
|
||||
fprintf (stderr, "malloc() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
memcpy (buf, TEST_BASE_URI, MHD_STATICSTR_LEN_ (TEST_BASE_URI));
|
||||
for (pos = MHD_STATICSTR_LEN_ (TEST_BASE_URI);
|
||||
pos < TEST_STRING_VLONG_LEN;
|
||||
++pos)
|
||||
{
|
||||
if (0 == pos % 9)
|
||||
buf[pos] = '/';
|
||||
else
|
||||
buf[pos] = 'a' + (char) (unsigned char) (pos % ((unsigned char)
|
||||
('z' - 'a' + 1)));
|
||||
}
|
||||
buf[TEST_STRING_VLONG_LEN] = 0;
|
||||
uri_to_use = buf;
|
||||
}
|
||||
|
||||
c = curl_easy_init ();
|
||||
if (NULL == c)
|
||||
{
|
||||
fprintf (stderr, "curl_easy_init() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_URL,
|
||||
uri_to_use))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
|
||||
©Buffer))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
|
||||
((long) CURL_TIMEOUT)))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
|
||||
oneone ?
|
||||
CURL_HTTP_VERSION_1_1 :
|
||||
CURL_HTTP_VERSION_1_0))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_TIMEOUT,
|
||||
((long) CURL_TIMEOUT)))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L))) &&
|
||||
#ifdef _DEBUG
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_VERBOSE, 1L))) &&
|
||||
#endif /* _DEBUG */
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION,
|
||||
&libcurl_debug_cb))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_DEBUGDATA,
|
||||
cbc))) &&
|
||||
#if CURL_AT_LEAST_VERSION (7, 19, 4)
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_PROTOCOLS,
|
||||
CURLPROTO_HTTP))) &&
|
||||
#endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
|
||||
#if CURL_AT_LEAST_VERSION (7, 45, 0)
|
||||
(CURLE_OK == (e = curl_easy_setopt (c,
|
||||
CURLOPT_DEFAULT_PROTOCOL, "http"))) &&
|
||||
#endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */
|
||||
#if CURL_AT_LEAST_VERSION (7, 24, 0)
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INTERFACE,
|
||||
"host!127.0.0.101"))) &&
|
||||
#else /* ! CURL_AT_LEAST_VERSION (7, 24, 0) */
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INTERFACE,
|
||||
"127.0.0.101"))) &&
|
||||
#endif /* ! CURL_AT_LEAST_VERSION (7, 24, 0) */
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_PORT, ((long) port)))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_HTTPHEADER,
|
||||
use_long_header ?
|
||||
libcurl_long_header : NULL)))
|
||||
)
|
||||
{
|
||||
if (NULL != buf)
|
||||
{
|
||||
free (buf);
|
||||
buf = NULL;
|
||||
}
|
||||
if (use_put)
|
||||
{
|
||||
if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_READFUNCTION,
|
||||
&putBuffer))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_READDATA, cbc))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_UPLOAD, (long) 1))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE,
|
||||
use_put_chunked ?
|
||||
((curl_off_t) -1) :
|
||||
((curl_off_t) cbc->up_size)))))
|
||||
{
|
||||
return c; /* Success exit point for 'use_put' */
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "PUT-related curl_easy_setopt() failed at line %d, "
|
||||
"error: %s\n", (int) __LINE__,
|
||||
curl_easy_strerror (e));
|
||||
}
|
||||
else if (use_post)
|
||||
{
|
||||
if (! use_post_form)
|
||||
{
|
||||
if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_POST, (long) 1))) &&
|
||||
(CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_POSTFIELDS,
|
||||
POST_URLENC_DATA))) &&
|
||||
(CURLE_OK ==
|
||||
(e = curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE,
|
||||
MHD_STATICSTR_LEN_ (POST_URLENC_DATA)))))
|
||||
{
|
||||
return c; /* Success exit point for 'use_post' */
|
||||
}
|
||||
else
|
||||
fprintf (stderr,
|
||||
"POST-related curl_easy_setopt() failed at line %d, "
|
||||
"error: %s\n", (int) __LINE__,
|
||||
curl_easy_strerror (e));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
*mime = curl_mime_init (c);
|
||||
if (NULL != *mime)
|
||||
{
|
||||
curl_mimepart *part;
|
||||
if ((NULL != (part = curl_mime_addpart (*mime))) &&
|
||||
(CURLE_OK == curl_mime_name (part, POST_KEY1)) &&
|
||||
(CURLE_OK == curl_mime_data (part, POST_VALUE1,
|
||||
MHD_STATICSTR_LEN_ (POST_VALUE1))) &&
|
||||
(NULL != (part = curl_mime_addpart (*mime))) &&
|
||||
(CURLE_OK == curl_mime_name (part, POST_KEY2)) &&
|
||||
(CURLE_OK == curl_mime_data (part, POST_VALUE2,
|
||||
MHD_STATICSTR_LEN_ (POST_VALUE2))))
|
||||
{
|
||||
if (CURLE_OK ==
|
||||
(e = curl_easy_setopt (c, CURLOPT_MIMEPOST, *mime)))
|
||||
return c; /* Success exit point for 'use_post' */
|
||||
else
|
||||
fprintf (stderr, "curl_easy_setopt(c, CURLOPT_MIMEPOST, mime) "
|
||||
"failed at line %d, error: %s\n",
|
||||
(int) __LINE__, curl_easy_strerror (e));
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "curl_mime_addpart(), curl_mime_name() or "
|
||||
"curl_mime_data() failed.\n");
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "curl_mime_init() failed.\n");
|
||||
|
||||
#else /* TEST_USE_STATIC_POST_DATA */
|
||||
if (CURLE_OK == (e = curl_easy_setopt (c,
|
||||
CURLOPT_HTTPPOST, post_first)))
|
||||
{
|
||||
return c; /* Success exit point for 'use_post' */
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "POST form-related curl_easy_setopt() failed, "
|
||||
"error: %s\n", curl_easy_strerror (e));
|
||||
#endif /* TEST_USE_STATIC_POST_DATA */
|
||||
}
|
||||
}
|
||||
else
|
||||
return c; /* Success exit point */
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "curl_easy_setopt() failed at line %d, "
|
||||
"error: %s\n", (int) __LINE__,
|
||||
curl_easy_strerror (e));
|
||||
|
||||
curl_easy_cleanup (c);
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
if (NULL != *mime)
|
||||
curl_mime_free (*mime);
|
||||
#endif /* ! TEST_USE_STATIC_POST_DATA */
|
||||
|
||||
if (NULL != buf)
|
||||
free (buf);
|
||||
|
||||
return NULL; /* Failure exit point */
|
||||
}
|
||||
|
||||
|
||||
static struct MHD_Daemon *
|
||||
start_daemon_for_test (unsigned int daemon_flags, uint16_t *pport,
|
||||
struct ahc_param_strct *callback_param)
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
struct MHD_OptionItem ops[] = {
|
||||
{ MHD_OPTION_END, 0, NULL },
|
||||
{ MHD_OPTION_END, 0, NULL }
|
||||
};
|
||||
callback_param->magic1 = (unsigned int) TEST_MAGIC_MARKER1;
|
||||
callback_param->err_flag = 0;
|
||||
callback_param->num_replies = 0;
|
||||
|
||||
if (use_put_large)
|
||||
{
|
||||
ops[0].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT;
|
||||
ops[0].value = (intptr_t) (PUT_LARGE_SIZE / 4);
|
||||
}
|
||||
else if (use_long_header || use_long_uri)
|
||||
{
|
||||
ops[0].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT;
|
||||
ops[0].value = (intptr_t) (TEST_STRING_VLONG_LEN / 2);
|
||||
}
|
||||
d = MHD_start_daemon (daemon_flags /* | MHD_USE_ERROR_LOG */,
|
||||
*pport, NULL, NULL,
|
||||
&ahc_check, callback_param,
|
||||
MHD_OPTION_CONNECTION_TIMEOUT,
|
||||
(unsigned int) MHD_TIMEOUT,
|
||||
MHD_OPTION_NOTIFY_COMPLETED,
|
||||
&req_completed_cleanup, callback_param,
|
||||
MHD_OPTION_ARRAY, ops,
|
||||
MHD_OPTION_END);
|
||||
if (NULL == d)
|
||||
{
|
||||
fprintf (stderr, "MHD_start_daemon() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
/* Do not use accept4() as only accept() is intercepted by zzuf */
|
||||
MHD_avoid_accept4_ (d);
|
||||
|
||||
if (0 == *pport)
|
||||
{
|
||||
const union MHD_DaemonInfo *dinfo;
|
||||
|
||||
dinfo = MHD_get_daemon_info (d,
|
||||
MHD_DAEMON_INFO_BIND_PORT);
|
||||
if ( (NULL == dinfo) ||
|
||||
(0 == dinfo->port) )
|
||||
{
|
||||
fprintf (stderr, "MHD_get_daemon_info() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
MHD_stop_daemon (d);
|
||||
return NULL;
|
||||
}
|
||||
*pport = dinfo->port;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_test_starting (unsigned int daemon_flags)
|
||||
{
|
||||
fflush (stderr);
|
||||
if (0 != (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags))
|
||||
{
|
||||
if (0 != (MHD_USE_THREAD_PER_CONNECTION & daemon_flags))
|
||||
{
|
||||
if (0 != (MHD_USE_POLL & daemon_flags))
|
||||
printf ("\nStarting test with internal polling by poll() and "
|
||||
"thread-per-connection.\n");
|
||||
else
|
||||
printf ("\nStarting test with internal polling by select() and "
|
||||
"thread-per-connection.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 != (MHD_USE_POLL & daemon_flags))
|
||||
printf ("\nStarting test with internal polling by poll().\n");
|
||||
else if (0 != (MHD_USE_EPOLL & daemon_flags))
|
||||
printf ("\nStarting test with internal polling by 'epoll'.\n");
|
||||
else
|
||||
printf ("\nStarting test with internal polling by select().\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 != (MHD_USE_EPOLL & daemon_flags))
|
||||
printf ("\nStarting test with external polling and internal 'epoll'.\n");
|
||||
else
|
||||
printf ("\nStarting test with external polling.\n");
|
||||
}
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testInternalPolling (uint16_t *pport, unsigned int daemon_flags)
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
struct ahc_param_strct callback_param;
|
||||
unsigned int ret;
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
curl_mime *mime;
|
||||
#endif /* ! TEST_USE_STATIC_POST_DATA */
|
||||
|
||||
if (0 == (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags))
|
||||
{
|
||||
fprintf (stderr, "Wrong internal flags, the test is broken. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
abort (); /* Wrong flags, error in code */
|
||||
}
|
||||
|
||||
print_test_starting (daemon_flags);
|
||||
initCBC (&cbc, buf, sizeof(buf));
|
||||
d = start_daemon_for_test (daemon_flags, pport, &callback_param);
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
|
||||
ret = 0;
|
||||
c = setupCURL (&cbc, *pport
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
, &mime
|
||||
#endif /* ! TEST_USE_STATIC_POST_DATA */
|
||||
);
|
||||
if (NULL != c)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = dry_run ? LOOP_COUNT : 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
callback_param.num_replies = 0;
|
||||
resetCBC (&cbc);
|
||||
/* Run libcurl without checking the result */
|
||||
curl_easy_perform (c);
|
||||
fflush (stderr);
|
||||
}
|
||||
curl_easy_cleanup (c);
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
if (NULL != mime)
|
||||
curl_mime_free (mime);
|
||||
#endif /* ! TEST_USE_STATIC_POST_DATA */
|
||||
}
|
||||
else
|
||||
ret = 99; /* Not an MHD error */
|
||||
|
||||
if ((0 == ret) && callback_param.err_flag)
|
||||
{
|
||||
fprintf (stderr, "One or more errors have been detected by "
|
||||
"access handler callback function. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
ret = 1;
|
||||
}
|
||||
else if ((0 == ret) && cbc.excess_found)
|
||||
{
|
||||
fprintf (stderr, "The extra reply data have been detected one "
|
||||
"or more times. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
MHD_stop_daemon (d);
|
||||
fflush (stderr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testInternalGet ()
|
||||
testExternalPolling (uint16_t *pport, unsigned int daemon_flags)
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
CURLM *multi;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
int i;
|
||||
struct ahc_param_strct callback_param;
|
||||
unsigned int ret;
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
curl_mime *mime;
|
||||
#endif /* ! TEST_USE_STATIC_POST_DATA */
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d =
|
||||
MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
|
||||
if (0 != (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags))
|
||||
{
|
||||
fprintf (stderr, "Wrong internal flags, the test is broken. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
abort (); /* Wrong flags, error in code */
|
||||
}
|
||||
|
||||
print_test_starting (daemon_flags);
|
||||
initCBC (&cbc, buf, sizeof(buf));
|
||||
d = start_daemon_for_test (daemon_flags, pport, &callback_param);
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
|
||||
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, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testMultithreadedGet ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
|
||||
| MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 16;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned 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;
|
||||
int max;
|
||||
int running;
|
||||
time_t start;
|
||||
struct timeval tv;
|
||||
int i;
|
||||
|
||||
multi = NULL;
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 256;
|
||||
ret = 0;
|
||||
multi = curl_multi_init ();
|
||||
if (multi == NULL)
|
||||
{
|
||||
MHD_stop_daemon (d);
|
||||
return 512;
|
||||
fprintf (stderr, "curl_multi_init() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
ret = 99; /* Not an MHD error */
|
||||
}
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
else
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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_FAILONERROR, 1L);
|
||||
if (oneone)
|
||||
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
CURL *c;
|
||||
c = setupCURL (&cbc, *pport
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
, &mime
|
||||
#endif /* ! TEST_USE_STATIC_POST_DATA */
|
||||
);
|
||||
|
||||
if (NULL == c)
|
||||
ret = 99; /* Not an MHD error */
|
||||
else
|
||||
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
mret = curl_multi_add_handle (multi, c);
|
||||
if (mret != CURLM_OK)
|
||||
{
|
||||
curl_multi_cleanup (multi);
|
||||
curl_easy_cleanup (c);
|
||||
zzuf_socat_stop ();
|
||||
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)
|
||||
int i;
|
||||
|
||||
for (i = dry_run ? LOOP_COUNT : 0;
|
||||
(i < LOOP_COUNT) && (0 == ret); i++)
|
||||
{
|
||||
curl_multi_remove_handle (multi, c);
|
||||
curl_multi_cleanup (multi);
|
||||
curl_easy_cleanup (c);
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 2048;
|
||||
CURLMcode mret;
|
||||
|
||||
/* The same 'multi' handle will be used in transfers so
|
||||
connection will be reused.
|
||||
The same 'easy' handle is added (and removed later) to (re-)start
|
||||
the same transfer. */
|
||||
mret = curl_multi_add_handle (multi, c);
|
||||
if (CURLM_OK != mret)
|
||||
{
|
||||
fprintf (stderr, "curl_multi_add_handle() failed at %d, "
|
||||
"error: %s\n", (int) __LINE__,
|
||||
curl_multi_strerror (mret));
|
||||
ret = 99; /* Not an MHD error */
|
||||
}
|
||||
else
|
||||
{
|
||||
time_t start;
|
||||
|
||||
fprintf (stderr, ".");
|
||||
callback_param.num_replies = 0;
|
||||
resetCBC (&cbc);
|
||||
start = time (NULL);
|
||||
do
|
||||
{
|
||||
fd_set rs;
|
||||
fd_set ws;
|
||||
fd_set es;
|
||||
int maxfd_curl;
|
||||
MHD_socket maxfd_mhd;
|
||||
int maxfd;
|
||||
int running;
|
||||
struct timeval tv;
|
||||
|
||||
maxfd_curl = 0;
|
||||
maxfd_mhd = MHD_INVALID_SOCKET;
|
||||
FD_ZERO (&rs);
|
||||
FD_ZERO (&ws);
|
||||
FD_ZERO (&es);
|
||||
curl_multi_perform (multi, &running);
|
||||
if (0 == running)
|
||||
{
|
||||
int msgs_left;
|
||||
do
|
||||
{
|
||||
(void) curl_multi_info_read (multi, &msgs_left);
|
||||
} while (0 != msgs_left);
|
||||
break; /* The transfer has been finished */
|
||||
}
|
||||
mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxfd_curl);
|
||||
if (CURLM_OK != mret)
|
||||
{
|
||||
fprintf (stderr, "curl_multi_fdset() failed at line %d, "
|
||||
"error: %s\n", (int) __LINE__,
|
||||
curl_multi_strerror (mret));
|
||||
ret = 99; /* Not an MHD error */
|
||||
break;
|
||||
}
|
||||
if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxfd_mhd))
|
||||
{
|
||||
fprintf (stderr, "MHD_get_fdset() failed "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
#ifndef MHD_WINSOCK_SOCKETS
|
||||
if ((int) maxfd_mhd > maxfd_curl)
|
||||
maxfd = (int) maxfd_mhd;
|
||||
else
|
||||
#endif /* ! MHD_WINSOCK_SOCKETS */
|
||||
maxfd = maxfd_curl;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100 * 1000;
|
||||
if (0 == MHD_get_timeout64s (d))
|
||||
tv.tv_usec = 0;
|
||||
else
|
||||
{
|
||||
long curl_to = -1;
|
||||
curl_multi_timeout (multi, &curl_to);
|
||||
if (0 == curl_to)
|
||||
tv.tv_usec = 0;
|
||||
}
|
||||
if (-1 == select (maxfd + 1, &rs, &ws, &es, &tv))
|
||||
{
|
||||
#ifdef MHD_POSIX_SOCKETS
|
||||
if (EINTR != errno)
|
||||
fprintf (stderr, "Unexpected select() error "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
#else /* ! MHD_POSIX_SOCKETS */
|
||||
if ((WSAEINVAL != WSAGetLastError ()) ||
|
||||
(0 != rs.fd_count) || (0 != ws.fd_count) ||
|
||||
(0 != es.fd_count))
|
||||
fprintf (stderr, "Unexpected select() error "
|
||||
"at line %d.\n", (int) __LINE__);
|
||||
Sleep ((unsigned long) tv.tv_usec / 1000);
|
||||
#endif /* ! MHD_POSIX_SOCKETS */
|
||||
}
|
||||
MHD_run (d);
|
||||
} while (time (NULL) - start <= MHD_TIMEOUT);
|
||||
/* Remove 'easy' handle from 'multi' handle to
|
||||
* restart the transfer or to finish. */
|
||||
curl_multi_remove_handle (multi, c);
|
||||
}
|
||||
}
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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)
|
||||
{
|
||||
curl_multi_info_read (multi, &running);
|
||||
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);
|
||||
}
|
||||
curl_multi_cleanup (multi);
|
||||
#ifndef TEST_USE_STATIC_POST_DATA
|
||||
if (NULL != mime)
|
||||
curl_mime_free (mime);
|
||||
#endif /* ! TEST_USE_STATIC_POST_DATA */
|
||||
}
|
||||
|
||||
if ((0 == ret) && callback_param.err_flag)
|
||||
{
|
||||
fprintf (stderr, "One or more errors have been detected by "
|
||||
"access handler callback function. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
ret = 1;
|
||||
}
|
||||
else if ((0 == ret) && cbc.excess_found)
|
||||
{
|
||||
fprintf (stderr, "The extra reply data have been detected one "
|
||||
"or more times. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
curl_multi_cleanup (multi);
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
run_all_checks (void)
|
||||
{
|
||||
uint16_t port;
|
||||
unsigned int testRes;
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (MHD_are_sanitizers_enabled_ ())
|
||||
{
|
||||
fprintf (stderr, "The test does not work with sanitizers. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
return 77;
|
||||
}
|
||||
if (! MHD_is_avoid_accept4_possible_ ())
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Non-debug build of MHD on this platform use accept4() function. "
|
||||
"Test with zzuf is not possible. "
|
||||
"At line %d.\n", (int) __LINE__);
|
||||
return 77;
|
||||
}
|
||||
if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
|
||||
port = 0; /* Use system automatic assignment */
|
||||
else
|
||||
{
|
||||
port = 4010; /* Use predefined port, may break parallel testing of another MHD build */
|
||||
if (oneone)
|
||||
port += 100;
|
||||
if (use_long_uri)
|
||||
port += 30;
|
||||
else if (use_long_header)
|
||||
port += 35;
|
||||
else if (use_get_chunked)
|
||||
port += 0;
|
||||
else if (use_get)
|
||||
port += 5;
|
||||
else if (use_post_form)
|
||||
port += 10;
|
||||
else if (use_post)
|
||||
port += 15;
|
||||
else if (use_put_large)
|
||||
port += 20;
|
||||
else if (use_put_chunked)
|
||||
port += 25;
|
||||
}
|
||||
|
||||
if (! dry_run && (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)))
|
||||
{
|
||||
testRes = testInternalPolling (&port, MHD_USE_SELECT_INTERNALLY);
|
||||
if ((77 == testRes) || (99 == testRes))
|
||||
return testRes;
|
||||
ret += testRes;
|
||||
testRes = testInternalPolling (&port, MHD_USE_SELECT_INTERNALLY
|
||||
| MHD_USE_THREAD_PER_CONNECTION);
|
||||
if ((77 == testRes) || (99 == testRes))
|
||||
return testRes;
|
||||
ret += testRes;
|
||||
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL))
|
||||
{
|
||||
testRes = testInternalPolling (&port, MHD_USE_POLL_INTERNALLY);
|
||||
if ((77 == testRes) || (99 == testRes))
|
||||
return testRes;
|
||||
ret += testRes;
|
||||
testRes = testInternalPolling (&port, MHD_USE_POLL_INTERNALLY
|
||||
| MHD_USE_THREAD_PER_CONNECTION);
|
||||
if ((77 == testRes) || (99 == testRes))
|
||||
return testRes;
|
||||
ret += testRes;
|
||||
}
|
||||
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL))
|
||||
{
|
||||
testRes = testInternalPolling (&port, MHD_USE_EPOLL_INTERNALLY);
|
||||
if ((77 == testRes) || (99 == testRes))
|
||||
return testRes;
|
||||
}
|
||||
}
|
||||
testRes = testExternalPolling (&port, MHD_NO_FLAG);
|
||||
if ((77 == testRes) || (99 == testRes))
|
||||
return testRes;
|
||||
ret += testRes;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
unsigned int errorCount = 0;
|
||||
(void) argc; /* Unused. Silent compiler warning. */
|
||||
unsigned int res;
|
||||
|
||||
oneone = (NULL != strrchr (argv[0], (int) '/')) ?
|
||||
(NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
|
||||
if (0 != curl_global_init (CURL_GLOBAL_WIN32))
|
||||
return 2;
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
|
||||
oneone = ! has_in_name (argv[0], "10");
|
||||
use_get = has_in_name (argv[0], "_get");
|
||||
use_get_chunked = has_in_name (argv[0], "_get_chunked");
|
||||
use_put = has_in_name (argv[0], "_put");
|
||||
use_put_large = has_in_name (argv[0], "_put_large");
|
||||
use_put_chunked = has_in_name (argv[0], "_put_chunked");
|
||||
use_post = has_in_name (argv[0], "_post");
|
||||
use_post_form = has_in_name (argv[0], "_post_form");
|
||||
use_long_header = has_in_name (argv[0], "_long_header");
|
||||
use_long_uri = has_in_name (argv[0], "_long_uri");
|
||||
use_close = has_in_name (argv[0], "_close");
|
||||
|
||||
dry_run = has_param (argc, argv, "--dry-run") ||
|
||||
has_param (argc, argv, "-n");
|
||||
|
||||
if (1 !=
|
||||
((use_get ? 1 : 0) + (use_put ? 1 : 0) + (use_post ? 1 : 0)))
|
||||
{
|
||||
errorCount += testInternalGet ();
|
||||
errorCount += testMultithreadedGet ();
|
||||
fprintf (stderr, "Wrong test name '%s': no or multiple indications "
|
||||
"for the test type.\n", argv[0] ? argv[0] : "(NULL)");
|
||||
return 99;
|
||||
}
|
||||
errorCount += testExternalGet ();
|
||||
if (errorCount != 0)
|
||||
fprintf (stderr, "Error (code: %u)\n", errorCount);
|
||||
curl_global_cleanup ();
|
||||
return (0 == errorCount) ? 0 : 1; /* 0 == pass */
|
||||
|
||||
/* zzuf cannot bypass exit values.
|
||||
Unless 'dry run' is used, do not return errors for external error
|
||||
conditions (like out-of-memory) as they will be reported as test failures. */
|
||||
if (! test_global_init ())
|
||||
return dry_run ? 99 : 0;
|
||||
res = run_all_checks ();
|
||||
test_global_deinit ();
|
||||
if (99 == res)
|
||||
return dry_run ? 99 : 0;
|
||||
if (77 == res)
|
||||
return dry_run ? 77 : 0;
|
||||
return (0 == res) ? 0 : 1; /* 0 == pass */
|
||||
}
|
||||
|
||||
@@ -1,364 +0,0 @@
|
||||
/*
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file daemontest_get_chunked.c
|
||||
* @brief Testcase for libmicrohttpd GET operations with chunked content 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
|
||||
|
||||
#include "socat.c"
|
||||
|
||||
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 enum MHD_Result
|
||||
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 **req_cls)
|
||||
{
|
||||
static int aptr;
|
||||
const char *me = cls;
|
||||
struct MHD_Response *response;
|
||||
struct MHD_Response **responseptr;
|
||||
enum MHD_Result ret;
|
||||
|
||||
(void) url;
|
||||
(void) version; /* Unused. Silent compiler warning. */
|
||||
(void) upload_data;
|
||||
(void) upload_data_size; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (NULL == url)
|
||||
fprintf (stderr, "The \"url\" parameter is NULL.\n");
|
||||
if (NULL == method)
|
||||
fprintf (stderr, "The \"method\" parameter is NULL.\n");
|
||||
if (NULL == version)
|
||||
fprintf (stderr, "The \"version\" parameter is NULL.\n");
|
||||
if (NULL == upload_data_size)
|
||||
fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
|
||||
if ((0 != *upload_data_size) && (NULL == upload_data))
|
||||
fprintf (stderr, "Upload data is NULL with non-zero size.\n");
|
||||
if (0 != strcmp (me, method))
|
||||
return MHD_NO; /* unexpected method */
|
||||
if (&aptr != *req_cls)
|
||||
{
|
||||
/* do never respond on first call */
|
||||
*req_cls = &aptr;
|
||||
return MHD_YES;
|
||||
}
|
||||
responseptr = malloc (sizeof (struct MHD_Response *));
|
||||
if (NULL == responseptr)
|
||||
return MHD_NO;
|
||||
response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
|
||||
1024,
|
||||
&crc, responseptr, &crcf);
|
||||
if (NULL == response)
|
||||
{
|
||||
free (responseptr);
|
||||
return MHD_NO;
|
||||
}
|
||||
*responseptr = response;
|
||||
ret = MHD_queue_response (connection,
|
||||
MHD_HTTP_OK,
|
||||
response);
|
||||
MHD_destroy_response (response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testInternalGet ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d =
|
||||
MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
|
||||
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, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testMultithreadedGet ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
|
||||
| MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 16;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned 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;
|
||||
int max;
|
||||
int running;
|
||||
time_t start;
|
||||
struct timeval tv;
|
||||
int i;
|
||||
|
||||
multi = NULL;
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 256;
|
||||
multi = curl_multi_init ();
|
||||
if (multi == NULL)
|
||||
{
|
||||
MHD_stop_daemon (d);
|
||||
return 512;
|
||||
}
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
mret = curl_multi_add_handle (multi, c);
|
||||
if (mret != CURLM_OK)
|
||||
{
|
||||
curl_multi_cleanup (multi);
|
||||
curl_easy_cleanup (c);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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)
|
||||
{
|
||||
curl_multi_info_read (multi, &running);
|
||||
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);
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
curl_multi_cleanup (multi);
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
unsigned int errorCount = 0;
|
||||
(void) argc; (void) argv; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (0 != curl_global_init (CURL_GLOBAL_WIN32))
|
||||
return 2;
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
|
||||
{
|
||||
errorCount += testInternalGet ();
|
||||
errorCount += testMultithreadedGet ();
|
||||
}
|
||||
errorCount += testExternalGet ();
|
||||
if (errorCount != 0)
|
||||
fprintf (stderr, "Error (code: %u)\n", errorCount);
|
||||
curl_global_cleanup ();
|
||||
return (0 == errorCount) ? 0 : 1; /* 0 == pass */
|
||||
}
|
||||
@@ -1,265 +0,0 @@
|
||||
/*
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, 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
|
||||
|
||||
#include "socat.c"
|
||||
|
||||
/**
|
||||
* 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 enum MHD_Result
|
||||
apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
(void) cls; (void) addr; (void) addrlen; /* Unused. Silent compiler warning. */
|
||||
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)
|
||||
{
|
||||
(void) ptr; (void) ctx; /* Unused. Silent compiler warning. */
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
|
||||
static enum MHD_Result
|
||||
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 **req_cls)
|
||||
{
|
||||
const char *me = cls;
|
||||
struct MHD_Response *response;
|
||||
enum MHD_Result ret;
|
||||
(void) version; (void) upload_data; /* Unused. Silent compiler warning. */
|
||||
(void) upload_data_size; (void) req_cls; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (NULL == url)
|
||||
fprintf (stderr, "The \"url\" parameter is NULL.\n");
|
||||
if (NULL == method)
|
||||
fprintf (stderr, "The \"method\" parameter is NULL.\n");
|
||||
if (NULL == version)
|
||||
fprintf (stderr, "The \"version\" parameter is NULL.\n");
|
||||
if (NULL == upload_data_size)
|
||||
fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
|
||||
if ((0 != *upload_data_size) && (NULL == upload_data))
|
||||
fprintf (stderr, "Upload data is NULL with non-zero size.\n");
|
||||
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 unsigned int
|
||||
testLongUrlGet ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
char *url;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d =
|
||||
MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080,
|
||||
&apc_all,
|
||||
NULL,
|
||||
&ahc_echo,
|
||||
"GET",
|
||||
MHD_OPTION_CONNECTION_MEMORY_LIMIT,
|
||||
(size_t) (VERY_LONG / 2), MHD_OPTION_END);
|
||||
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
|
||||
c = curl_easy_init ();
|
||||
url = malloc (VERY_LONG);
|
||||
if (NULL == url)
|
||||
{
|
||||
zzuf_socat_stop ();
|
||||
return 1;
|
||||
}
|
||||
memset (url, 'a', VERY_LONG);
|
||||
url[VERY_LONG - 1] = '\0';
|
||||
memcpy (url, "http://127.0.0.1:11081/",
|
||||
strlen ("http://127.0.0.1:11081/"));
|
||||
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, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
|
||||
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, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
free (url);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testLongHeaderGet ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
char *url;
|
||||
struct curl_slist *header = NULL;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d =
|
||||
MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080,
|
||||
&apc_all,
|
||||
NULL,
|
||||
&ahc_echo,
|
||||
"GET",
|
||||
MHD_OPTION_CONNECTION_MEMORY_LIMIT,
|
||||
(size_t) (VERY_LONG / 2), MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 16;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
c = curl_easy_init ();
|
||||
url = malloc (VERY_LONG);
|
||||
if (NULL == url)
|
||||
{
|
||||
zzuf_socat_stop ();
|
||||
curl_easy_cleanup (c);
|
||||
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:11081/hello_world");
|
||||
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
|
||||
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
|
||||
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, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_slist_free_all (header);
|
||||
header = NULL;
|
||||
curl_easy_cleanup (c);
|
||||
free (url);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
unsigned int errorCount = 0;
|
||||
const char *sl;
|
||||
(void) argc; /* Unused. Silent compiler warning. */
|
||||
|
||||
sl = strrchr (argv[0], (int) '/');
|
||||
oneone = (NULL != sl) ? (NULL != strstr (sl, "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 (0 == errorCount) ? 0 : 1; /* 0 == pass */
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
/*
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, 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
|
||||
|
||||
|
||||
#include "socat.c"
|
||||
|
||||
#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 **req_cls,
|
||||
enum MHD_RequestTerminationCode toe)
|
||||
{
|
||||
struct MHD_PostProcessor *pp = *req_cls;
|
||||
(void) cls; (void) connection; (void) toe; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (NULL != pp)
|
||||
MHD_destroy_post_processor (pp);
|
||||
*req_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 enum MHD_Result
|
||||
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;
|
||||
(void) kind; (void) filename; (void) content_type; /* Unused. Silent compiler warning. */
|
||||
(void) transfer_encoding; (void) off; /* Unused. Silent compiler warning. */
|
||||
|
||||
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 enum MHD_Result
|
||||
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 **req_cls)
|
||||
{
|
||||
static int eok;
|
||||
struct MHD_Response *response;
|
||||
struct MHD_PostProcessor *pp;
|
||||
enum MHD_Result ret;
|
||||
(void) cls; (void) version; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (NULL == url)
|
||||
fprintf (stderr, "The \"url\" parameter is NULL.\n");
|
||||
if (NULL == method)
|
||||
fprintf (stderr, "The \"method\" parameter is NULL.\n");
|
||||
if (NULL == version)
|
||||
fprintf (stderr, "The \"version\" parameter is NULL.\n");
|
||||
if (NULL == upload_data_size)
|
||||
fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
|
||||
if ((0 != *upload_data_size) && (NULL == upload_data))
|
||||
fprintf (stderr, "Upload data is NULL with non-zero size.\n");
|
||||
if (0 != strcmp ("POST", method))
|
||||
{
|
||||
return MHD_NO; /* unexpected method */
|
||||
}
|
||||
pp = *req_cls;
|
||||
if (pp == NULL)
|
||||
{
|
||||
eok = 0;
|
||||
pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
|
||||
*req_cls = 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);
|
||||
*req_cls = NULL;
|
||||
return ret;
|
||||
}
|
||||
*upload_data_size = 0;
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testInternalPost ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d =
|
||||
MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, NULL,
|
||||
MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
|
||||
MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
|
||||
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_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, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testMultithreadedPost ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
|
||||
| MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, NULL,
|
||||
MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
|
||||
MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 16;
|
||||
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
|
||||
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_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, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned 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;
|
||||
int max;
|
||||
int running;
|
||||
time_t start;
|
||||
struct timeval tv;
|
||||
int i;
|
||||
|
||||
multi = NULL;
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
|
||||
1082, NULL, NULL, &ahc_echo, NULL,
|
||||
MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
|
||||
MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 256;
|
||||
multi = curl_multi_init ();
|
||||
if (multi == NULL)
|
||||
{
|
||||
MHD_stop_daemon (d);
|
||||
return 512;
|
||||
}
|
||||
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
|
||||
|
||||
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, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
|
||||
|
||||
mret = curl_multi_add_handle (multi, c);
|
||||
if (mret != CURLM_OK)
|
||||
{
|
||||
curl_multi_cleanup (multi);
|
||||
curl_easy_cleanup (c);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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)
|
||||
{
|
||||
curl_multi_info_read (multi, &running);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
curl_multi_cleanup (multi);
|
||||
zzuf_socat_stop ();
|
||||
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
unsigned int errorCount = 0;
|
||||
(void) argc; /* Unused. Silent compiler warning. */
|
||||
|
||||
oneone = (NULL != strrchr (argv[0], (int) '/')) ?
|
||||
(NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
|
||||
if (0 != curl_global_init (CURL_GLOBAL_WIN32))
|
||||
return 2;
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
|
||||
{
|
||||
errorCount += testInternalPost ();
|
||||
errorCount += testMultithreadedPost ();
|
||||
}
|
||||
errorCount += testExternalPost ();
|
||||
if (errorCount != 0)
|
||||
fprintf (stderr, "Error (code: %u)\n", errorCount);
|
||||
curl_global_cleanup ();
|
||||
return (0 == errorCount) ? 0 : 1; /* 0 == pass */
|
||||
}
|
||||
@@ -1,432 +0,0 @@
|
||||
/*
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test_post_form.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>
|
||||
|
||||
#ifndef WINDOWS
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "socat.c"
|
||||
|
||||
static int oneone;
|
||||
|
||||
struct CBC
|
||||
{
|
||||
char *buf;
|
||||
size_t pos;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
completed_cb (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
void **req_cls,
|
||||
enum MHD_RequestTerminationCode toe)
|
||||
{
|
||||
struct MHD_PostProcessor *pp = *req_cls;
|
||||
(void) cls; (void) connection; (void) toe; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (NULL != pp)
|
||||
MHD_destroy_post_processor (pp);
|
||||
*req_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 enum MHD_Result
|
||||
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;
|
||||
(void) kind; (void) filename; (void) content_type; /* Unused. Silent compiler warning. */
|
||||
(void) transfer_encoding; (void) off; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (key == NULL)
|
||||
return MHD_YES;
|
||||
#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 enum MHD_Result
|
||||
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 **req_cls)
|
||||
{
|
||||
static int eok;
|
||||
struct MHD_Response *response;
|
||||
struct MHD_PostProcessor *pp;
|
||||
enum MHD_Result ret;
|
||||
(void) cls; (void) version; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (NULL == url)
|
||||
fprintf (stderr, "The \"url\" parameter is NULL.\n");
|
||||
if (NULL == method)
|
||||
fprintf (stderr, "The \"method\" parameter is NULL.\n");
|
||||
if (NULL == version)
|
||||
fprintf (stderr, "The \"version\" parameter is NULL.\n");
|
||||
if (NULL == upload_data_size)
|
||||
fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
|
||||
if ((0 != *upload_data_size) && (NULL == upload_data))
|
||||
fprintf (stderr, "Upload data is NULL with non-zero size.\n");
|
||||
if (0 != strcmp ("POST", method))
|
||||
{
|
||||
return MHD_NO; /* unexpected method */
|
||||
}
|
||||
pp = *req_cls;
|
||||
if (pp == NULL)
|
||||
{
|
||||
eok = 0;
|
||||
pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
|
||||
if (pp == NULL)
|
||||
return MHD_NO;
|
||||
*req_cls = 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);
|
||||
*req_cls = 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 unsigned int
|
||||
testInternalPost ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
int i;
|
||||
struct curl_httppost *pd;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d =
|
||||
MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, NULL,
|
||||
MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
|
||||
MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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);
|
||||
pd = make_form ();
|
||||
curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
curl_formfree (pd);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testMultithreadedPost ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
int i;
|
||||
struct curl_httppost *pd;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
|
||||
| MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080, NULL, NULL, &ahc_echo, NULL,
|
||||
MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
|
||||
MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 16;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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);
|
||||
pd = make_form ();
|
||||
curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
curl_formfree (pd);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned 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;
|
||||
int max;
|
||||
int running;
|
||||
time_t start;
|
||||
struct timeval tv;
|
||||
struct curl_httppost *pd;
|
||||
int i;
|
||||
|
||||
multi = NULL;
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
|
||||
1082, NULL, NULL, &ahc_echo, NULL,
|
||||
MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
|
||||
MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 256;
|
||||
multi = curl_multi_init ();
|
||||
if (multi == NULL)
|
||||
{
|
||||
MHD_stop_daemon (d);
|
||||
return 512;
|
||||
}
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
|
||||
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, 1L);
|
||||
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, 15L);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
|
||||
mret = curl_multi_add_handle (multi, c);
|
||||
if (mret != CURLM_OK)
|
||||
{
|
||||
curl_multi_cleanup (multi);
|
||||
curl_formfree (pd);
|
||||
curl_easy_cleanup (c);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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)
|
||||
{
|
||||
curl_multi_info_read (multi, &running);
|
||||
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);
|
||||
}
|
||||
curl_formfree (pd);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
curl_multi_cleanup (multi);
|
||||
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
unsigned int errorCount = 0;
|
||||
(void) argc; /* Unused. Silent compiler warning. */
|
||||
|
||||
oneone = (NULL != strrchr (argv[0], (int) '/')) ?
|
||||
(NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
|
||||
if (0 != curl_global_init (CURL_GLOBAL_WIN32))
|
||||
return 2;
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
|
||||
{
|
||||
errorCount += testInternalPost ();
|
||||
errorCount += testMultithreadedPost ();
|
||||
}
|
||||
errorCount += testExternalPost ();
|
||||
if (errorCount != 0)
|
||||
fprintf (stderr, "Error (code: %u)\n", errorCount);
|
||||
curl_global_cleanup ();
|
||||
return (0 == errorCount) ? 0 : 1; /* 0 == pass */
|
||||
}
|
||||
@@ -1,380 +0,0 @@
|
||||
/*
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test_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
|
||||
|
||||
|
||||
#include "socat.c"
|
||||
|
||||
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 enum MHD_Result
|
||||
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 **req_cls)
|
||||
{
|
||||
int *done = cls;
|
||||
struct MHD_Response *response;
|
||||
enum MHD_Result ret;
|
||||
(void) version; (void) req_cls; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (NULL == url)
|
||||
fprintf (stderr, "The \"url\" parameter is NULL.\n");
|
||||
if (NULL == method)
|
||||
fprintf (stderr, "The \"method\" parameter is NULL.\n");
|
||||
if (NULL == version)
|
||||
fprintf (stderr, "The \"version\" parameter is NULL.\n");
|
||||
if (NULL == upload_data_size)
|
||||
fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
|
||||
if ((0 != *upload_data_size) && (NULL == upload_data))
|
||||
fprintf (stderr, "Upload data is NULL with non-zero size.\n");
|
||||
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 unsigned int
|
||||
testInternalPut ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
unsigned int pos = 0;
|
||||
int done_flag = 0;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d =
|
||||
MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080,
|
||||
NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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);
|
||||
curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testMultithreadedPut ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
unsigned int pos = 0;
|
||||
int done_flag = 0;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
|
||||
| MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080,
|
||||
NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 16;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
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);
|
||||
curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned 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;
|
||||
int max;
|
||||
int running;
|
||||
time_t start;
|
||||
struct timeval tv;
|
||||
unsigned int pos = 0;
|
||||
int done_flag = 0;
|
||||
int i;
|
||||
|
||||
multi = NULL;
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
|
||||
11080,
|
||||
NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 256;
|
||||
multi = curl_multi_init ();
|
||||
if (multi == NULL)
|
||||
{
|
||||
MHD_stop_daemon (d);
|
||||
return 512;
|
||||
}
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
|
||||
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);
|
||||
curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
|
||||
|
||||
mret = curl_multi_add_handle (multi, c);
|
||||
if (mret != CURLM_OK)
|
||||
{
|
||||
curl_multi_cleanup (multi);
|
||||
curl_easy_cleanup (c);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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)
|
||||
{
|
||||
curl_multi_info_read (multi, &running);
|
||||
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);
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
curl_multi_cleanup (multi);
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
unsigned int errorCount = 0;
|
||||
(void) argc; /* Unused. Silent compiler warning. */
|
||||
|
||||
oneone = (NULL != strrchr (argv[0], (int) '/')) ?
|
||||
(NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
|
||||
if (0 != curl_global_init (CURL_GLOBAL_WIN32))
|
||||
return 2;
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
|
||||
{
|
||||
errorCount += testInternalPut ();
|
||||
errorCount += testMultithreadedPut ();
|
||||
}
|
||||
errorCount += testExternalPut ();
|
||||
if (errorCount != 0)
|
||||
fprintf (stderr, "Error (code: %u)\n", errorCount);
|
||||
curl_global_cleanup ();
|
||||
return (0 == errorCount) ? 0 : 1; /* 0 == pass */
|
||||
}
|
||||
@@ -1,395 +0,0 @@
|
||||
/*
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, 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
|
||||
|
||||
#include "socat.c"
|
||||
|
||||
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 enum MHD_Result
|
||||
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 **req_cls)
|
||||
{
|
||||
int *done = cls;
|
||||
struct MHD_Response *response;
|
||||
enum MHD_Result ret;
|
||||
int have;
|
||||
(void) version; (void) req_cls; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (NULL == url)
|
||||
fprintf (stderr, "The \"url\" parameter is NULL.\n");
|
||||
if (NULL == method)
|
||||
fprintf (stderr, "The \"method\" parameter is NULL.\n");
|
||||
if (NULL == version)
|
||||
fprintf (stderr, "The \"version\" parameter is NULL.\n");
|
||||
if (NULL == upload_data_size)
|
||||
fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
|
||||
if ((0 != *upload_data_size) && (NULL == upload_data))
|
||||
fprintf (stderr, "Upload data is NULL with non-zero size.\n");
|
||||
if (0 != strcmp ("PUT", method))
|
||||
return MHD_NO; /* unexpected method */
|
||||
if ((*done) < 8)
|
||||
{
|
||||
have = *upload_data_size;
|
||||
if (have + *done > 8)
|
||||
{
|
||||
return MHD_NO;
|
||||
}
|
||||
if (0 == have)
|
||||
{
|
||||
(void) 0; /* Do nothing - no data yet */
|
||||
}
|
||||
else if (0 == memcmp (upload_data, &"Hello123"[*done], have))
|
||||
{
|
||||
*done += have;
|
||||
*upload_data_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 unsigned int
|
||||
testInternalPut ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
char buf[2048];
|
||||
struct CBC cbc;
|
||||
unsigned int pos = 0;
|
||||
int done_flag = 0;
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
|
||||
11080,
|
||||
NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
done_flag = 0;
|
||||
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, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned 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_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
|
||||
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, 1L);
|
||||
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, 15L);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
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 unsigned 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;
|
||||
int max;
|
||||
int running;
|
||||
time_t start;
|
||||
struct timeval tv;
|
||||
unsigned int pos = 0;
|
||||
int done_flag = 0;
|
||||
int i;
|
||||
|
||||
multi = NULL;
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_USE_ERROR_LOG,
|
||||
11082,
|
||||
NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 256;
|
||||
|
||||
multi = curl_multi_init ();
|
||||
if (multi == NULL)
|
||||
{
|
||||
MHD_stop_daemon (d);
|
||||
return 512;
|
||||
}
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
done_flag = 0;
|
||||
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, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
|
||||
|
||||
mret = curl_multi_add_handle (multi, c);
|
||||
if (mret != CURLM_OK)
|
||||
{
|
||||
curl_multi_cleanup (multi);
|
||||
curl_easy_cleanup (c);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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)
|
||||
{
|
||||
curl_multi_info_read (multi, &running);
|
||||
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);
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
curl_multi_cleanup (multi);
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
unsigned int errorCount = 0;
|
||||
(void) argc; (void) argv; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (0 != curl_global_init (CURL_GLOBAL_WIN32))
|
||||
return 2;
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
|
||||
{
|
||||
errorCount += testInternalPut ();
|
||||
errorCount += testMultithreadedPut ();
|
||||
}
|
||||
errorCount += testExternalPut ();
|
||||
if (errorCount != 0)
|
||||
fprintf (stderr, "Error (code: %u)\n", errorCount);
|
||||
curl_global_cleanup ();
|
||||
return (0 == errorCount) ? 0 : 1; /* 0 == pass */
|
||||
}
|
||||
@@ -1,403 +0,0 @@
|
||||
/*
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test_put_large.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
|
||||
|
||||
#include "socat.c"
|
||||
|
||||
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...
|
||||
*/
|
||||
#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 enum MHD_Result
|
||||
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 **req_cls)
|
||||
{
|
||||
int *done = cls;
|
||||
struct MHD_Response *response;
|
||||
enum MHD_Result ret;
|
||||
(void) version; (void) req_cls; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (NULL == url)
|
||||
fprintf (stderr, "The \"url\" parameter is NULL.\n");
|
||||
if (NULL == method)
|
||||
fprintf (stderr, "The \"method\" parameter is NULL.\n");
|
||||
if (NULL == version)
|
||||
fprintf (stderr, "The \"version\" parameter is NULL.\n");
|
||||
if (NULL == upload_data_size)
|
||||
fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
|
||||
if ((0 != *upload_data_size) && (NULL == upload_data))
|
||||
fprintf (stderr, "Upload data is NULL with non-zero size.\n");
|
||||
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
|
||||
{
|
||||
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 unsigned int
|
||||
testInternalPut ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
struct CBC cbc;
|
||||
unsigned int pos = 0;
|
||||
int done_flag = 0;
|
||||
char buf[2048];
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d =
|
||||
MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080,
|
||||
NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
|
||||
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);
|
||||
curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testMultithreadedPut ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
struct CBC cbc;
|
||||
unsigned int pos = 0;
|
||||
int done_flag = 0;
|
||||
char buf[2048];
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
|
||||
| MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
|
||||
11080,
|
||||
NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 16;
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
|
||||
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);
|
||||
curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_perform (c);
|
||||
curl_easy_cleanup (c);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
testExternalPut ()
|
||||
{
|
||||
struct MHD_Daemon *d;
|
||||
CURL *c;
|
||||
struct CBC cbc;
|
||||
CURLM *multi;
|
||||
CURLMcode mret;
|
||||
fd_set rs;
|
||||
fd_set ws;
|
||||
fd_set es;
|
||||
int max;
|
||||
int running;
|
||||
time_t start;
|
||||
struct timeval tv;
|
||||
unsigned int pos = 0;
|
||||
int done_flag = 0;
|
||||
char buf[2048];
|
||||
int i;
|
||||
|
||||
cbc.buf = buf;
|
||||
cbc.size = 2048;
|
||||
cbc.pos = 0;
|
||||
multi = NULL;
|
||||
d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
|
||||
11080,
|
||||
NULL, NULL, &ahc_echo, &done_flag,
|
||||
MHD_OPTION_CONNECTION_MEMORY_LIMIT,
|
||||
(size_t) (PUT_SIZE * 4), MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
return 256;
|
||||
multi = curl_multi_init ();
|
||||
if (multi == NULL)
|
||||
{
|
||||
MHD_stop_daemon (d);
|
||||
return 512;
|
||||
}
|
||||
zzuf_socat_start ();
|
||||
for (i = 0; i < LOOP_COUNT; i++)
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
|
||||
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);
|
||||
curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
|
||||
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_MS, CURL_TIMEOUT);
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
* setting NOSIGNAL results in really weird
|
||||
* crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
|
||||
|
||||
mret = curl_multi_add_handle (multi, c);
|
||||
if (mret != CURLM_OK)
|
||||
{
|
||||
curl_multi_cleanup (multi);
|
||||
curl_easy_cleanup (c);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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);
|
||||
zzuf_socat_stop ();
|
||||
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)
|
||||
{
|
||||
curl_multi_info_read (multi, &running);
|
||||
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);
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
zzuf_socat_stop ();
|
||||
curl_multi_cleanup (multi);
|
||||
MHD_stop_daemon (d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
unsigned int errorCount = 0;
|
||||
(void) argc; /* Unused. Silent compiler warning. */
|
||||
|
||||
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 (0 == put_buffer)
|
||||
return 77;
|
||||
memset (put_buffer, 1, PUT_SIZE);
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
|
||||
{
|
||||
errorCount += testInternalPut ();
|
||||
errorCount += testMultithreadedPut ();
|
||||
}
|
||||
errorCount += testExternalPut ();
|
||||
free (put_buffer);
|
||||
if (errorCount != 0)
|
||||
fprintf (stderr, "Error (code: %u)\n", errorCount);
|
||||
curl_global_cleanup ();
|
||||
return (0 == errorCount) ? 0 : 1; /* 0 == pass */
|
||||
}
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
|
||||
mhd_listen_ip='127.0.0.1'
|
||||
max_runtime_sec='300'
|
||||
|
||||
if test "x${ZZUF}" = "xno" ; then
|
||||
echo "zzuf command missing" 1>&2
|
||||
exit 77
|
||||
fi
|
||||
|
||||
if command -v "${ZZUF}" > /dev/null 2>&1 ; then : ; else
|
||||
echo "zzuf command missing" 1>&2
|
||||
exit 77
|
||||
fi
|
||||
|
||||
# zzuf cannot pass-through the return value of checked program
|
||||
# so try the direct dry-run first to get possibe 77 or 99 codes
|
||||
echo "## Dry-run of the $@..."
|
||||
if "$@" --dry-run ; then
|
||||
echo "# Dry-run succeded."
|
||||
else
|
||||
res_code=$?
|
||||
echo "Dry-run failed with exit code $res_code. $@ will not be run with zzuf." 1>&2
|
||||
exit $res_code
|
||||
fi
|
||||
|
||||
# fuzz the input only for IP ${mhd_listen_ip}. libcurl uses another IP
|
||||
# in this test therefore libcurl input is not fuzzed.
|
||||
zzuf_all_params="--ratio=0.001:0.4 --autoinc --verbose --signal \
|
||||
--max-usertime=${max_runtime_sec} --check-exit --network \
|
||||
--allow=${mhd_listen_ip} --exclude=."
|
||||
|
||||
if test -n "${ZZUF_SEED}" ; then
|
||||
zzuf_all_params="${zzuf_all_params} --seed=${ZZUF_SEED}"
|
||||
fi
|
||||
|
||||
if test -n "${ZZUF_FLAGS}" ; then
|
||||
zzuf_all_params="${zzuf_all_params} ${ZZUF_FLAGS}"
|
||||
fi
|
||||
|
||||
# Uncomment the next line to see more data in logs
|
||||
#zzuf_all_params="${zzuf_all_params} -dd"
|
||||
|
||||
echo "## Dry-run of the $@ with zzuf..."
|
||||
if "$ZZUF" ${zzuf_all_params} "$@" --dry-run ; then
|
||||
echo "# Dry-run with zzuf succeded."
|
||||
else
|
||||
res_code=$?
|
||||
echo "$@ cannot be run with zzuf. The test is skipped." 1>&2
|
||||
exit 77
|
||||
fi
|
||||
|
||||
echo "## Real test of $@ with zzuf..."
|
||||
"$ZZUF" ${zzuf_all_params} "$@"
|
||||
exit $?
|
||||
Reference in New Issue
Block a user