blob: 888bff16157716844d1e7aa51c8b4b75680f9114 [file] [log] [blame]
/*
This file is part of libmicrohttpd
Copyright (C) 2016 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
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_quiesce_stream.c
* @brief Testcase for libmicrohttpd quiescing
* @author Markus Doppelbauer
* @author Christian Grothoff
* @author Karlson2k (Evgeny Grin)
*/
#include "mhd_options.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <microhttpd.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#elif defined(_WIN32)
#include <windows.h>
#define sleep(s) (Sleep ((s) * 1000), 0)
#endif /* _WIN32 */
static volatile unsigned int request_counter;
static void
http_PanicCallback (void *cls,
const char *file,
unsigned int line,
const char *reason)
{
(void) cls; /* Unused. Silent compiler warning. */
fprintf (stderr,
"PANIC: exit process: %s at %s:%u\n",
reason,
file,
line);
exit (EXIT_FAILURE);
}
static void *
resume_connection (void *arg)
{
struct MHD_Connection *connection = arg;
/* fprintf (stderr, "Calling resume\n"); */
MHD_resume_connection (connection);
return NULL;
}
static void
suspend_connection (struct MHD_Connection *connection)
{
pthread_t thread_id;
int status;
/* fprintf (stderr, "Calling suspend\n"); */
MHD_suspend_connection (connection);
status = pthread_create (&thread_id,
NULL,
&resume_connection,
connection);
if (0 != status)
{
fprintf (stderr,
"Could not create thead\n");
exit (EXIT_FAILURE);
}
pthread_detach (thread_id);
}
struct ContentReaderUserdata
{
size_t bytes_written;
struct MHD_Connection *connection;
};
static ssize_t
http_ContentReaderCallback (void *cls,
uint64_t pos,
char *buf,
size_t max)
{
static const char alphabet[] =
"\nABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
struct ContentReaderUserdata *userdata = cls;
(void) pos; (void) max; /* Unused. Silent compiler warning. */
if (userdata->bytes_written >= 1024)
{
fprintf (stderr,
"finish: %u\n",
request_counter);
return MHD_CONTENT_READER_END_OF_STREAM;
}
userdata->bytes_written++;
buf[0] = alphabet[userdata->bytes_written % (sizeof(alphabet) - 1)];
suspend_connection (userdata->connection);
return 1;
}
static void
free_crc_data (void *crc_data)
{
struct ContentReaderUserdata *userdata = crc_data;
free (userdata);
}
static enum MHD_Result
http_AccessHandlerCallback (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)
{
enum MHD_Result ret;
struct MHD_Response *response;
(void) cls; (void) url; /* Unused. Silent compiler warning. */
(void) method; (void) version; (void) upload_data; /* Unused. Silent compiler warning. */
(void) upload_data_size; /* Unused. Silent compiler warning. */
/* Never respond on first call */
if (NULL == *req_cls)
{
struct ContentReaderUserdata *userdata;
fprintf (stderr,
"start: %u\n",
++request_counter);
userdata = malloc (sizeof(struct ContentReaderUserdata));
if (NULL == userdata)
return MHD_NO;
userdata->bytes_written = 0;
userdata->connection = connection;
*req_cls = userdata;
return MHD_YES;
}
/* Second call: create response */
response
= MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
32 * 1024,
&http_ContentReaderCallback,
*req_cls,
&free_crc_data);
ret = MHD_queue_response (connection,
MHD_HTTP_OK,
response);
MHD_destroy_response (response);
suspend_connection (connection);
return ret;
}
int
main (void)
{
uint16_t port;
char command_line[1024];
/* Flags */
unsigned int daemon_flags
= MHD_USE_INTERNAL_POLLING_THREAD
| MHD_USE_AUTO
| MHD_ALLOW_SUSPEND_RESUME
| MHD_USE_ITC;
struct MHD_Daemon *daemon;
if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
port = 0;
else
port = 1470;
/* Panic callback */
MHD_set_panic_func (&http_PanicCallback,
NULL);
/* Create daemon */
daemon = MHD_start_daemon (daemon_flags,
port,
NULL,
NULL,
&http_AccessHandlerCallback,
NULL,
MHD_OPTION_END);
if (NULL == daemon)
return 1;
if (0 == port)
{
const union MHD_DaemonInfo *dinfo;
dinfo = MHD_get_daemon_info (daemon, MHD_DAEMON_INFO_BIND_PORT);
if ((NULL == dinfo) || (0 == dinfo->port) )
{
MHD_stop_daemon (daemon); return 32;
}
port = dinfo->port;
}
snprintf (command_line,
sizeof (command_line),
"curl -s http://127.0.0.1:%u",
(unsigned int) port);
if (0 != system (command_line))
{
MHD_stop_daemon (daemon);
return 1;
}
/* wait for a request */
while (0 == request_counter)
(void) sleep (1);
fprintf (stderr,
"quiesce\n");
MHD_quiesce_daemon (daemon);
/* wait a second */
(void) sleep (1);
fprintf (stderr,
"stopping daemon\n");
MHD_stop_daemon (daemon);
return 0;
}