/*
This file is part of libmicrohttpd
Copyright (C) 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 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;
/* fprintf (stderr, "Calling suspend\n"); */
MHD_suspend_connection (connection);
int 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
{
int 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: %d\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 int
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 **con_cls )
{
int ret;
(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 == *con_cls)
{
fprintf (stderr,
"start: %d\n",
++request_counter);
struct ContentReaderUserdata *userdata = malloc (sizeof(struct ContentReaderUserdata));
if (NULL == userdata)
return MHD_NO;
userdata->bytes_written = 0;
userdata->connection = connection;
*con_cls = userdata;
return MHD_YES;
}
/* Second call: create response */
struct MHD_Response *response
= MHD_create_response_from_callback (-1,
32 * 1024,
&http_ContentReaderCallback,
*con_cls,
NULL);
ret = MHD_queue_response (connection,
MHD_HTTP_OK,
response);
MHD_destroy_response (response);
suspend_connection (connection);
return ret;
}
int
main(void)
{
int port;
char command_line[1024];
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);
/* Flags */
unsigned int daemon_flags
= MHD_USE_INTERNAL_POLLING_THREAD
| MHD_USE_AUTO
| MHD_ALLOW_SUSPEND_RESUME
| MHD_USE_ITC;
/* Create daemon */
struct MHD_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 = (int)dinfo->port;
}
sprintf(command_line, "curl -s http://127.0.0.1:%d", 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;
}