• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3      This file is part of libmicrohttpd
4      Copyright (C) 2007 Christian Grothoff
5 
6      libmicrohttpd is free software; you can redistribute it and/or modify
7      it under the terms of the GNU General Public License as published
8      by the Free Software Foundation; either version 3, or (at your
9      option) any later version.
10 
11      libmicrohttpd is distributed in the hope that it will be useful, but
12      WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14      General Public License for more details.
15 
16      You should have received a copy of the GNU General Public License
17      along with libmicrohttpd; see the file COPYING.  If not, write to the
18      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19      Boston, MA 02111-1307, USA.
20 */
21 
22 /**
23  * @file test_parse_cookies.c
24  * @brief  Testcase for HTTP cookie parsing
25  * @author Christian Grothoff
26  */
27 
28 #include "MHD_config.h"
29 #include "platform.h"
30 #include <curl/curl.h>
31 #include <microhttpd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 
36 #ifndef WINDOWS
37 #include <unistd.h>
38 #endif
39 
40 static int oneone;
41 
42 struct CBC
43 {
44   char *buf;
45   size_t pos;
46   size_t size;
47 };
48 
49 static size_t
copyBuffer(void * ptr,size_t size,size_t nmemb,void * ctx)50 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
51 {
52   struct CBC *cbc = ctx;
53 
54   if (cbc->pos + size * nmemb > cbc->size)
55     return 0;                   /* overflow */
56   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
57   cbc->pos += size * nmemb;
58   return size * nmemb;
59 }
60 
61 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)62 ahc_echo (void *cls,
63           struct MHD_Connection *connection,
64           const char *url,
65           const char *method,
66           const char *version,
67           const char *upload_data, size_t *upload_data_size,
68           void **unused)
69 {
70   static int ptr;
71   const char *me = cls;
72   struct MHD_Response *response;
73   int ret;
74   const char *hdr;
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   ret = 0;
85 
86   hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name1");
87   if ((hdr == NULL) || (0 != strcmp (hdr, "var1")))
88     abort ();
89   hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name2");
90   if ((hdr == NULL) || (0 != strcmp (hdr, "var2")))
91     abort ();
92   hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name3");
93   if ((hdr == NULL) || (0 != strcmp (hdr, "")))
94     abort ();
95   hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name4");
96   if ((hdr == NULL) || (0 != strcmp (hdr, "var4 with spaces")))
97     abort ();
98   response = MHD_create_response_from_buffer (strlen (url),
99 					      (void *) url,
100 					      MHD_RESPMEM_PERSISTENT);
101   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
102   MHD_destroy_response (response);
103   if (ret == MHD_NO)
104     abort ();
105   return ret;
106 }
107 
108 static int
testExternalGet()109 testExternalGet ()
110 {
111   struct MHD_Daemon *d;
112   CURL *c;
113   char buf[2048];
114   struct CBC cbc;
115   CURLM *multi;
116   CURLMcode mret;
117   fd_set rs;
118   fd_set ws;
119   fd_set es;
120   MHD_socket max;
121   int running;
122   struct CURLMsg *msg;
123   time_t start;
124   struct timeval tv;
125 
126   multi = NULL;
127   cbc.buf = buf;
128   cbc.size = 2048;
129   cbc.pos = 0;
130   d = MHD_start_daemon (MHD_USE_DEBUG,
131                         21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
132   if (d == NULL)
133     return 256;
134   c = curl_easy_init ();
135   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:21080/hello_world");
136   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
137   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
138   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
139   /* note that the string below intentionally uses the
140      various ways cookies can be specified to exercise the
141      parser! Do not change! */
142   curl_easy_setopt (c, CURLOPT_COOKIE,
143                     "name1=var1; name2=var2,name3 ;name4=\"var4 with spaces\";");
144   if (oneone)
145     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
146   else
147     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
148   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
149   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
150   /* NOTE: use of CONNECTTIMEOUT without also
151      setting NOSIGNAL results in really weird
152      crashes on my system! */
153   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
154 
155 
156   multi = curl_multi_init ();
157   if (multi == NULL)
158     {
159       curl_easy_cleanup (c);
160       MHD_stop_daemon (d);
161       return 512;
162     }
163   mret = curl_multi_add_handle (multi, c);
164   if (mret != CURLM_OK)
165     {
166       curl_multi_cleanup (multi);
167       curl_easy_cleanup (c);
168       MHD_stop_daemon (d);
169       return 1024;
170     }
171   start = time (NULL);
172   while ((time (NULL) - start < 5) && (multi != NULL))
173     {
174       max = 0;
175       FD_ZERO (&rs);
176       FD_ZERO (&ws);
177       FD_ZERO (&es);
178       curl_multi_perform (multi, &running);
179       mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
180       if (mret != CURLM_OK)
181         {
182           curl_multi_remove_handle (multi, c);
183           curl_multi_cleanup (multi);
184           curl_easy_cleanup (c);
185           MHD_stop_daemon (d);
186           return 2048;
187         }
188       if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
189         {
190           curl_multi_remove_handle (multi, c);
191           curl_multi_cleanup (multi);
192           curl_easy_cleanup (c);
193           MHD_stop_daemon (d);
194           return 4096;
195         }
196       tv.tv_sec = 0;
197       tv.tv_usec = 1000;
198       select (max + 1, &rs, &ws, &es, &tv);
199       curl_multi_perform (multi, &running);
200       if (running == 0)
201         {
202           msg = curl_multi_info_read (multi, &running);
203           if (msg == NULL)
204             break;
205           if (msg->msg == CURLMSG_DONE)
206             {
207               if (msg->data.result != CURLE_OK)
208                 printf ("%s failed at %s:%d: `%s'\n",
209                         "curl_multi_perform",
210                         __FILE__,
211                         __LINE__, curl_easy_strerror (msg->data.result));
212               curl_multi_remove_handle (multi, c);
213               curl_multi_cleanup (multi);
214               curl_easy_cleanup (c);
215               c = NULL;
216               multi = NULL;
217             }
218         }
219       MHD_run (d);
220     }
221   if (multi != NULL)
222     {
223       curl_multi_remove_handle (multi, c);
224       curl_easy_cleanup (c);
225       curl_multi_cleanup (multi);
226     }
227   MHD_stop_daemon (d);
228   if (cbc.pos != strlen ("/hello_world"))
229     return 8192;
230   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
231     return 16384;
232   return 0;
233 }
234 
235 
236 int
main(int argc,char * const * argv)237 main (int argc, char *const *argv)
238 {
239   unsigned int errorCount = 0;
240 
241   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
242     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
243   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
244     return 2;
245   errorCount += testExternalGet ();
246   if (errorCount != 0)
247     fprintf (stderr, "Error (code: %u)\n", errorCount);
248   curl_global_cleanup ();
249   return errorCount != 0;       /* 0 == pass */
250 }
251