• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2      This file is part of libmicrohttpd
3      Copyright (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 test_long_header.c
23  * @brief  Testcase for libmicrohttpd handling of very long headers
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  * We will set the memory available per connection to
41  * half of this value, so the actual value does not have
42  * to be big at all...
43  */
44 #define VERY_LONG (1024*10)
45 
46 static int oneone;
47 
48 static int
apc_all(void * cls,const struct sockaddr * addr,socklen_t addrlen)49 apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
50 {
51   return MHD_YES;
52 }
53 
54 struct CBC
55 {
56   char *buf;
57   size_t pos;
58   size_t size;
59 };
60 
61 static size_t
copyBuffer(void * ptr,size_t size,size_t nmemb,void * ctx)62 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
63 {
64   return size * nmemb;
65 }
66 
67 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)68 ahc_echo (void *cls,
69           struct MHD_Connection *connection,
70           const char *url,
71           const char *method,
72           const char *version,
73           const char *upload_data, size_t *upload_data_size,
74           void **unused)
75 {
76   const char *me = cls;
77   struct MHD_Response *response;
78   int ret;
79 
80   if (0 != strcmp (me, method))
81     return MHD_NO;              /* unexpected method */
82   response = MHD_create_response_from_buffer (strlen (url),
83 					      (void *) url,
84 					      MHD_RESPMEM_MUST_COPY);
85   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
86   MHD_destroy_response (response);
87   return ret;
88 }
89 
90 
91 static int
testLongUrlGet()92 testLongUrlGet ()
93 {
94   struct MHD_Daemon *d;
95   CURL *c;
96   char buf[2048];
97   struct CBC cbc;
98   char *url;
99   long code;
100 
101   cbc.buf = buf;
102   cbc.size = 2048;
103   cbc.pos = 0;
104   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
105                         1080,
106                         &apc_all,
107                         NULL,
108                         &ahc_echo,
109                         "GET",
110                         MHD_OPTION_CONNECTION_MEMORY_LIMIT,
111                         (size_t) (VERY_LONG / 2), MHD_OPTION_END);
112   if (d == NULL)
113     return 1;
114   c = curl_easy_init ();
115   url = malloc (VERY_LONG);
116   if (url == NULL)
117     {
118 	MHD_stop_daemon (d);
119  	return 1;
120     }
121   memset (url, 'a', VERY_LONG);
122   url[VERY_LONG - 1] = '\0';
123   memcpy (url, "http://127.0.0.1:1080/", strlen ("http://127.0.0.1:1080/"));
124   curl_easy_setopt (c, CURLOPT_URL, url);
125   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
126   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
127   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
128   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
129   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
130   if (oneone)
131     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
132   else
133     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
134   /* NOTE: use of CONNECTTIMEOUT without also
135      setting NOSIGNAL results in really weird
136      crashes on my system! */
137   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
138   if (CURLE_OK == curl_easy_perform (c))
139     {
140       curl_easy_cleanup (c);
141       MHD_stop_daemon (d);
142       free (url);
143       return 2;
144     }
145   if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
146     {
147       curl_easy_cleanup (c);
148       MHD_stop_daemon (d);
149       free (url);
150       return 4;
151     }
152   curl_easy_cleanup (c);
153   MHD_stop_daemon (d);
154   free (url);
155   if (code != MHD_HTTP_REQUEST_URI_TOO_LONG)
156     return 8;
157   return 0;
158 }
159 
160 
161 static int
testLongHeaderGet()162 testLongHeaderGet ()
163 {
164   struct MHD_Daemon *d;
165   CURL *c;
166   char buf[2048];
167   struct CBC cbc;
168   char *url;
169   long code;
170   struct curl_slist *header = NULL;
171 
172   cbc.buf = buf;
173   cbc.size = 2048;
174   cbc.pos = 0;
175   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
176                         1080,
177                         &apc_all,
178                         NULL,
179                         &ahc_echo,
180                         "GET",
181                         MHD_OPTION_CONNECTION_MEMORY_LIMIT,
182                         (size_t) (VERY_LONG / 2), MHD_OPTION_END);
183   if (d == NULL)
184     return 16;
185   c = curl_easy_init ();
186   url = malloc (VERY_LONG);
187   if (url == NULL)
188      {
189 	MHD_stop_daemon (d);
190 	return 16;
191      }
192   memset (url, 'a', VERY_LONG);
193   url[VERY_LONG - 1] = '\0';
194   url[VERY_LONG / 2] = ':';
195   url[VERY_LONG / 2 + 1] = ' ';
196   header = curl_slist_append (header, url);
197 
198   curl_easy_setopt (c, CURLOPT_HTTPHEADER, header);
199   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
200   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
201   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
202   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
203   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
204   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
205   if (oneone)
206     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
207   else
208     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
209   /* NOTE: use of CONNECTTIMEOUT without also
210      setting NOSIGNAL results in really weird
211      crashes on my system! */
212   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
213   if (CURLE_OK == curl_easy_perform (c))
214     {
215       curl_easy_cleanup (c);
216       MHD_stop_daemon (d);
217       curl_slist_free_all (header);
218       free (url);
219       return 32;
220     }
221   if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
222     {
223       curl_slist_free_all (header);
224       curl_easy_cleanup (c);
225       MHD_stop_daemon (d);
226       free (url);
227       return 64;
228     }
229   curl_slist_free_all (header);
230   curl_easy_cleanup (c);
231   MHD_stop_daemon (d);
232   free (url);
233   if (code != MHD_HTTP_REQUEST_ENTITY_TOO_LARGE)
234     return 128;
235   return 0;
236 }
237 
238 int
main(int argc,char * const * argv)239 main (int argc, char *const *argv)
240 {
241   unsigned int errorCount = 0;
242 
243   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
244     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
245   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
246     return 2;
247   errorCount += testLongUrlGet ();
248   errorCount += testLongHeaderGet ();
249   if (errorCount != 0)
250     fprintf (stderr, "Error (code: %u)\n", errorCount);
251   curl_global_cleanup ();
252   return errorCount != 0;       /* 0 == pass */
253 }
254