aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2007-06-16 07:23:19 +0000
committerChristian Grothoff <christian@grothoff.org>2007-06-16 07:23:19 +0000
commit553f84de5cc0efb7b5af14308463cfabd9a2d966 (patch)
tree589e6db19f934bf9901f9a13e3d22131a250c5d7
parentb3523e0462066f6f9da7669bcea7de5d639f2020 (diff)
downloadlibmicrohttpd-553f84de5cc0efb7b5af14308463cfabd9a2d966.tar.gz
libmicrohttpd-553f84de5cc0efb7b5af14308463cfabd9a2d966.zip
adding testcases for PUT and POST
-rw-r--r--src/daemon/Makefile.am18
-rw-r--r--src/daemon/daemon.c6
-rw-r--r--src/daemon/daemontest1.c2
-rw-r--r--src/daemon/daemontest_post.c399
-rw-r--r--src/daemon/daemontest_put.c448
-rw-r--r--src/daemon/session.c17
6 files changed, 880 insertions, 10 deletions
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 048c3176..7eda834b 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -32,7 +32,9 @@ if HAVE_CURL
32 32
33check_PROGRAMS = \ 33check_PROGRAMS = \
34 daemontest \ 34 daemontest \
35 daemontest1 35 daemontest1 \
36 daemontest_post \
37 daemontest_put
36 38
37TESTS = $(check_PROGRAMS) 39TESTS = $(check_PROGRAMS)
38 40
@@ -47,4 +49,18 @@ daemontest1_LDADD = \
47 $(top_builddir)/src/daemon/libmicrohttpd.la \ 49 $(top_builddir)/src/daemon/libmicrohttpd.la \
48 @LIBCURL@ 50 @LIBCURL@
49 51
52
53daemontest_post_SOURCES = \
54 daemontest_post.c
55daemontest_post_LDADD = \
56 $(top_builddir)/src/daemon/libmicrohttpd.la \
57 @LIBCURL@
58
59
60daemontest_put_SOURCES = \
61 daemontest_put.c
62daemontest_put_LDADD = \
63 $(top_builddir)/src/daemon/libmicrohttpd.la \
64 @LIBCURL@
65
50endif \ No newline at end of file 66endif \ No newline at end of file
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index 07f1ae71..f393355b 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -317,7 +317,7 @@ MHD_cleanup_sessions(struct MHD_Daemon * daemon) {
317 } 317 }
318 318
319 if ( (pos->headersReceived == 1) && 319 if ( (pos->headersReceived == 1) &&
320 (pos->readLoc > 0) ) 320 (pos->response == NULL) )
321 MHD_call_session_handler(pos); 321 MHD_call_session_handler(pos);
322 322
323 prev = pos; 323 prev = pos;
@@ -390,8 +390,10 @@ MHD_select(struct MHD_Daemon * daemon,
390 pos = daemon->connections; 390 pos = daemon->connections;
391 while (pos != NULL) { 391 while (pos != NULL) {
392 ds = pos->socket_fd; 392 ds = pos->socket_fd;
393 if (ds == -1) 393 if (ds == -1) {
394 pos = pos->next;
394 continue; 395 continue;
396 }
395 if (FD_ISSET(ds, &rs)) 397 if (FD_ISSET(ds, &rs))
396 MHD_session_handle_read(pos); 398 MHD_session_handle_read(pos);
397 if (FD_ISSET(ds, &ws)) 399 if (FD_ISSET(ds, &ws))
diff --git a/src/daemon/daemontest1.c b/src/daemon/daemontest1.c
index 354da630..d3b6c5bc 100644
--- a/src/daemon/daemontest1.c
+++ b/src/daemon/daemontest1.c
@@ -21,7 +21,7 @@
21/** 21/**
22 * @file daemontest1.c 22 * @file daemontest1.c
23 * @brief Testcase for libmicrohttpd GET operations 23 * @brief Testcase for libmicrohttpd GET operations
24 * TODO: external select, parsing of query 24 * TODO: test parsing of query
25 * @author Christian Grothoff 25 * @author Christian Grothoff
26 */ 26 */
27 27
diff --git a/src/daemon/daemontest_post.c b/src/daemon/daemontest_post.c
new file mode 100644
index 00000000..5e46bac3
--- /dev/null
+++ b/src/daemon/daemontest_post.c
@@ -0,0 +1,399 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 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 daemontest_post.c
23 * @brief Testcase for libmicrohttpd POST operations
24 * TODO: use curl_formadd to produce POST data and
25 * add that to the CURL operation; then check
26 * on the server side if the headers arrive
27 * nicely (need to implement parsing POST data
28 * first!)
29 * @author Christian Grothoff
30 */
31
32#include "config.h"
33#include <curl/curl.h>
34#include <microhttpd.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <string.h>
38#include <time.h>
39
40static int apc_all(void * cls,
41 const struct sockaddr * addr,
42 socklen_t addrlen) {
43 return MHD_YES;
44}
45
46struct CBC {
47 char * buf;
48 size_t pos;
49 size_t size;
50};
51
52static size_t copyBuffer(void * ptr,
53 size_t size,
54 size_t nmemb,
55 void * ctx) {
56 struct CBC * cbc = ctx;
57
58 if (cbc->pos + size * nmemb > cbc->size)
59 return 0; /* overflow */
60 memcpy(&cbc->buf[cbc->pos],
61 ptr,
62 size * nmemb);
63 cbc->pos += size * nmemb;
64 return size * nmemb;
65}
66
67static int ahc_echo(void * cls,
68 struct MHD_Session * session,
69 const char * url,
70 const char * method,
71 const char * upload_data,
72 unsigned int * upload_data_size) {
73 struct MHD_Response * response;
74 int ret;
75
76 if (0 != strcmp("POST", method)) {
77 printf("METHOD: %s\n", method);
78 return MHD_NO; /* unexpected method */
79 }
80 /* FIXME: check session headers... */
81 response = MHD_create_response_from_data(strlen(url),
82 (void*) url,
83 MHD_NO,
84 MHD_YES);
85 ret = MHD_queue_response(session,
86 MHD_HTTP_OK,
87 response);
88 MHD_destroy_response(response);
89 return ret;
90}
91
92
93static int testInternalPost() {
94 struct MHD_Daemon * d;
95 CURL * c;
96 char buf[2048];
97 struct CBC cbc;
98
99 cbc.buf = buf;
100 cbc.size = 2048;
101 cbc.pos = 0;
102 d = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY | MHD_USE_IPv4 | MHD_USE_DEBUG,
103 1080,
104 &apc_all,
105 NULL,
106 &ahc_echo,
107 NULL);
108 if (d == NULL)
109 return 1;
110 c = curl_easy_init();
111 curl_easy_setopt(c,
112 CURLOPT_URL,
113 "http://localhost:1080/hello_world");
114 curl_easy_setopt(c,
115 CURLOPT_WRITEFUNCTION,
116 &copyBuffer);
117 curl_easy_setopt(c,
118 CURLOPT_WRITEDATA,
119 &cbc);
120 curl_easy_setopt(c,
121 CURLOPT_HTTPPOST,
122 NULL); /* FIXME! */
123 curl_easy_setopt(c,
124 CURLOPT_POST,
125 1L);
126 curl_easy_setopt(c,
127 CURLOPT_FAILONERROR,
128 1);
129 curl_easy_setopt(c,
130 CURLOPT_TIMEOUT,
131 2L);
132 curl_easy_setopt(c,
133 CURLOPT_CONNECTTIMEOUT,
134 2L);
135 // NOTE: use of CONNECTTIMEOUT without also
136 // setting NOSIGNAL results in really weird
137 // crashes on my system!
138 curl_easy_setopt(c,
139 CURLOPT_NOSIGNAL,
140 1);
141 if (CURLE_OK != curl_easy_perform(c)) {
142 curl_easy_cleanup(c);
143 MHD_stop_daemon(d);
144 return 2;
145 }
146 curl_easy_cleanup(c);
147 if (cbc.pos != strlen("/hello_world")) {
148 MHD_stop_daemon(d);
149 return 4;
150 }
151
152 if (0 != strncmp("/hello_world",
153 cbc.buf,
154 strlen("/hello_world"))) {
155 MHD_stop_daemon(d);
156 return 8;
157 }
158 MHD_stop_daemon(d);
159
160 return 0;
161}
162
163static int testMultithreadedPost() {
164 struct MHD_Daemon * d;
165 CURL * c;
166 char buf[2048];
167 struct CBC cbc;
168
169 cbc.buf = buf;
170 cbc.size = 2048;
171 cbc.pos = 0;
172 d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION | MHD_USE_IPv4 | MHD_USE_DEBUG,
173 1081,
174 &apc_all,
175 NULL,
176 &ahc_echo,
177 NULL);
178 if (d == NULL)
179 return 16;
180 c = curl_easy_init();
181 curl_easy_setopt(c,
182 CURLOPT_URL,
183 "http://localhost:1081/hello_world");
184 curl_easy_setopt(c,
185 CURLOPT_WRITEFUNCTION,
186 &copyBuffer);
187 curl_easy_setopt(c,
188 CURLOPT_WRITEDATA,
189 &cbc);
190 curl_easy_setopt(c,
191 CURLOPT_HTTPPOST,
192 NULL); /* FIXME! */
193 curl_easy_setopt(c,
194 CURLOPT_POST,
195 1L);
196 curl_easy_setopt(c,
197 CURLOPT_FAILONERROR,
198 1);
199 curl_easy_setopt(c,
200 CURLOPT_TIMEOUT,
201 2L);
202 curl_easy_setopt(c,
203 CURLOPT_CONNECTTIMEOUT,
204 2L);
205 // NOTE: use of CONNECTTIMEOUT without also
206 // setting NOSIGNAL results in really weird
207 // crashes on my system!
208 curl_easy_setopt(c,
209 CURLOPT_NOSIGNAL,
210 1);
211 if (CURLE_OK != curl_easy_perform(c)) {
212 curl_easy_cleanup(c);
213 MHD_stop_daemon(d);
214 return 32;
215 }
216 curl_easy_cleanup(c);
217 if (cbc.pos != strlen("/hello_world")) {
218 MHD_stop_daemon(d);
219 return 64;
220 }
221 if (0 != strncmp("/hello_world",
222 cbc.buf,
223 strlen("/hello_world"))) {
224 MHD_stop_daemon(d);
225 return 128;
226 }
227 MHD_stop_daemon(d);
228
229 return 0;
230}
231
232
233static int testExternalPost() {
234 struct MHD_Daemon * d;
235 CURL * c;
236 char buf[2048];
237 struct CBC cbc;
238 CURLM * multi;
239 CURLMcode mret;
240 fd_set rs;
241 fd_set ws;
242 fd_set es;
243 int max;
244 int running;
245 struct CURLMsg * msg;
246 time_t start;
247 struct timeval tv;
248
249 multi = NULL;
250 cbc.buf = buf;
251 cbc.size = 2048;
252 cbc.pos = 0;
253 d = MHD_start_daemon(MHD_USE_IPv4 | MHD_USE_DEBUG,
254 1082,
255 &apc_all,
256 NULL,
257 &ahc_echo,
258 NULL);
259 if (d == NULL)
260 return 256;
261 c = curl_easy_init();
262 curl_easy_setopt(c,
263 CURLOPT_URL,
264 "http://localhost:1082/hello_world");
265 curl_easy_setopt(c,
266 CURLOPT_WRITEFUNCTION,
267 &copyBuffer);
268 curl_easy_setopt(c,
269 CURLOPT_WRITEDATA,
270 &cbc);
271 curl_easy_setopt(c,
272 CURLOPT_HTTPPOST,
273 NULL); /* FIXME! */
274 curl_easy_setopt(c,
275 CURLOPT_POST,
276 1L);
277 curl_easy_setopt(c,
278 CURLOPT_FAILONERROR,
279 1);
280 curl_easy_setopt(c,
281 CURLOPT_TIMEOUT,
282 5L);
283 curl_easy_setopt(c,
284 CURLOPT_CONNECTTIMEOUT,
285 5L);
286 // NOTE: use of CONNECTTIMEOUT without also
287 // setting NOSIGNAL results in really weird
288 // crashes on my system!
289 curl_easy_setopt(c,
290 CURLOPT_NOSIGNAL,
291 1);
292
293
294 multi = curl_multi_init();
295 if (multi == NULL) {
296 curl_easy_cleanup(c);
297 MHD_stop_daemon(d);
298 return 512;
299 }
300 mret = curl_multi_add_handle(multi, c);
301 if (mret != CURLM_OK) {
302 curl_multi_cleanup(multi);
303 curl_easy_cleanup(c);
304 MHD_stop_daemon(d);
305 return 1024;
306 }
307 start = time(NULL);
308 while ( (time(NULL) - start < 5) &&
309 (multi != NULL) ) {
310 max = 0;
311 FD_ZERO(&rs);
312 FD_ZERO(&ws);
313 FD_ZERO(&es);
314 curl_multi_perform(multi, &running);
315 mret = curl_multi_fdset(multi,
316 &rs,
317 &ws,
318 &es,
319 &max);
320 if (mret != CURLM_OK) {
321 curl_multi_remove_handle(multi, c);
322 curl_multi_cleanup(multi);
323 curl_easy_cleanup(c);
324 MHD_stop_daemon(d);
325 return 2048;
326 }
327 if (MHD_YES != MHD_get_fdset(d,
328 &rs,
329 &ws,
330 &es,
331 &max)) {
332 curl_multi_remove_handle(multi, c);
333 curl_multi_cleanup(multi);
334 curl_easy_cleanup(c);
335 MHD_stop_daemon(d);
336 return 4096;
337 }
338 tv.tv_sec = 0;
339 tv.tv_usec = 1000;
340 select(max + 1,
341 &rs,
342 &ws,
343 &es,
344 &tv);
345 curl_multi_perform(multi, &running);
346 if (running == 0) {
347 msg = curl_multi_info_read(multi,
348 &running);
349 if (msg == NULL)
350 break;
351 if (msg->msg == CURLMSG_DONE) {
352 if (msg->data.result != CURLE_OK)
353 printf("%s failed at %s:%d: `%s'\n",
354 "curl_multi_perform",
355 __FILE__,
356 __LINE__,
357 curl_easy_strerror(msg->data.result));
358 curl_multi_remove_handle(multi, c);
359 curl_multi_cleanup(multi);
360 curl_easy_cleanup(c);
361 c = NULL;
362 multi = NULL;
363 }
364 }
365 MHD_run(d);
366 }
367 if (multi != NULL) {
368 curl_multi_remove_handle(multi, c);
369 curl_easy_cleanup(c);
370 curl_multi_cleanup(multi);
371 }
372 MHD_stop_daemon(d);
373 if (cbc.pos != strlen("/hello_world"))
374 return 8192;
375 if (0 != strncmp("/hello_world",
376 cbc.buf,
377 strlen("/hello_world")))
378 return 16384;
379 return 0;
380}
381
382
383
384int main(int argc,
385 char * const * argv) {
386 unsigned int errorCount = 0;
387
388 if (0 != curl_global_init(CURL_GLOBAL_WIN32))
389 return 2;
390 errorCount += testInternalPost();
391 errorCount += testMultithreadedPost();
392 errorCount += testExternalPost();
393 if (errorCount != 0)
394 fprintf(stderr,
395 "Error (code: %u)\n",
396 errorCount);
397 curl_global_cleanup();
398 return errorCount != 0; /* 0 == pass */
399}
diff --git a/src/daemon/daemontest_put.c b/src/daemon/daemontest_put.c
new file mode 100644
index 00000000..822f44a1
--- /dev/null
+++ b/src/daemon/daemontest_put.c
@@ -0,0 +1,448 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 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 daemontest_put.c
23 * @brief Testcase for libmicrohttpd PUT operations
24 * @author Christian Grothoff
25 */
26
27#include "config.h"
28#include <curl/curl.h>
29#include <microhttpd.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <string.h>
33#include <time.h>
34
35static int apc_all(void * cls,
36 const struct sockaddr * addr,
37 socklen_t addrlen) {
38 return MHD_YES;
39}
40
41struct CBC {
42 char * buf;
43 size_t pos;
44 size_t size;
45};
46
47static size_t putBuffer(void * stream,
48 size_t size,
49 size_t nmemb,
50 void * ptr) {
51 unsigned int * pos = ptr;
52 unsigned int wrt;
53
54 wrt = size * nmemb;
55 if (wrt > 8 - (*pos))
56 wrt = 8 - (*pos);
57 memcpy(stream,
58 &("Hello123"[*pos]),
59 wrt);
60 (*pos) += wrt;
61 return wrt;
62}
63
64static size_t copyBuffer(void * ptr,
65 size_t size,
66 size_t nmemb,
67 void * ctx) {
68 struct CBC * cbc = ctx;
69
70 if (cbc->pos + size * nmemb > cbc->size)
71 return 0; /* overflow */
72 memcpy(&cbc->buf[cbc->pos],
73 ptr,
74 size * nmemb);
75 cbc->pos += size * nmemb;
76 return size * nmemb;
77}
78
79static int ahc_echo(void * cls,
80 struct MHD_Session * session,
81 const char * url,
82 const char * method,
83 const char * upload_data,
84 unsigned int * upload_data_size) {
85 int * done = cls;
86 struct MHD_Response * response;
87 int ret;
88
89 if (0 != strcmp("PUT", method))
90 return MHD_NO; /* unexpected method */
91 if ((*done) == 0) {
92 if (*upload_data_size != 8)
93 return MHD_YES; /* not yet ready */
94 if (0 == memcmp(upload_data,
95 "Hello123",
96 8)) {
97 *upload_data_size = 0;
98 } else {
99 printf("Invalid upload data `%8s'!\n",
100 upload_data);
101 return MHD_NO;
102 }
103 *done = 1;
104 return MHD_YES;
105 }
106 response = MHD_create_response_from_data(strlen(url),
107 (void*) url,
108 MHD_NO,
109 MHD_YES);
110 ret = MHD_queue_response(session,
111 MHD_HTTP_OK,
112 response);
113 MHD_destroy_response(response);
114 return ret;
115}
116
117
118static int testInternalPut() {
119 struct MHD_Daemon * d;
120 CURL * c;
121 char buf[2048];
122 struct CBC cbc;
123 unsigned int pos = 0;
124 int done_flag = 0;
125
126 cbc.buf = buf;
127 cbc.size = 2048;
128 cbc.pos = 0;
129 d = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY | MHD_USE_IPv4 | MHD_USE_DEBUG,
130 1080,
131 &apc_all,
132 NULL,
133 &ahc_echo,
134 &done_flag);
135 if (d == NULL)
136 return 1;
137 c = curl_easy_init();
138 curl_easy_setopt(c,
139 CURLOPT_URL,
140 "http://localhost:1080/hello_world");
141 curl_easy_setopt(c,
142 CURLOPT_WRITEFUNCTION,
143 &copyBuffer);
144 curl_easy_setopt(c,
145 CURLOPT_WRITEDATA,
146 &cbc);
147 curl_easy_setopt(c,
148 CURLOPT_READFUNCTION,
149 &putBuffer);
150 curl_easy_setopt(c,
151 CURLOPT_READDATA,
152 &pos);
153 curl_easy_setopt(c,
154 CURLOPT_UPLOAD,
155 1L);
156 curl_easy_setopt(c,
157 CURLOPT_INFILESIZE_LARGE,
158 (curl_off_t) 8L);
159 curl_easy_setopt(c,
160 CURLOPT_FAILONERROR,
161 1);
162 curl_easy_setopt(c,
163 CURLOPT_TIMEOUT,
164 15L);
165 curl_easy_setopt(c,
166 CURLOPT_CONNECTTIMEOUT,
167 15L);
168 // NOTE: use of CONNECTTIMEOUT without also
169 // setting NOSIGNAL results in really weird
170 // crashes on my system!
171 curl_easy_setopt(c,
172 CURLOPT_NOSIGNAL,
173 1);
174 if (CURLE_OK != curl_easy_perform(c)) {
175 curl_easy_cleanup(c);
176 MHD_stop_daemon(d);
177 return 2;
178 }
179 curl_easy_cleanup(c);
180 if (cbc.pos != strlen("/hello_world")) {
181 MHD_stop_daemon(d);
182 return 4;
183 }
184
185 if (0 != strncmp("/hello_world",
186 cbc.buf,
187 strlen("/hello_world"))) {
188 MHD_stop_daemon(d);
189 return 8;
190 }
191 MHD_stop_daemon(d);
192
193 return 0;
194}
195
196static int testMultithreadedPut() {
197 struct MHD_Daemon * d;
198 CURL * c;
199 char buf[2048];
200 struct CBC cbc;
201 unsigned int pos = 0;
202 int done_flag = 0;
203
204 cbc.buf = buf;
205 cbc.size = 2048;
206 cbc.pos = 0;
207 d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION | MHD_USE_IPv4 | MHD_USE_DEBUG,
208 1081,
209 &apc_all,
210 NULL,
211 &ahc_echo,
212 &done_flag);
213 if (d == NULL)
214 return 16;
215 c = curl_easy_init();
216 curl_easy_setopt(c,
217 CURLOPT_URL,
218 "http://localhost:1081/hello_world");
219 curl_easy_setopt(c,
220 CURLOPT_WRITEFUNCTION,
221 &copyBuffer);
222 curl_easy_setopt(c,
223 CURLOPT_WRITEDATA,
224 &cbc);
225 curl_easy_setopt(c,
226 CURLOPT_READFUNCTION,
227 &putBuffer);
228 curl_easy_setopt(c,
229 CURLOPT_READDATA,
230 &pos);
231 curl_easy_setopt(c,
232 CURLOPT_UPLOAD,
233 1L);
234 curl_easy_setopt(c,
235 CURLOPT_INFILESIZE_LARGE,
236 (curl_off_t) 8L);
237 curl_easy_setopt(c,
238 CURLOPT_FAILONERROR,
239 1);
240 curl_easy_setopt(c,
241 CURLOPT_TIMEOUT,
242 15L);
243 curl_easy_setopt(c,
244 CURLOPT_CONNECTTIMEOUT,
245 15L);
246 // NOTE: use of CONNECTTIMEOUT without also
247 // setting NOSIGNAL results in really weird
248 // crashes on my system!
249 curl_easy_setopt(c,
250 CURLOPT_NOSIGNAL,
251 1);
252 if (CURLE_OK != curl_easy_perform(c)) {
253 curl_easy_cleanup(c);
254 MHD_stop_daemon(d);
255 return 32;
256 }
257 curl_easy_cleanup(c);
258 if (cbc.pos != strlen("/hello_world")) {
259 MHD_stop_daemon(d);
260 return 64;
261 }
262 if (0 != strncmp("/hello_world",
263 cbc.buf,
264 strlen("/hello_world"))) {
265 MHD_stop_daemon(d);
266 return 128;
267 }
268 MHD_stop_daemon(d);
269
270 return 0;
271}
272
273
274static int testExternalPut() {
275 struct MHD_Daemon * d;
276 CURL * c;
277 char buf[2048];
278 struct CBC cbc;
279 CURLM * multi;
280 CURLMcode mret;
281 fd_set rs;
282 fd_set ws;
283 fd_set es;
284 int max;
285 int running;
286 struct CURLMsg * msg;
287 time_t start;
288 struct timeval tv;
289 unsigned int pos = 0;
290 int done_flag = 0;
291
292 multi = NULL;
293 cbc.buf = buf;
294 cbc.size = 2048;
295 cbc.pos = 0;
296 d = MHD_start_daemon(MHD_USE_IPv4 | MHD_USE_DEBUG,
297 1082,
298 &apc_all,
299 NULL,
300 &ahc_echo,
301 &done_flag);
302 if (d == NULL)
303 return 256;
304 c = curl_easy_init();
305 curl_easy_setopt(c,
306 CURLOPT_URL,
307 "http://localhost:1082/hello_world");
308 curl_easy_setopt(c,
309 CURLOPT_WRITEFUNCTION,
310 &copyBuffer);
311 curl_easy_setopt(c,
312 CURLOPT_WRITEDATA,
313 &cbc);
314 curl_easy_setopt(c,
315 CURLOPT_READFUNCTION,
316 &putBuffer);
317 curl_easy_setopt(c,
318 CURLOPT_READDATA,
319 &pos);
320 curl_easy_setopt(c,
321 CURLOPT_UPLOAD,
322 1L);
323 curl_easy_setopt(c,
324 CURLOPT_INFILESIZE_LARGE,
325 (curl_off_t) 8L);
326 curl_easy_setopt(c,
327 CURLOPT_FAILONERROR,
328 1);
329 curl_easy_setopt(c,
330 CURLOPT_TIMEOUT,
331 15L);
332 curl_easy_setopt(c,
333 CURLOPT_CONNECTTIMEOUT,
334 15L);
335 // NOTE: use of CONNECTTIMEOUT without also
336 // setting NOSIGNAL results in really weird
337 // crashes on my system!
338 curl_easy_setopt(c,
339 CURLOPT_NOSIGNAL,
340 1);
341
342
343 multi = curl_multi_init();
344 if (multi == NULL) {
345 curl_easy_cleanup(c);
346 MHD_stop_daemon(d);
347 return 512;
348 }
349 mret = curl_multi_add_handle(multi, c);
350 if (mret != CURLM_OK) {
351 curl_multi_cleanup(multi);
352 curl_easy_cleanup(c);
353 MHD_stop_daemon(d);
354 return 1024;
355 }
356 start = time(NULL);
357 while ( (time(NULL) - start < 5) &&
358 (multi != NULL) ) {
359 max = 0;
360 FD_ZERO(&rs);
361 FD_ZERO(&ws);
362 FD_ZERO(&es);
363 curl_multi_perform(multi, &running);
364 mret = curl_multi_fdset(multi,
365 &rs,
366 &ws,
367 &es,
368 &max);
369 if (mret != CURLM_OK) {
370 curl_multi_remove_handle(multi, c);
371 curl_multi_cleanup(multi);
372 curl_easy_cleanup(c);
373 MHD_stop_daemon(d);
374 return 2048;
375 }
376 if (MHD_YES != MHD_get_fdset(d,
377 &rs,
378 &ws,
379 &es,
380 &max)) {
381 curl_multi_remove_handle(multi, c);
382 curl_multi_cleanup(multi);
383 curl_easy_cleanup(c);
384 MHD_stop_daemon(d);
385 return 4096;
386 }
387 tv.tv_sec = 0;
388 tv.tv_usec = 1000;
389 select(max + 1,
390 &rs,
391 &ws,
392 &es,
393 &tv);
394 curl_multi_perform(multi, &running);
395 if (running == 0) {
396 msg = curl_multi_info_read(multi,
397 &running);
398 if (msg == NULL)
399 break;
400 if (msg->msg == CURLMSG_DONE) {
401 if (msg->data.result != CURLE_OK)
402 printf("%s failed at %s:%d: `%s'\n",
403 "curl_multi_perform",
404 __FILE__,
405 __LINE__,
406 curl_easy_strerror(msg->data.result));
407 curl_multi_remove_handle(multi, c);
408 curl_multi_cleanup(multi);
409 curl_easy_cleanup(c);
410 c = NULL;
411 multi = NULL;
412 }
413 }
414 MHD_run(d);
415 }
416 if (multi != NULL) {
417 curl_multi_remove_handle(multi, c);
418 curl_easy_cleanup(c);
419 curl_multi_cleanup(multi);
420 }
421 MHD_stop_daemon(d);
422 if (cbc.pos != strlen("/hello_world"))
423 return 8192;
424 if (0 != strncmp("/hello_world",
425 cbc.buf,
426 strlen("/hello_world")))
427 return 16384;
428 return 0;
429}
430
431
432
433int main(int argc,
434 char * const * argv) {
435 unsigned int errorCount = 0;
436
437 if (0 != curl_global_init(CURL_GLOBAL_WIN32))
438 return 2;
439 errorCount += testInternalPut();
440 errorCount += testMultithreadedPut();
441 errorCount += testExternalPut();
442 if (errorCount != 0)
443 fprintf(stderr,
444 "Error (code: %u)\n",
445 errorCount);
446 curl_global_cleanup();
447 return errorCount != 0; /* 0 == pass */
448}
diff --git a/src/daemon/session.c b/src/daemon/session.c
index 1af59e84..84ed6bc2 100644
--- a/src/daemon/session.c
+++ b/src/daemon/session.c
@@ -131,17 +131,22 @@ MHD_session_get_fdset(struct MHD_Session * session,
131 fd_set * write_fd_set, 131 fd_set * write_fd_set,
132 fd_set * except_fd_set, 132 fd_set * except_fd_set,
133 int * max_fd) { 133 int * max_fd) {
134 int fd;
135
136 fd = session->socket_fd;
137 if (fd == -1)
138 return MHD_YES;
134 if ( (session->read_close == 0) && 139 if ( (session->read_close == 0) &&
135 ( (session->headersReceived == 0) || 140 ( (session->headersReceived == 0) ||
136 (session->readLoc < session->read_buffer_size) ) ) 141 (session->readLoc < session->read_buffer_size) ) )
137 FD_SET(session->socket_fd, read_fd_set); 142 FD_SET(fd, read_fd_set);
138 if (session->response != NULL) 143 if (session->response != NULL)
139 FD_SET(session->socket_fd, write_fd_set); 144 FD_SET(fd, write_fd_set);
140 if ( (session->socket_fd > *max_fd) && 145 if ( (fd > *max_fd) &&
141 ( (session->headersReceived == 0) || 146 ( (session->headersReceived == 0) ||
142 (session->readLoc < session->read_buffer_size) || 147 (session->readLoc < session->read_buffer_size) ||
143 (session->response != NULL) ) ) 148 (session->response != NULL) ) )
144 *max_fd = session->socket_fd; 149 *max_fd = fd;
145 return MHD_YES; 150 return MHD_YES;
146} 151}
147 152
@@ -479,9 +484,9 @@ MHD_call_session_handler(struct MHD_Session * session) {
479 memmove(session->read_buffer, 484 memmove(session->read_buffer,
480 &session->read_buffer[session->readLoc - processed], 485 &session->read_buffer[session->readLoc - processed],
481 processed); 486 processed);
482 session->readLoc = processed;
483 if (session->uploadSize != -1) 487 if (session->uploadSize != -1)
484 session->uploadSize -= processed; 488 session->uploadSize -= (session->readLoc - processed);
489 session->readLoc = processed;
485 if ( (session->uploadSize == 0) || 490 if ( (session->uploadSize == 0) ||
486 ( (session->readLoc == 0) && 491 ( (session->readLoc == 0) &&
487 (session->uploadSize == -1) && 492 (session->uploadSize == -1) &&