1/* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2009, 2011 Christian Grothoff 4 5 libmicrohttpd is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 2, or (at your 8 option) any later version. 9 10 libmicrohttpd is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libmicrohttpd; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 Boston, MA 02111-1307, USA. 19*/ 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 */ 27 28 29#include "MHD_config.h" 30#include "platform.h" 31#include <curl/curl.h> 32#include <microhttpd.h> 33 34struct callback_closure { 35 unsigned int called; 36}; 37 38 39static ssize_t 40called_twice(void *cls, uint64_t pos, char *buf, size_t max) 41{ 42 struct callback_closure *cls2 = cls; 43 44 if (cls2->called == 0) 45 { 46 memset(buf, 0, max); 47 strcat(buf, "test"); 48 cls2->called = 1; 49 return strlen(buf); 50 } 51 if (cls2->called == 1) 52 { 53 cls2->called = 2; 54 return MHD_CONTENT_READER_END_OF_STREAM; 55 } 56 fprintf(stderr, 57 "Handler called after returning END_OF_STREAM!\n"); 58 return MHD_CONTENT_READER_END_WITH_ERROR; 59} 60 61 62static int 63callback(void *cls, struct MHD_Connection *connection, const char *url, 64 const char *method, const char *version, const char *upload_data, 65 size_t *upload_data_size, void **con_cls) { 66 struct callback_closure *cbc = calloc(1, sizeof(struct callback_closure)); 67 struct MHD_Response *r; 68 69 r = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024, 70 &called_twice, cbc, 71 &free); 72 MHD_queue_response(connection, 200, r); 73 MHD_destroy_response(r); 74 return MHD_YES; 75} 76 77 78static size_t 79discard_buffer (void *ptr, size_t size, size_t nmemb, void *ctx) 80{ 81 return size * nmemb; 82} 83 84 85int main(int argc, char **argv) 86{ 87 struct MHD_Daemon *d; 88 fd_set rs; 89 fd_set ws; 90 fd_set es; 91 MHD_socket max; 92 CURL *c; 93 CURLM *multi; 94 CURLMcode mret; 95 struct CURLMsg *msg; 96 int running; 97 struct timeval tv; 98 int extra; 99 100 d = MHD_start_daemon(0, 101 8000, 102 NULL, 103 NULL, 104 callback, 105 NULL, 106 MHD_OPTION_END); 107 c = curl_easy_init (); 108 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:8000/"); 109 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &discard_buffer); 110 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); 111 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 112 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 113 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 114 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 115 multi = curl_multi_init (); 116 if (multi == NULL) 117 { 118 curl_easy_cleanup (c); 119 MHD_stop_daemon (d); 120 return 1; 121 } 122 mret = curl_multi_add_handle (multi, c); 123 if (mret != CURLM_OK) 124 { 125 curl_multi_cleanup (multi); 126 curl_easy_cleanup (c); 127 MHD_stop_daemon (d); 128 return 2; 129 } 130 extra = 10; 131 while ( (c != NULL) || (--extra > 0) ) 132 { 133 max = MHD_INVALID_SOCKET; 134 FD_ZERO(&ws); 135 FD_ZERO(&rs); 136 FD_ZERO(&es); 137 curl_multi_perform (multi, &running); 138 if (NULL != multi) 139 { 140 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); 141 if (mret != CURLM_OK) 142 { 143 curl_multi_remove_handle (multi, c); 144 curl_multi_cleanup (multi); 145 curl_easy_cleanup (c); 146 MHD_stop_daemon (d); 147 return 3; 148 } 149 } 150 if (MHD_YES != 151 MHD_get_fdset(d, &rs, &ws, &es, &max)) 152 { 153 curl_multi_remove_handle (multi, c); 154 curl_multi_cleanup (multi); 155 curl_easy_cleanup (c); 156 MHD_stop_daemon (d); 157 return 4; 158 } 159 tv.tv_sec = 0; 160 tv.tv_usec = 1000; 161 select(max + 1, &rs, &ws, &es, &tv); 162 if (NULL != multi) 163 { 164 curl_multi_perform (multi, &running); 165 if (running == 0) 166 { 167 msg = curl_multi_info_read (multi, &running); 168 if (msg == NULL) 169 break; 170 if (msg->msg == CURLMSG_DONE) 171 { 172 if (msg->data.result != CURLE_OK) 173 printf ("%s failed at %s:%d: `%s'\n", 174 "curl_multi_perform", 175 __FILE__, 176 __LINE__, curl_easy_strerror (msg->data.result)); 177 curl_multi_remove_handle (multi, c); 178 curl_multi_cleanup (multi); 179 curl_easy_cleanup (c); 180 c = NULL; 181 multi = NULL; 182 } 183 } 184 } 185 MHD_run(d); 186 } 187 MHD_stop_daemon(d); 188 return 0; 189} 190