• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2      This file is part of libmicrohttpd
3      Copyright (C) 2007, 2008 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_put.c
23  * @brief  Testcase for libmicrohttpd PUT 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 
35 #ifndef WINDOWS
36 #include <unistd.h>
37 #endif
38 
39 
40 #include "socat.c"
41 
42 static int oneone;
43 
44 struct CBC
45 {
46   char *buf;
47   size_t pos;
48   size_t size;
49 };
50 
51 static size_t
putBuffer(void * stream,size_t size,size_t nmemb,void * ptr)52 putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
53 {
54   unsigned int *pos = ptr;
55   unsigned int wrt;
56 
57   wrt = size * nmemb;
58   if (wrt > 8 - (*pos))
59     wrt = 8 - (*pos);
60   memcpy (stream, &("Hello123"[*pos]), wrt);
61   (*pos) += wrt;
62   return wrt;
63 }
64 
65 static size_t
copyBuffer(void * ptr,size_t size,size_t nmemb,void * ctx)66 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
67 {
68   struct CBC *cbc = ctx;
69 
70   if (cbc->pos + size * nmemb > cbc->size)
71     return 0;                   /* overflow */
72   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
73   cbc->pos += size * nmemb;
74   return size * nmemb;
75 }
76 
77 static int
ahc_echo(void * cls,struct MHD_Connection * connection,const char * url,const char * method,const char * version,const char * upload_data,size_t * upload_data_size,void ** unused)78 ahc_echo (void *cls,
79           struct MHD_Connection *connection,
80           const char *url,
81           const char *method,
82           const char *version,
83           const char *upload_data, size_t *upload_data_size,
84           void **unused)
85 {
86   int *done = cls;
87   struct MHD_Response *response;
88   int ret;
89 
90   if (0 != strcmp ("PUT", method))
91     return MHD_NO;              /* unexpected method */
92   if ((*done) == 0)
93     {
94       if (*upload_data_size != 8)
95         return MHD_YES;         /* not yet ready */
96       if (0 == memcmp (upload_data, "Hello123", 8))
97         {
98           *upload_data_size = 0;
99         }
100       else
101         {
102           printf ("Invalid upload data `%8s'!\n", upload_data);
103           return MHD_NO;
104         }
105       *done = 1;
106       return MHD_YES;
107     }
108   response = MHD_create_response_from_buffer (strlen (url),
109 					      (void *) url,
110 					      MHD_RESPMEM_MUST_COPY);
111   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
112   MHD_destroy_response (response);
113   return ret;
114 }
115 
116 
117 static int
testInternalPut()118 testInternalPut ()
119 {
120   struct MHD_Daemon *d;
121   CURL *c;
122   char buf[2048];
123   struct CBC cbc;
124   unsigned int pos = 0;
125   int done_flag = 0;
126   int i;
127 
128   cbc.buf = buf;
129   cbc.size = 2048;
130   cbc.pos = 0;
131   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
132                         11080,
133                         NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
134   if (d == NULL)
135     return 1;
136   zzuf_socat_start ();
137   for (i = 0; i < LOOP_COUNT; i++)
138     {
139       fprintf (stderr, ".");
140       c = curl_easy_init ();
141       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
142       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
143       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
144       curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
145       curl_easy_setopt (c, CURLOPT_READDATA, &pos);
146       curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
147       curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
148       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
149       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
150       if (oneone)
151         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
152       else
153         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
154       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
155       // NOTE: use of CONNECTTIMEOUT without also
156       //   setting NOSIGNAL results in really weird
157       //   crashes on my system!
158       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
159       curl_easy_perform (c);
160       curl_easy_cleanup (c);
161     }
162   fprintf (stderr, "\n");
163   zzuf_socat_stop ();
164   MHD_stop_daemon (d);
165   return 0;
166 }
167 
168 static int
testMultithreadedPut()169 testMultithreadedPut ()
170 {
171   struct MHD_Daemon *d;
172   CURL *c;
173   char buf[2048];
174   struct CBC cbc;
175   unsigned int pos = 0;
176   int done_flag = 0;
177   int i;
178 
179   cbc.buf = buf;
180   cbc.size = 2048;
181   cbc.pos = 0;
182   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */ ,
183                         11080,
184                         NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
185   if (d == NULL)
186     return 16;
187   zzuf_socat_start ();
188   for (i = 0; i < LOOP_COUNT; i++)
189     {
190       fprintf (stderr, ".");
191       c = curl_easy_init ();
192       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
193       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
194       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
195       curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
196       curl_easy_setopt (c, CURLOPT_READDATA, &pos);
197       curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
198       curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
199       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
200       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
201       if (oneone)
202         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
203       else
204         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
205       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
206       // NOTE: use of CONNECTTIMEOUT without also
207       //   setting NOSIGNAL results in really weird
208       //   crashes on my system!
209       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
210       curl_easy_perform (c);
211       curl_easy_cleanup (c);
212     }
213   fprintf (stderr, "\n");
214   zzuf_socat_stop ();
215   MHD_stop_daemon (d);
216   return 0;
217 }
218 
219 
220 static int
testExternalPut()221 testExternalPut ()
222 {
223   struct MHD_Daemon *d;
224   CURL *c;
225   char buf[2048];
226   struct CBC cbc;
227   CURLM *multi;
228   CURLMcode mret;
229   fd_set rs;
230   fd_set ws;
231   fd_set es;
232   int max;
233   int running;
234   time_t start;
235   struct timeval tv;
236   unsigned int pos = 0;
237   int done_flag = 0;
238   int i;
239 
240   multi = NULL;
241   cbc.buf = buf;
242   cbc.size = 2048;
243   cbc.pos = 0;
244   d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG */ ,
245                         11080,
246                         NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
247   if (d == NULL)
248     return 256;
249   multi = curl_multi_init ();
250   if (multi == NULL)
251     {
252       MHD_stop_daemon (d);
253       return 512;
254     }
255   zzuf_socat_start ();
256   for (i = 0; i < LOOP_COUNT; i++)
257     {
258       fprintf (stderr, ".");
259 
260       c = curl_easy_init ();
261       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
262       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
263       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
264       curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
265       curl_easy_setopt (c, CURLOPT_READDATA, &pos);
266       curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
267       curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
268       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
269       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
270       if (oneone)
271         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
272       else
273         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
274       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
275       // NOTE: use of CONNECTTIMEOUT without also
276       //   setting NOSIGNAL results in really weird
277       //   crashes on my system!
278       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
279 
280 
281 
282       mret = curl_multi_add_handle (multi, c);
283       if (mret != CURLM_OK)
284         {
285           curl_multi_cleanup (multi);
286           curl_easy_cleanup (c);
287           zzuf_socat_stop ();
288           MHD_stop_daemon (d);
289           return 1024;
290         }
291       start = time (NULL);
292       while ((time (NULL) - start < 5) && (c != NULL))
293         {
294           max = 0;
295           FD_ZERO (&rs);
296           FD_ZERO (&ws);
297           FD_ZERO (&es);
298           curl_multi_perform (multi, &running);
299           mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
300           if (mret != CURLM_OK)
301             {
302               curl_multi_remove_handle (multi, c);
303               curl_multi_cleanup (multi);
304               curl_easy_cleanup (c);
305               zzuf_socat_stop ();
306               MHD_stop_daemon (d);
307               return 2048;
308             }
309           if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
310             {
311               curl_multi_remove_handle (multi, c);
312               curl_multi_cleanup (multi);
313               curl_easy_cleanup (c);
314               zzuf_socat_stop ();
315               MHD_stop_daemon (d);
316               return 4096;
317             }
318           tv.tv_sec = 0;
319           tv.tv_usec = 1000;
320           select (max + 1, &rs, &ws, &es, &tv);
321           curl_multi_perform (multi, &running);
322           if (running == 0)
323             {
324               curl_multi_info_read (multi, &running);
325               curl_multi_remove_handle (multi, c);
326               curl_easy_cleanup (c);
327               c = NULL;
328             }
329           MHD_run (d);
330         }
331       if (c != NULL)
332         {
333           curl_multi_remove_handle (multi, c);
334           curl_easy_cleanup (c);
335         }
336     }
337   fprintf (stderr, "\n");
338   curl_multi_cleanup (multi);
339   zzuf_socat_stop ();
340   MHD_stop_daemon (d);
341   return 0;
342 }
343 
344 
345 int
main(int argc,char * const * argv)346 main (int argc, char *const *argv)
347 {
348   unsigned int errorCount = 0;
349 
350   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
351     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
352   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
353     return 2;
354   errorCount += testInternalPut ();
355   errorCount += testMultithreadedPut ();
356   errorCount += testExternalPut ();
357   if (errorCount != 0)
358     fprintf (stderr, "Error (code: %u)\n", errorCount);
359   curl_global_cleanup ();
360   return errorCount != 0;       /* 0 == pass */
361 }
362