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