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, ©Buffer);
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, ©Buffer);
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