test_quiesce_stream.c (6746B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2016 Christian Grothoff 4 Copyright (C) 2016-2022 Evgeny Grin (Karlson2k) 5 6 libmicrohttpd is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published 8 by the Free Software Foundation; either version 2, or (at your 9 option) any later version. 10 11 libmicrohttpd is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with libmicrohttpd; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20 */ 21 /** 22 * @file test_quiesce_stream.c 23 * @brief Testcase for libmicrohttpd quiescing 24 * @author Markus Doppelbauer 25 * @author Christian Grothoff 26 * @author Karlson2k (Evgeny Grin) 27 */ 28 #include "mhd_options.h" 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <errno.h> 33 #include <pthread.h> 34 #include <microhttpd.h> 35 #ifdef HAVE_UNISTD_H 36 #include <unistd.h> 37 #elif defined(_WIN32) 38 #include <windows.h> 39 #define sleep(s) (Sleep ((s) * 1000), 0) 40 #endif /* _WIN32 */ 41 42 43 static volatile unsigned int request_counter; 44 45 46 _MHD_NORETURN static void 47 http_PanicCallback (void *cls, 48 const char *file, 49 unsigned int line, 50 const char *reason) 51 { 52 (void) cls; /* Unused. Silent compiler warning. */ 53 fprintf (stderr, 54 "PANIC: exit process: %s at %s:%u\n", 55 reason, 56 file, 57 line); 58 exit (EXIT_FAILURE); 59 } 60 61 62 static void * 63 resume_connection (void *arg) 64 { 65 struct MHD_Connection *connection = arg; 66 67 /* fprintf (stderr, "Calling resume\n"); */ 68 MHD_resume_connection (connection); 69 return NULL; 70 } 71 72 73 static void 74 suspend_connection (struct MHD_Connection *connection) 75 { 76 pthread_t thread_id; 77 int status; 78 79 /* fprintf (stderr, "Calling suspend\n"); */ 80 MHD_suspend_connection (connection); 81 status = pthread_create (&thread_id, 82 NULL, 83 &resume_connection, 84 connection); 85 if (0 != status) 86 { 87 fprintf (stderr, 88 "Could not create thead\n"); 89 exit (EXIT_FAILURE); 90 } 91 pthread_detach (thread_id); 92 } 93 94 95 struct ContentReaderUserdata 96 { 97 size_t bytes_written; 98 struct MHD_Connection *connection; 99 }; 100 101 102 static ssize_t 103 http_ContentReaderCallback (void *cls, 104 uint64_t pos, 105 char *buf, 106 size_t max) 107 { 108 static const char alphabet[] = 109 "\nABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 110 struct ContentReaderUserdata *userdata = cls; 111 (void) pos; (void) max; /* Unused. Silent compiler warning. */ 112 113 if (userdata->bytes_written >= 1024) 114 { 115 fprintf (stderr, 116 "finish: %u\n", 117 request_counter); 118 return MHD_CONTENT_READER_END_OF_STREAM; 119 } 120 userdata->bytes_written++; 121 buf[0] = alphabet[userdata->bytes_written % (sizeof(alphabet) - 1)]; 122 suspend_connection (userdata->connection); 123 124 return 1; 125 } 126 127 128 static void 129 free_crc_data (void *crc_data) 130 { 131 struct ContentReaderUserdata *userdata = crc_data; 132 133 free (userdata); 134 } 135 136 137 static enum MHD_Result 138 http_AccessHandlerCallback (void *cls, 139 struct MHD_Connection *connection, 140 const char *url, 141 const char *method, 142 const char *version, 143 const char *upload_data, 144 size_t *upload_data_size, 145 void **req_cls) 146 { 147 enum MHD_Result ret; 148 struct MHD_Response *response; 149 (void) cls; (void) url; /* Unused. Silent compiler warning. */ 150 (void) method; (void) version; (void) upload_data; /* Unused. Silent compiler warning. */ 151 (void) upload_data_size; /* Unused. Silent compiler warning. */ 152 153 /* Never respond on first call */ 154 if (NULL == *req_cls) 155 { 156 struct ContentReaderUserdata *userdata; 157 fprintf (stderr, 158 "start: %u\n", 159 ++request_counter); 160 161 userdata = malloc (sizeof(struct ContentReaderUserdata)); 162 163 if (NULL == userdata) 164 return MHD_NO; 165 userdata->bytes_written = 0; 166 userdata->connection = connection; 167 *req_cls = userdata; 168 return MHD_YES; 169 } 170 171 /* Second call: create response */ 172 response 173 = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 174 32 * 1024, 175 &http_ContentReaderCallback, 176 *req_cls, 177 &free_crc_data); 178 ret = MHD_queue_response (connection, 179 MHD_HTTP_OK, 180 response); 181 MHD_destroy_response (response); 182 183 suspend_connection (connection); 184 return ret; 185 } 186 187 188 int 189 main (void) 190 { 191 uint16_t port; 192 char command_line[1024]; 193 /* Flags */ 194 unsigned int daemon_flags 195 = MHD_USE_INTERNAL_POLLING_THREAD 196 | MHD_USE_AUTO 197 | MHD_ALLOW_SUSPEND_RESUME 198 | MHD_USE_ITC; 199 struct MHD_Daemon *daemon; 200 201 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 202 port = 0; 203 else 204 port = 1470; 205 206 /* Panic callback */ 207 MHD_set_panic_func (&http_PanicCallback, 208 NULL); 209 210 211 /* Create daemon */ 212 daemon = MHD_start_daemon (daemon_flags, 213 port, 214 NULL, 215 NULL, 216 &http_AccessHandlerCallback, 217 NULL, 218 MHD_OPTION_END); 219 if (NULL == daemon) 220 return 1; 221 if (0 == port) 222 { 223 const union MHD_DaemonInfo *dinfo; 224 dinfo = MHD_get_daemon_info (daemon, MHD_DAEMON_INFO_BIND_PORT); 225 if ((NULL == dinfo) || (0 == dinfo->port) ) 226 { 227 MHD_stop_daemon (daemon); return 32; 228 } 229 port = dinfo->port; 230 } 231 snprintf (command_line, 232 sizeof (command_line), 233 "curl -s http://127.0.0.1:%u", 234 (unsigned int) port); 235 236 if (0 != system (command_line)) 237 { 238 MHD_stop_daemon (daemon); 239 return 1; 240 } 241 /* wait for a request */ 242 while (0 == request_counter) 243 (void) sleep (1); 244 245 fprintf (stderr, 246 "quiesce\n"); 247 MHD_quiesce_daemon (daemon); 248 249 /* wait a second */ 250 (void) sleep (1); 251 252 fprintf (stderr, 253 "stopping daemon\n"); 254 MHD_stop_daemon (daemon); 255 256 return 0; 257 }