test_callback.c (7575B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2009, 2011 Christian Grothoff 4 Copyright (C) 2014-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_callback.c 23 * @brief Testcase for MHD not calling the callback too often 24 * @author Jan Seeger 25 * @author Christian Grothoff 26 * @author Karlson2k (Evgeny Grin) 27 */ 28 #include "MHD_config.h" 29 #include "platform.h" 30 #include <curl/curl.h> 31 #include <microhttpd.h> 32 #include <errno.h> 33 34 struct callback_closure 35 { 36 unsigned int called; 37 }; 38 39 40 static ssize_t 41 called_twice (void *cls, uint64_t pos, char *buf, size_t max) 42 { 43 struct callback_closure *cls2 = cls; 44 45 (void) pos; /* Unused. Silence compiler warning. */ 46 (void) max; 47 if (cls2->called == 0) 48 { 49 memcpy (buf, "test", 5); 50 cls2->called = 1; 51 return (ssize_t) strlen (buf); 52 } 53 if (cls2->called == 1) 54 { 55 cls2->called = 2; 56 return MHD_CONTENT_READER_END_OF_STREAM; 57 } 58 fprintf (stderr, 59 "Handler called after returning END_OF_STREAM!\n"); 60 abort (); 61 return MHD_CONTENT_READER_END_WITH_ERROR; 62 } 63 64 65 static enum MHD_Result 66 callback (void *cls, 67 struct MHD_Connection *connection, 68 const char *url, 69 const char *method, 70 const char *version, 71 const char *upload_data, 72 size_t *upload_data_size, 73 void **req_cls) 74 { 75 struct callback_closure *cbc = calloc (1, sizeof(struct callback_closure)); 76 struct MHD_Response *r; 77 enum MHD_Result ret; 78 79 (void) cls; 80 (void) url; /* Unused. Silent compiler warning. */ 81 (void) method; 82 (void) version; 83 (void) upload_data; /* Unused. Silent compiler warning. */ 84 (void) upload_data_size; 85 (void) req_cls; /* Unused. Silent compiler warning. */ 86 87 if (NULL == cbc) 88 return MHD_NO; 89 r = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024, 90 &called_twice, cbc, 91 &free); 92 if (NULL == r) 93 { 94 free (cbc); 95 return MHD_NO; 96 } 97 ret = MHD_queue_response (connection, 98 MHD_HTTP_OK, 99 r); 100 MHD_destroy_response (r); 101 return ret; 102 } 103 104 105 static size_t 106 discard_buffer (void *ptr, 107 size_t size, 108 size_t nmemb, 109 void *ctx) 110 { 111 (void) ptr; (void) ctx; /* Unused. Silent compiler warning. */ 112 return size * nmemb; 113 } 114 115 116 int 117 main (int argc, char **argv) 118 { 119 struct MHD_Daemon *d; 120 fd_set rs; 121 fd_set ws; 122 fd_set es; 123 MHD_socket maxsock; 124 #ifdef MHD_WINSOCK_SOCKETS 125 int maxposixs; /* Max socket number unused on W32 */ 126 #else /* MHD_POSIX_SOCKETS */ 127 #define maxposixs maxsock 128 #endif /* MHD_POSIX_SOCKETS */ 129 CURL *c; 130 CURLM *multi; 131 CURLMcode mret; 132 struct CURLMsg *msg; 133 int running; 134 struct timeval tv; 135 int extra; 136 uint16_t port; 137 (void) argc; (void) argv; /* Unused. Silent compiler warning. */ 138 139 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 140 port = 0; 141 else 142 port = 1140; 143 144 d = MHD_start_daemon (MHD_USE_NO_THREAD_SAFETY, 145 port, 146 NULL, 147 NULL, 148 &callback, 149 NULL, 150 MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE, 151 MHD_OPTION_END); 152 if (d == NULL) 153 return 32; 154 if (0 == port) 155 { 156 const union MHD_DaemonInfo *dinfo; 157 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 158 if ((NULL == dinfo) || (0 == dinfo->port) ) 159 { 160 MHD_stop_daemon (d); return 48; 161 } 162 port = dinfo->port; 163 } 164 c = curl_easy_init (); 165 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/"); 166 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 167 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &discard_buffer); 168 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 169 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 170 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 171 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 172 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 173 multi = curl_multi_init (); 174 if (multi == NULL) 175 { 176 curl_easy_cleanup (c); 177 MHD_stop_daemon (d); 178 return 99; 179 } 180 mret = curl_multi_add_handle (multi, c); 181 if (mret != CURLM_OK) 182 { 183 curl_multi_cleanup (multi); 184 curl_easy_cleanup (c); 185 MHD_stop_daemon (d); 186 return 99; 187 } 188 extra = 10; 189 while ( (c != NULL) || (--extra > 0) ) 190 { 191 maxsock = MHD_INVALID_SOCKET; 192 maxposixs = -1; 193 FD_ZERO (&ws); 194 FD_ZERO (&rs); 195 FD_ZERO (&es); 196 curl_multi_perform (multi, &running); 197 if (NULL != multi) 198 { 199 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs); 200 if (mret != CURLM_OK) 201 { 202 curl_multi_remove_handle (multi, c); 203 curl_multi_cleanup (multi); 204 curl_easy_cleanup (c); 205 MHD_stop_daemon (d); 206 return 99; 207 } 208 } 209 if (MHD_YES != 210 MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) 211 { 212 curl_multi_remove_handle (multi, c); 213 curl_multi_cleanup (multi); 214 curl_easy_cleanup (c); 215 MHD_stop_daemon (d); 216 return 4; 217 } 218 tv.tv_sec = 0; 219 tv.tv_usec = 1000; 220 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) 221 { 222 #ifdef MHD_POSIX_SOCKETS 223 if (EINTR != errno) 224 { 225 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", 226 (int) errno, __LINE__); 227 fflush (stderr); 228 exit (99); 229 } 230 #else 231 if ((WSAEINVAL != WSAGetLastError ()) || 232 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 233 { 234 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", 235 (int) WSAGetLastError (), __LINE__); 236 fflush (stderr); 237 exit (99); 238 } 239 Sleep (1); 240 #endif 241 } 242 if (NULL != multi) 243 { 244 curl_multi_perform (multi, &running); 245 if (0 == running) 246 { 247 int pending; 248 int curl_fine = 0; 249 while (NULL != (msg = curl_multi_info_read (multi, &pending))) 250 { 251 if (msg->msg == CURLMSG_DONE) 252 { 253 if (msg->data.result == CURLE_OK) 254 curl_fine = 1; 255 else 256 { 257 fprintf (stderr, 258 "%s failed at %s:%d: `%s'\n", 259 "curl_multi_perform", 260 __FILE__, 261 __LINE__, curl_easy_strerror (msg->data.result)); 262 abort (); 263 } 264 } 265 } 266 if (! curl_fine) 267 { 268 fprintf (stderr, "libcurl haven't returned OK code\n"); 269 abort (); 270 } 271 curl_multi_remove_handle (multi, c); 272 curl_multi_cleanup (multi); 273 curl_easy_cleanup (c); 274 c = NULL; 275 multi = NULL; 276 } 277 } 278 MHD_run (d); 279 } 280 MHD_stop_daemon (d); 281 return 0; 282 }