aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl/test_patch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testcurl/test_patch.c')
-rw-r--r--src/testcurl/test_patch.c510
1 files changed, 510 insertions, 0 deletions
diff --git a/src/testcurl/test_patch.c b/src/testcurl/test_patch.c
new file mode 100644
index 00000000..86327b0d
--- /dev/null
+++ b/src/testcurl/test_patch.c
@@ -0,0 +1,510 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file test_patch.c
23 * @brief Testcase for libmicrohttpd PATCH operations
24 * @author Christian Grothoff
25 */
26
27#include "MHD_config.h"
28#include "platform.h"
29#include <curl/curl.h>
30#include <microhttpd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34#include "mhd_has_in_name.h"
35
36#ifndef WINDOWS
37#include <unistd.h>
38#endif
39
40#if defined(CPU_COUNT) && (CPU_COUNT + 0) < 2
41#undef CPU_COUNT
42#endif
43#if ! defined(CPU_COUNT)
44#define CPU_COUNT 2
45#endif
46
47static int oneone;
48
49struct CBC
50{
51 char *buf;
52 size_t pos;
53 size_t size;
54};
55
56static size_t
57putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
58{
59 unsigned int *pos = ptr;
60 unsigned int wrt;
61
62 wrt = size * nmemb;
63 if (wrt > 8 - (*pos))
64 wrt = 8 - (*pos);
65 memcpy (stream, &("Hello123"[*pos]), wrt);
66 (*pos) += wrt;
67 return wrt;
68}
69
70
71static size_t
72copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
73{
74 struct CBC *cbc = ctx;
75
76 if (cbc->pos + size * nmemb > cbc->size)
77 return 0; /* overflow */
78 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
79 cbc->pos += size * nmemb;
80 return size * nmemb;
81}
82
83
84static int
85ahc_echo (void *cls,
86 struct MHD_Connection *connection,
87 const char *url,
88 const char *method,
89 const char *version,
90 const char *upload_data, size_t *upload_data_size,
91 void **unused)
92{
93 int *done = cls;
94 struct MHD_Response *response;
95 int ret;
96 (void) version; (void) unused; /* Unused. Silent compiler warning. */
97
98 if (0 != strcasecmp ("PATCH", method))
99 return MHD_NO; /* unexpected method */
100 if ((*done) == 0)
101 {
102 if (*upload_data_size != 8)
103 return MHD_YES; /* not yet ready */
104 if (0 == memcmp (upload_data, "Hello123", 8))
105 {
106 *upload_data_size = 0;
107 }
108 else
109 {
110 printf ("Invalid upload data `%8s'!\n", upload_data);
111 return MHD_NO;
112 }
113 *done = 1;
114 return MHD_YES;
115 }
116 response = MHD_create_response_from_buffer (strlen (url), (void*) url,
117 MHD_RESPMEM_MUST_COPY);
118 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
119 MHD_destroy_response (response);
120 return ret;
121}
122
123
124static CURL *
125setup_curl (long port,
126 struct CBC *cbc,
127 unsigned int *pos)
128{
129 CURL *c;
130
131 c = curl_easy_init ();
132 curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST, "PATCH");
133 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
134 curl_easy_setopt (c, CURLOPT_PORT, (long) port);
135 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
136 curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc);
137 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
138 curl_easy_setopt (c, CURLOPT_READDATA, pos);
139 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
140 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
141 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
142 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
143 if (oneone)
144 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
145 else
146 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
147 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
148 /* NOTE: use of CONNECTTIMEOUT without also
149 * setting NOSIGNAL results in really weird
150 * crashes on my system! */
151 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
152
153 return c;
154}
155
156
157static int
158testInternalPut ()
159{
160 struct MHD_Daemon *d;
161 CURL *c;
162 char buf[2048];
163 struct CBC cbc;
164 unsigned int pos = 0;
165 int done_flag = 0;
166 CURLcode errornum;
167 int port;
168
169 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
170 port = 0;
171 else
172 {
173 port = 1450;
174 if (oneone)
175 port += 10;
176 }
177
178 cbc.buf = buf;
179 cbc.size = 2048;
180 cbc.pos = 0;
181 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
182 port,
183 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
184 if (d == NULL)
185 return 1;
186 if (0 == port)
187 {
188 const union MHD_DaemonInfo *dinfo;
189 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
190 if ((NULL == dinfo) || (0 == dinfo->port) )
191 {
192 MHD_stop_daemon (d); return 32;
193 }
194 port = (int) dinfo->port;
195 }
196 c = setup_curl (port, &cbc, &pos);
197 if (CURLE_OK != (errornum = curl_easy_perform (c)))
198 {
199 fprintf (stderr,
200 "curl_easy_perform failed: `%s'\n",
201 curl_easy_strerror (errornum));
202 curl_easy_cleanup (c);
203 MHD_stop_daemon (d);
204 return 2;
205 }
206 curl_easy_cleanup (c);
207 MHD_stop_daemon (d);
208 if (cbc.pos != strlen ("/hello_world"))
209 return 4;
210 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
211 return 8;
212 return 0;
213}
214
215
216static int
217testMultithreadedPut ()
218{
219 struct MHD_Daemon *d;
220 CURL *c;
221 char buf[2048];
222 struct CBC cbc;
223 unsigned int pos = 0;
224 int done_flag = 0;
225 CURLcode errornum;
226 int port;
227
228 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
229 port = 0;
230 else
231 {
232 port = 1451;
233 if (oneone)
234 port += 10;
235 }
236
237 cbc.buf = buf;
238 cbc.size = 2048;
239 cbc.pos = 0;
240 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
241 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
242 port,
243 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
244 if (d == NULL)
245 return 16;
246 if (0 == port)
247 {
248 const union MHD_DaemonInfo *dinfo;
249 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
250 if ((NULL == dinfo) || (0 == dinfo->port) )
251 {
252 MHD_stop_daemon (d); return 32;
253 }
254 port = (int) dinfo->port;
255 }
256 c = setup_curl (port, &cbc, &pos);
257 if (CURLE_OK != (errornum = curl_easy_perform (c)))
258 {
259 fprintf (stderr,
260 "curl_easy_perform failed: `%s'\n",
261 curl_easy_strerror (errornum));
262 curl_easy_cleanup (c);
263 MHD_stop_daemon (d);
264 return 32;
265 }
266 curl_easy_cleanup (c);
267 MHD_stop_daemon (d);
268 if (cbc.pos != strlen ("/hello_world"))
269 return 64;
270 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
271 return 128;
272
273 return 0;
274}
275
276
277static int
278testMultithreadedPoolPut ()
279{
280 struct MHD_Daemon *d;
281 CURL *c;
282 char buf[2048];
283 struct CBC cbc;
284 unsigned int pos = 0;
285 int done_flag = 0;
286 CURLcode errornum;
287 int port;
288
289 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
290 port = 0;
291 else
292 {
293 port = 1452;
294 if (oneone)
295 port += 10;
296 }
297
298 cbc.buf = buf;
299 cbc.size = 2048;
300 cbc.pos = 0;
301 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
302 port,
303 NULL, NULL, &ahc_echo, &done_flag,
304 MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
305 if (d == NULL)
306 return 16;
307 if (0 == port)
308 {
309 const union MHD_DaemonInfo *dinfo;
310 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
311 if ((NULL == dinfo) || (0 == dinfo->port) )
312 {
313 MHD_stop_daemon (d); return 32;
314 }
315 port = (int) dinfo->port;
316 }
317 c = setup_curl (port, &cbc, &pos);
318 if (CURLE_OK != (errornum = curl_easy_perform (c)))
319 {
320 fprintf (stderr,
321 "curl_easy_perform failed: `%s'\n",
322 curl_easy_strerror (errornum));
323 curl_easy_cleanup (c);
324 MHD_stop_daemon (d);
325 return 32;
326 }
327 curl_easy_cleanup (c);
328 MHD_stop_daemon (d);
329 if (cbc.pos != strlen ("/hello_world"))
330 return 64;
331 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
332 return 128;
333
334 return 0;
335}
336
337
338static int
339testExternalPut ()
340{
341 struct MHD_Daemon *d;
342 CURL *c;
343 char buf[2048];
344 struct CBC cbc;
345 CURLM *multi;
346 CURLMcode mret;
347 fd_set rs;
348 fd_set ws;
349 fd_set es;
350 MHD_socket maxsock;
351 int maxposixs; /* Max socket number unused on W32 */
352 int running;
353 struct CURLMsg *msg;
354 time_t start;
355 struct timeval tv;
356 unsigned int pos = 0;
357 int done_flag = 0;
358 int port;
359
360 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
361 port = 0;
362 else
363 {
364 port = 1453;
365 if (oneone)
366 port += 10;
367 }
368
369 multi = NULL;
370 cbc.buf = buf;
371 cbc.size = 2048;
372 cbc.pos = 0;
373 d = MHD_start_daemon (MHD_USE_ERROR_LOG,
374 port,
375 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
376 if (d == NULL)
377 return 256;
378 if (0 == port)
379 {
380 const union MHD_DaemonInfo *dinfo;
381 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
382 if ((NULL == dinfo) || (0 == dinfo->port) )
383 {
384 MHD_stop_daemon (d); return 32;
385 }
386 port = (int) dinfo->port;
387 }
388 c = setup_curl (port, &cbc, &pos);
389
390 multi = curl_multi_init ();
391 if (multi == NULL)
392 {
393 curl_easy_cleanup (c);
394 MHD_stop_daemon (d);
395 return 512;
396 }
397 mret = curl_multi_add_handle (multi, c);
398 if (mret != CURLM_OK)
399 {
400 curl_multi_cleanup (multi);
401 curl_easy_cleanup (c);
402 MHD_stop_daemon (d);
403 return 1024;
404 }
405 start = time (NULL);
406 while ((time (NULL) - start < 5) && (multi != NULL))
407 {
408 maxsock = MHD_INVALID_SOCKET;
409 maxposixs = -1;
410 FD_ZERO (&rs);
411 FD_ZERO (&ws);
412 FD_ZERO (&es);
413 curl_multi_perform (multi, &running);
414 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
415 if (mret != CURLM_OK)
416 {
417 curl_multi_remove_handle (multi, c);
418 curl_multi_cleanup (multi);
419 curl_easy_cleanup (c);
420 MHD_stop_daemon (d);
421 return 2048;
422 }
423 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
424 {
425 curl_multi_remove_handle (multi, c);
426 curl_multi_cleanup (multi);
427 curl_easy_cleanup (c);
428 MHD_stop_daemon (d);
429 return 4096;
430 }
431#ifdef MHD_POSIX_SOCKETS
432 if (maxsock > maxposixs)
433 maxposixs = maxsock;
434#endif /* MHD_POSIX_SOCKETS */
435 tv.tv_sec = 0;
436 tv.tv_usec = 1000;
437 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
438 {
439#ifdef MHD_POSIX_SOCKETS
440 if (EINTR != errno)
441 abort ();
442#else
443 if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 !=
444 ws.
445 fd_count)
446 || (0 != es.fd_count) )
447 _exit (99);
448 Sleep (1000);
449#endif
450 }
451 curl_multi_perform (multi, &running);
452 if (running == 0)
453 {
454 msg = curl_multi_info_read (multi, &running);
455 if (msg == NULL)
456 break;
457 if (msg->msg == CURLMSG_DONE)
458 {
459 if (msg->data.result != CURLE_OK)
460 printf ("%s failed at %s:%d: `%s'\n",
461 "curl_multi_perform",
462 __FILE__,
463 __LINE__, curl_easy_strerror (msg->data.result));
464 curl_multi_remove_handle (multi, c);
465 curl_multi_cleanup (multi);
466 curl_easy_cleanup (c);
467 c = NULL;
468 multi = NULL;
469 }
470 }
471 MHD_run (d);
472 }
473 if (multi != NULL)
474 {
475 curl_multi_remove_handle (multi, c);
476 curl_easy_cleanup (c);
477 curl_multi_cleanup (multi);
478 }
479 MHD_stop_daemon (d);
480 if (cbc.pos != strlen ("/hello_world"))
481 return 8192;
482 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
483 return 16384;
484 return 0;
485}
486
487
488int
489main (int argc, char *const *argv)
490{
491 unsigned int errorCount = 0;
492 (void) argc; /* Unused. Silent compiler warning. */
493
494 if ((NULL == argv) || (0 == argv[0]))
495 return 99;
496 oneone = has_in_name (argv[0], "11");
497 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
498 return 2;
499 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
500 {
501 errorCount += testInternalPut ();
502 errorCount += testMultithreadedPut ();
503 errorCount += testMultithreadedPoolPut ();
504 }
505 errorCount += testExternalPut ();
506 if (errorCount != 0)
507 fprintf (stderr, "Error (code: %u)\n", errorCount);
508 curl_global_cleanup ();
509 return errorCount != 0; /* 0 == pass */
510}