test_quiesce_stream.c (6913B)
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 36 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 37 test into a marked, classifiable test error (TESTING.md, P5). */ 38 #include "mhd_panic_tripwire.h" 39 #ifdef HAVE_UNISTD_H 40 #include <unistd.h> 41 #elif defined(_WIN32) 42 #include <windows.h> 43 #define sleep(s) (Sleep ((s) * 1000), 0) 44 #endif /* _WIN32 */ 45 46 47 static volatile unsigned int request_counter; 48 49 50 _MHD_NORETURN static void 51 http_PanicCallback (void *cls, 52 const char *file, 53 unsigned int line, 54 const char *reason) 55 { 56 (void) cls; /* Unused. Silent compiler warning. */ 57 fprintf (stderr, 58 "PANIC: exit process: %s at %s:%u\n", 59 reason, 60 file, 61 line); 62 exit (EXIT_FAILURE); 63 } 64 65 66 static void * 67 resume_connection (void *arg) 68 { 69 struct MHD_Connection *connection = arg; 70 71 /* fprintf (stderr, "Calling resume\n"); */ 72 MHD_resume_connection (connection); 73 return NULL; 74 } 75 76 77 static void 78 suspend_connection (struct MHD_Connection *connection) 79 { 80 pthread_t thread_id; 81 int status; 82 83 /* fprintf (stderr, "Calling suspend\n"); */ 84 MHD_suspend_connection (connection); 85 status = pthread_create (&thread_id, 86 NULL, 87 &resume_connection, 88 connection); 89 if (0 != status) 90 { 91 fprintf (stderr, 92 "Could not create thead\n"); 93 exit (EXIT_FAILURE); 94 } 95 pthread_detach (thread_id); 96 } 97 98 99 struct ContentReaderUserdata 100 { 101 size_t bytes_written; 102 struct MHD_Connection *connection; 103 }; 104 105 106 static ssize_t 107 http_ContentReaderCallback (void *cls, 108 uint64_t pos, 109 char *buf, 110 size_t max) 111 { 112 static const char alphabet[] = 113 "\nABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 114 struct ContentReaderUserdata *userdata = cls; 115 (void) pos; (void) max; /* Unused. Silent compiler warning. */ 116 117 if (userdata->bytes_written >= 1024) 118 { 119 fprintf (stderr, 120 "finish: %u\n", 121 request_counter); 122 return MHD_CONTENT_READER_END_OF_STREAM; 123 } 124 userdata->bytes_written++; 125 buf[0] = alphabet[userdata->bytes_written % (sizeof(alphabet) - 1)]; 126 suspend_connection (userdata->connection); 127 128 return 1; 129 } 130 131 132 static void 133 free_crc_data (void *crc_data) 134 { 135 struct ContentReaderUserdata *userdata = crc_data; 136 137 free (userdata); 138 } 139 140 141 static enum MHD_Result 142 http_AccessHandlerCallback (void *cls, 143 struct MHD_Connection *connection, 144 const char *url, 145 const char *method, 146 const char *version, 147 const char *upload_data, 148 size_t *upload_data_size, 149 void **req_cls) 150 { 151 enum MHD_Result ret; 152 struct MHD_Response *response; 153 (void) cls; (void) url; /* Unused. Silent compiler warning. */ 154 (void) method; (void) version; (void) upload_data; /* Unused. Silent compiler warning. */ 155 (void) upload_data_size; /* Unused. Silent compiler warning. */ 156 157 /* Never respond on first call */ 158 if (NULL == *req_cls) 159 { 160 struct ContentReaderUserdata *userdata; 161 fprintf (stderr, 162 "start: %u\n", 163 ++request_counter); 164 165 userdata = malloc (sizeof(struct ContentReaderUserdata)); 166 167 if (NULL == userdata) 168 return MHD_NO; 169 userdata->bytes_written = 0; 170 userdata->connection = connection; 171 *req_cls = userdata; 172 return MHD_YES; 173 } 174 175 /* Second call: create response */ 176 response 177 = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 178 32 * 1024, 179 &http_ContentReaderCallback, 180 *req_cls, 181 &free_crc_data); 182 ret = MHD_queue_response (connection, 183 MHD_HTTP_OK, 184 response); 185 MHD_destroy_response (response); 186 187 suspend_connection (connection); 188 return ret; 189 } 190 191 192 int 193 main (void) 194 { 195 uint16_t port; 196 char command_line[1024]; 197 /* Flags */ 198 unsigned int daemon_flags 199 = MHD_USE_INTERNAL_POLLING_THREAD 200 | MHD_USE_AUTO 201 | MHD_ALLOW_SUSPEND_RESUME 202 | MHD_USE_ITC; 203 struct MHD_Daemon *daemon; 204 205 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 206 port = 0; 207 else 208 port = 1470; 209 210 /* Panic callback */ 211 MHD_set_panic_func (&http_PanicCallback, 212 NULL); 213 214 215 /* Create daemon */ 216 daemon = MHD_start_daemon (daemon_flags, 217 port, 218 NULL, 219 NULL, 220 &http_AccessHandlerCallback, 221 NULL, 222 MHD_OPTION_END); 223 if (NULL == daemon) 224 return 1; 225 if (0 == port) 226 { 227 const union MHD_DaemonInfo *dinfo; 228 dinfo = MHD_get_daemon_info (daemon, MHD_DAEMON_INFO_BIND_PORT); 229 if ((NULL == dinfo) || (0 == dinfo->port) ) 230 { 231 MHD_stop_daemon (daemon); return 32; 232 } 233 port = dinfo->port; 234 } 235 snprintf (command_line, 236 sizeof (command_line), 237 "curl -s http://127.0.0.1:%u", 238 (unsigned int) port); 239 240 if (0 != system (command_line)) 241 { 242 MHD_stop_daemon (daemon); 243 return 1; 244 } 245 /* wait for a request */ 246 while (0 == request_counter) 247 (void) sleep (1); 248 249 fprintf (stderr, 250 "quiesce\n"); 251 MHD_quiesce_daemon (daemon); 252 253 /* wait a second */ 254 (void) sleep (1); 255 256 fprintf (stderr, 257 "stopping daemon\n"); 258 MHD_stop_daemon (daemon); 259 260 return 0; 261 }