libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 2369ddff276508b0387443ff4cbdd4986f513a3e
parent ec8aedc77bbaa293dc76d2aba98fc8ce1243cf68
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun, 13 Apr 2008 02:28:23 +0000

socat-ing get'
'

Diffstat:
Msrc/testzzuf/Makefile.am | 2++
Asrc/testzzuf/README | 13+++++++++++++
Msrc/testzzuf/daemontest_get.c | 298++++++++++++++++++++++++++++++++++++++-----------------------------------------
Asrc/testzzuf/socat.c | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 258 insertions(+), 154 deletions(-)

diff --git a/src/testzzuf/Makefile.am b/src/testzzuf/Makefile.am @@ -2,6 +2,8 @@ SUBDIRS = . INCLUDES = -I$(top_srcdir)/src/include +EXTRA_DIST = README socat.c + check_PROGRAMS = \ daemontest_get \ daemontest_post \ diff --git a/src/testzzuf/README b/src/testzzuf/README @@ -0,0 +1,13 @@ +Testcases in this directory require zzuf and socat. + +zzuf is used to randomly mess with the TCP connection between the CURL +clients and the MHD server. The goal is to expose problems in MHD's +error handling (by introducing random syntax errors). socat is +used to listen on port 11081 and forward the randomzied stream to +port 11080 where MHD is waiting. + +As a result, the testcases in this directory do NOT check that +whatever CURL returns is what was expected -- random modifications to +the TCP stream can have random effects ;-). Testcases "fail" if the +code crashes or hangs indefinitely. + diff --git a/src/testzzuf/daemontest_get.c b/src/testzzuf/daemontest_get.c @@ -1,6 +1,6 @@ /* This file is part of libmicrohttpd - (C) 2007 Christian Grothoff + (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 @@ -21,7 +21,6 @@ /** * @file daemontest_get.c * @brief Testcase for libmicrohttpd GET operations - * TODO: test parsing of query * @author Christian Grothoff */ @@ -36,6 +35,18 @@ #include <unistd.h> #endif +#include "socat.c" + +/** + * 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. + */ +#define LOOP_COUNT 10 + +#define CURL_TIMEOUT 50L + static int oneone; struct CBC @@ -96,45 +107,39 @@ testInternalGet () CURL *c; char buf[2048]; struct CBC cbc; - CURLcode errornum; + int i; cbc.buf = buf; cbc.size = 2048; cbc.pos = 0; - d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */, 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); if (d == NULL) return 1; - c = curl_easy_init (); - curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world"); - curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); - curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); - curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); - curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); - curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); - if (oneone) - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - else - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); - // NOTE: use of CONNECTTIMEOUT without also - // setting NOSIGNAL results in really weird - // crashes on my system! - curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - if (CURLE_OK != (errornum = curl_easy_perform (c))) - { - fprintf (stderr, - "curl_easy_perform failed: `%s'\n", - curl_easy_strerror (errornum)); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 2; - } - curl_easy_cleanup (c); + zzuf_socat_start(); + for (i=0;i<LOOP_COUNT;i++) { + fprintf(stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + 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, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf(stderr, "\n"); + zzuf_socat_stop(); MHD_stop_daemon (d); - if (cbc.pos != strlen ("/hello_world")) - return 4; - if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) - return 8; return 0; } @@ -145,45 +150,39 @@ testMultithreadedGet () CURL *c; char buf[2048]; struct CBC cbc; - CURLcode errornum; + int i; cbc.buf = buf; cbc.size = 2048; cbc.pos = 0; - d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, - 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */, + 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); if (d == NULL) return 16; - c = curl_easy_init (); - curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); - curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); - curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); - curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); - curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); - if (oneone) - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - else - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); - curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); - // NOTE: use of CONNECTTIMEOUT without also - // setting NOSIGNAL results in really weird - // crashes on my system! - curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - if (CURLE_OK != (errornum = curl_easy_perform (c))) - { - fprintf (stderr, - "curl_easy_perform failed: `%s'\n", - curl_easy_strerror (errornum)); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 32; - } - curl_easy_cleanup (c); + zzuf_socat_start(); + for (i=0;i<LOOP_COUNT;i++) { + fprintf(stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + 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, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf(stderr, "\n"); + zzuf_socat_stop(); 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; } @@ -202,35 +201,18 @@ testExternalGet () fd_set es; int max; int running; - struct CURLMsg *msg; time_t start; struct timeval tv; + int i; multi = NULL; cbc.buf = buf; cbc.size = 2048; cbc.pos = 0; - d = MHD_start_daemon (MHD_USE_DEBUG, - 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG*/, + 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); if (d == NULL) return 256; - c = curl_easy_init (); - curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); - curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); - curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); - curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); - if (oneone) - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - else - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); - curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); - curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); - // NOTE: use of CONNECTTIMEOUT without also - // setting NOSIGNAL results in really weird - // crashes on my system! - curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - - multi = curl_multi_init (); if (multi == NULL) { @@ -238,75 +220,83 @@ testExternalGet () MHD_stop_daemon (d); return 512; } - mret = curl_multi_add_handle (multi, c); - if (mret != CURLM_OK) - { - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 1024; - } - start = time (NULL); - while ((time (NULL) - start < 5) && (multi != NULL)) - { - max = 0; - FD_ZERO (&rs); - FD_ZERO (&ws); - FD_ZERO (&es); - curl_multi_perform (multi, &running); - mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); - if (mret != CURLM_OK) - { - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 2048; - } - if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) - { - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 4096; - } - tv.tv_sec = 0; - tv.tv_usec = 1000; - select (max + 1, &rs, &ws, &es, &tv); - curl_multi_perform (multi, &running); - if (running == 0) - { - msg = curl_multi_info_read (multi, &running); - if (msg == NULL) - break; - if (msg->msg == CURLMSG_DONE) - { - if (msg->data.result != CURLE_OK) - printf ("%s failed at %s:%d: `%s'\n", - "curl_multi_perform", - __FILE__, - __LINE__, curl_easy_strerror (msg->data.result)); - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - c = NULL; - multi = NULL; - } - } - MHD_run (d); - } - if (multi != NULL) - { - curl_multi_remove_handle (multi, c); - curl_easy_cleanup (c); - curl_multi_cleanup (multi); - } + zzuf_socat_start(); + for (i=0;i<LOOP_COUNT;i++) { + fprintf(stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT_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, 1); + 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); - if (cbc.pos != strlen ("/hello_world")) - return 8192; - if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) - return 16384; return 0; } @@ -322,7 +312,7 @@ main (int argc, char *const *argv) return 2; errorCount += testInternalGet (); errorCount += testMultithreadedGet (); - errorCount += testExternalGet (); + errorCount += testExternalGet (); if (errorCount != 0) fprintf (stderr, "Error (code: %u)\n", errorCount); curl_global_cleanup (); diff --git a/src/testzzuf/socat.c b/src/testzzuf/socat.c @@ -0,0 +1,99 @@ +/* + This file is part of libmicrohttpd + (C) 2008 Christian Grothoff + + libmicrohttpd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file 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> + + +static pid_t zzuf_pid; + +static void +zzuf_socat_start() { + int status; + char * const args[] = { + "zzuf", + "--ratio=0.0:0.75", + "-n", + "-A", + "socat", + "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) + { + 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; + } + setpgrp(); + execvp("zzuf", + args); + fprintf(stderr, + "execution of `zzuf' failed: %s\n", + strerror(errno)); + zzuf_pid = 0; /* fork failed */ + 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); + sleep(1); /* allow socat to also die in peace */ + } +} + +/* end of socat.c */